use new gtest macros
started to refactor the persistence layer network fixes removed noise dependenciesmaster
parent
b61b7c58e0
commit
c235784e26
|
@ -23,7 +23,9 @@ include_directories(src/modules)
|
|||
include_directories(src/modules/ui)
|
||||
|
||||
fips_setup(PROJECT engine)
|
||||
gtest_suite_begin(tests TEMPLATE src/modules/core/tests/main.cpp.in)
|
||||
fips_add_subdirectory(src)
|
||||
gtest_suite_end(tests)
|
||||
fips_finish()
|
||||
|
||||
copy_data_files(shared)
|
27
Makefile
27
Makefile
|
@ -12,17 +12,32 @@ clean:
|
|||
$(Q)rm -f .fips-gen.py
|
||||
$(Q)rm -f .fips-imports.cmake
|
||||
|
||||
run: build
|
||||
$(Q)./fips run $(TARGET)
|
||||
|
||||
eclipse:
|
||||
$(Q)./fips config linux-eclipse-debug
|
||||
|
||||
server: build
|
||||
$(Q)./fips run server -- -set core_loglevel 4
|
||||
$(Q)./fips run server
|
||||
|
||||
client: build
|
||||
$(Q)./fips run client -- -set core_loglevel 2
|
||||
$(Q)./fips run client
|
||||
|
||||
debugserver: build
|
||||
$(Q)./fips gdb server
|
||||
|
||||
debugclient: build
|
||||
$(Q)./fips gdb client
|
||||
|
||||
debuggenerate: build
|
||||
$(Q)./fips gdb worldgenerator -- -set seed 1 -set size 1024
|
||||
|
||||
generate: build
|
||||
$(Q)./fips run worldgenerator -- -set seed 1 -set size 64
|
||||
$(Q)./fips run worldgenerator -- -set seed 1 -set size 1024
|
||||
|
||||
tests: build
|
||||
$(Q)./fips run tests
|
||||
|
||||
tests-list: build
|
||||
$(Q)./fips run tests -- --gtest_list_tests
|
||||
|
||||
tests-filter: build
|
||||
$(Q)./fips run tests -- --gtest_filter=$(FILTER)
|
||||
|
|
|
@ -1,18 +1,2 @@
|
|||
if (DEFINED ENV{SDL2DIR})
|
||||
set(SDL2_INCLUDE_DIRS ENV{SDL2DIR}/include)
|
||||
if (FIPS_WINDOWS)
|
||||
set(SDL2_LIBRARIES ENV{SDL2DIR}/libs/SDL_main.lib ENV{SDL2DIR}/libs/SDL.lib)
|
||||
endif()
|
||||
else()
|
||||
if (FIPS_WINDOWS)
|
||||
find_package(SDL REQUIRED)
|
||||
set(SDL2_INCLUDE_DIRS ${SDL_INCLUDE_DIRS})
|
||||
set(SDL2_LIBRARIES ${SDL_LIBRARIES})
|
||||
else()
|
||||
#include(FindPkgConfig)
|
||||
find_package(PkgConfig)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_search_module(SDL2 REQUIRED sdl2)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
include("${PROJECT_SOURCE_DIR}/cmake/macros.cmake")
|
||||
engine_find(SDL2 SDL.h SDL2 >=2.0.3)
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# macro for the FindLibName.cmake files.
|
||||
#
|
||||
# parameters:
|
||||
# LIB: the library we are trying to find
|
||||
# HEADER: the header we are trying to find
|
||||
# SUFFIX: suffix for the include dir
|
||||
# VERSION: the operator and version that is given to the pkg-config call (e.g. ">=1.0")
|
||||
#
|
||||
# Example: engine_find(SDL2_image SDL_image.h SDL2)
|
||||
#
|
||||
macro(engine_find LIB HEADER SUFFIX VERSION)
|
||||
string(TOUPPER ${LIB} PREFIX)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_PROCESSOR_ARCH "x64")
|
||||
else()
|
||||
set(_PROCESSOR_ARCH "x86")
|
||||
endif()
|
||||
set(_SEARCH_PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt
|
||||
)
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(_${PREFIX} QUIET ${LIB}${VERSION})
|
||||
endif()
|
||||
find_path(${PREFIX}_INCLUDE_DIRS
|
||||
NAMES ${HEADER}
|
||||
HINTS ENV ${PREFIX}DIR
|
||||
PATH_SUFFIXES include include/${SUFFIX} ${SUFFIX}
|
||||
PATHS
|
||||
${_${PREFIX}_INCLUDE_DIRS}
|
||||
${_SEARCH_PATHS}
|
||||
)
|
||||
find_library(${PREFIX}_LIBRARIES
|
||||
NAMES ${LIB}
|
||||
HINTS ENV ${PREFIX}DIR
|
||||
PATH_SUFFIXES lib64 lib lib/${_PROCESSOR_ARCH}
|
||||
PATHS
|
||||
${_${PREFIX}_LIBRARY_DIRS}
|
||||
${_SEARCH_PATHS}
|
||||
)
|
||||
unset(_SEARCH_PATHS)
|
||||
unset(_PROCESSOR_ARCH)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(${PREFIX} REQUIRED_VARS ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARIES)
|
||||
mark_as_advanced(${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARIES)
|
||||
endmacro()
|
|
@ -61,7 +61,7 @@ vec3 getSpecularColor(vec3 lightdir, vec3 normal) {
|
|||
}
|
||||
|
||||
vec3 getFogColor() {
|
||||
return vec3(0.04, 0.29, 0.94);
|
||||
return vec3(0.0, 0.6, 0.796);
|
||||
}
|
||||
|
||||
float getFog() {
|
||||
|
|
4
fips.yml
4
fips.yml
|
@ -1,8 +1,6 @@
|
|||
imports:
|
||||
fips-glm:
|
||||
git: https://github.com/floooh/fips-glm.git
|
||||
fips-accidentalnoise:
|
||||
git: https://github.com/mgerhardy/fips-accidentalnoise.git
|
||||
fips-enet:
|
||||
git: https://github.com/mgerhardy/fips-enet.git
|
||||
fips-polyvox:
|
||||
|
@ -26,8 +24,6 @@ imports:
|
|||
git: https://github.com/mgerhardy/fips-lua.git
|
||||
fips-zlib:
|
||||
git: https://github.com/floooh/fips-zlib.git
|
||||
fips-noisepp:
|
||||
git: https://github.com/mgerhardy/fips-noisepp.git
|
||||
|
||||
exports:
|
||||
header-dirs:
|
||||
|
|
|
@ -2,4 +2,3 @@ fips_add_subdirectory(modules)
|
|||
fips_add_subdirectory(client)
|
||||
fips_add_subdirectory(server)
|
||||
fips_add_subdirectory(rcon)
|
||||
fips_add_subdirectory(worldgenerator)
|
||||
|
|
|
@ -63,7 +63,7 @@ void Client::onEvent(const network::NewConnectionEvent& event) {
|
|||
flatbuffers::FlatBufferBuilder fbb;
|
||||
const std::string& email = core::Var::get("cl_email")->strVal();
|
||||
const std::string& password = core::Var::get("cl_password")->strVal();
|
||||
Log::info("Trying to log into the server");
|
||||
Log::info("Trying to log into the server with %s", email.c_str());
|
||||
_messageSender->sendClientMessage(_peer, fbb, Type_UserConnect,
|
||||
CreateUserConnect(fbb, fbb.CreateString(email), fbb.CreateString(password)).Union());
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ core::AppState Client::onInit() {
|
|||
registerMoveCmd("+move_forward", MOVEFORWARD);
|
||||
registerMoveCmd("+move_backward", MOVEBACKWARD);
|
||||
|
||||
_clearColor = glm::vec3(0.04, 0.29, 0.94);
|
||||
_clearColor = glm::vec3(0.0, 0.6, 0.796);
|
||||
|
||||
_root.SetSkinBg(TBIDC("background"));
|
||||
new frontend::LoginWindow(this);
|
||||
|
@ -424,7 +424,6 @@ void Client::spawn(frontend::ClientEntityId id, const char *name, const glm::vec
|
|||
_userId = id;
|
||||
_posLerp.setPosition(_now, pos);
|
||||
}
|
||||
;
|
||||
|
||||
bool Client::connect(uint16_t port, const std::string& hostname) {
|
||||
ENetPeer* peer = _network->connect(port, hostname);
|
||||
|
@ -436,7 +435,7 @@ bool Client::connect(uint16_t port, const std::string& hostname) {
|
|||
peer->data = this;
|
||||
|
||||
_peer = peer;
|
||||
Log::error("Connected to server %s:%i", hostname.c_str(), port);
|
||||
Log::info("Connected to server %s:%i", hostname.c_str(), port);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,5 @@
|
|||
void SeedHandler::execute(ENetPeer* peer, const void* raw) {
|
||||
const network::messages::server::Seed* message = static_cast<const network::messages::server::Seed*>(raw);
|
||||
const long seed = message->seed();
|
||||
Log::info("Seed is: %li", seed);
|
||||
_world->load(seed);
|
||||
_world->setSeed(seed);
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@ fips_add_subdirectory(cooldown)
|
|||
fips_add_subdirectory(backend)
|
||||
fips_add_subdirectory(frontend)
|
||||
fips_add_subdirectory(commonlua)
|
||||
fips_add_subdirectory(dbpost)
|
||||
fips_add_subdirectory(persistence)
|
||||
|
|
|
@ -8,10 +8,5 @@ fips_begin_module(attrib)
|
|||
fips_deps(core commonlua)
|
||||
fips_end_module()
|
||||
|
||||
gtest_begin(attrib)
|
||||
fips_dir(tests)
|
||||
fips_files(
|
||||
AttributesTest.cpp
|
||||
)
|
||||
fips_deps(attrib)
|
||||
gtest_end()
|
||||
gtest_suite_files(tests tests/AttributesTest.cpp)
|
||||
gtest_suite_deps(tests attrib)
|
||||
|
|
|
@ -56,7 +56,7 @@ fips_begin_module(backend)
|
|||
fips_dir(storage)
|
||||
fips_files(
|
||||
UserStore.cpp UserStore.h
|
||||
PQHandle.cpp PQHandle.h
|
||||
Persister.cpp Persister.h
|
||||
StoreCmd.cpp StoreCmd.h
|
||||
)
|
||||
|
||||
|
@ -75,15 +75,8 @@ fips_begin_module(backend)
|
|||
)
|
||||
find_package(SDL2 REQUIRED)
|
||||
include_directories(${SDL2_INCLUDE_DIRS} .)
|
||||
fips_deps(network io core util voxel attrib cooldown dbpost simpleai ${SDL2_LIBRARIES})
|
||||
fips_deps(network io core util voxel attrib cooldown persistence simpleai ${SDL2_LIBRARIES})
|
||||
fips_end_module()
|
||||
|
||||
gtest_begin(backend)
|
||||
fips_dir(tests)
|
||||
fips_files(
|
||||
SpawnMgrTest.cpp
|
||||
PoiProviderTest.cpp
|
||||
StorageTest.cpp
|
||||
)
|
||||
fips_deps(network io core util voxel attrib cooldown dbpost simpleai backend)
|
||||
gtest_end()
|
||||
gtest_suite_files(tests tests/SpawnMgrTest.cpp tests/PoiProviderTest.cpp tests/PersisterTest.cpp)
|
||||
gtest_suite_deps(tests network io core util voxel attrib cooldown persistence simpleai backend)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "EntityStorage.h"
|
||||
#include "core/Var.h"
|
||||
#include "User.h"
|
||||
#include "backend/storage/PQHandle.h"
|
||||
#include "backend/storage/Persister.h"
|
||||
#include "backend/storage/UserStore.h"
|
||||
|
||||
#define broadcastMsg(msg, type) _messageSender->broadcastServerMessage(fbb, network::messages::server::type, network::messages::server::msg.Union());
|
||||
|
@ -30,12 +30,12 @@ void EntityStorage::registerUser(const UserPtr& user) {
|
|||
|
||||
EntityId EntityStorage::getUserId(const std::string& user, const std::string& passwd) const {
|
||||
std::string tmUid = "0";
|
||||
PQHandle pq;
|
||||
Persister pq;
|
||||
pq.init();
|
||||
int checkId = pq.loadUser(user, passwd, tmUid);
|
||||
|
||||
if (checkId == 0) {
|
||||
const core::VarPtr& autoReg = core::Var::get("user_auto_register", "no");
|
||||
const core::VarPtr& autoReg = core::Var::get("user_auto_register", "yes");
|
||||
if (autoReg->strVal() == "yes") {
|
||||
pq.storeUser(user, passwd, tmUid);
|
||||
checkId = pq.loadUser(user, passwd, tmUid);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "network/MessageSender.h"
|
||||
#include "Npc.h"
|
||||
#include "core/Var.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
|
|
|
@ -22,16 +22,9 @@ bool ServerLoop::onInit() {
|
|||
if (!_spawnMgr->init())
|
||||
return false;
|
||||
const core::VarPtr& seed = core::Var::get("sv_seed", "1");
|
||||
const core::VarPtr& size = core::Var::get("sv_size", "128");
|
||||
|
||||
class ProgressMonitor: public util::IProgressMonitor {
|
||||
public:
|
||||
void done() override {
|
||||
Log::info("\ndone");
|
||||
}
|
||||
} monitor;
|
||||
|
||||
if (!_world->load(seed->longVal(), &monitor))
|
||||
return false;
|
||||
_world->setSeed(seed->longVal());
|
||||
if (_aiServer.start()) {
|
||||
Log::info("Start the ai debug server on 127.0.0.1:11338");
|
||||
_aiServer.addZone(&_zone);
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace backend {
|
|||
|
||||
class ServerNetworkModule: public NetworkModule {
|
||||
void configureHandlers() const override {
|
||||
configureHandler(Type_UserConnect, UserConnectHandler(network::Network &, backend::EntityStorage &));
|
||||
configureHandler(Type_UserConnect, UserConnectHandler(network::Network &, backend::EntityStorage &, voxel::World &));
|
||||
configureHandler(Type_UserDisconnect, UserDisconnectHandler());
|
||||
configureHandler(Type_Attack, AttackHandler());
|
||||
configureHandler(Type_Move, MoveHandler());
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
namespace backend {
|
||||
|
||||
UserConnectHandler::UserConnectHandler(network::NetworkPtr network, backend::EntityStoragePtr entityStorage) :
|
||||
_network(network), _entityStorage(entityStorage) {
|
||||
UserConnectHandler::UserConnectHandler(network::NetworkPtr network, backend::EntityStoragePtr entityStorage, voxel::WorldPtr world) :
|
||||
_network(network), _entityStorage(entityStorage), _world(world) {
|
||||
auto data = CreateAuthFailed(_authFailed);
|
||||
auto msg = CreateServerMessage(_authFailed, Type_AuthFailed, data.Union());
|
||||
FinishServerMessageBuffer(_authFailed, msg);
|
||||
|
@ -31,9 +31,7 @@ void UserConnectHandler::execute(ENetPeer* peer, const void* raw) {
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: use the current seed from the world, not from a config var that can be changed during runtime
|
||||
const long seed = core::Var::get("sv_seed")->longVal();
|
||||
user->sendSeed(seed);
|
||||
user->sendSeed(_world->seed());
|
||||
user->sendUserSpawn();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "network/Network.h"
|
||||
#include "voxel/World.h"
|
||||
#include "backend/entity/EntityStorage.h"
|
||||
|
||||
#include <flatbuffers/flatbuffers.h>
|
||||
|
@ -11,12 +12,13 @@ class UserConnectHandler: public network::IProtocolHandler {
|
|||
private:
|
||||
network::NetworkPtr _network;
|
||||
backend::EntityStoragePtr _entityStorage;
|
||||
voxel::WorldPtr _world;
|
||||
flatbuffers::FlatBufferBuilder _authFailed;
|
||||
|
||||
void sendAuthFailed(ENetPeer* peer);
|
||||
|
||||
public:
|
||||
UserConnectHandler(network::NetworkPtr network, backend::EntityStoragePtr entityStorage);
|
||||
UserConnectHandler(network::NetworkPtr network, backend::EntityStoragePtr entityStorage, voxel::WorldPtr world);
|
||||
|
||||
void execute(ENetPeer* peer, const void* message) override;
|
||||
};
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
namespace backend {
|
||||
|
||||
static const long spawnTime = 15000L;
|
||||
|
||||
SpawnMgr::SpawnMgr(voxel::WorldPtr world, EntityStoragePtr entityStorage, network::MessageSenderPtr messageSender, core::TimeProviderPtr timeProvider, AILoaderPtr loader, attrib::ContainerProviderPtr containerProvider, PoiProviderPtr poiProvider) :
|
||||
_loader(loader), _world(world), _entityStorage(entityStorage), _messageSender(messageSender), _timeProvider(timeProvider), _containerProvider(containerProvider), _poiProvider(poiProvider), _time(0L) {
|
||||
_loader(loader), _world(world), _entityStorage(entityStorage), _messageSender(messageSender), _timeProvider(timeProvider), _containerProvider(containerProvider), _poiProvider(poiProvider), _time(15000L) {
|
||||
}
|
||||
|
||||
bool SpawnMgr::init() {
|
||||
|
@ -82,7 +84,6 @@ int SpawnMgr::spawn(ai::Zone& zone, network::messages::NpcType type, int amount,
|
|||
}
|
||||
|
||||
void SpawnMgr::onFrame(ai::Zone& zone, long dt) {
|
||||
static const long spawnTime = 15000L;
|
||||
_time += dt;
|
||||
if (_time >= spawnTime) {
|
||||
_time -= spawnTime;
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
#include "PQHandle.h"
|
||||
#include "dbpost/StoreInterface.h"
|
||||
#include "UserStore.h"
|
||||
#include "core/Log.h"
|
||||
#include "core/Var.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
PQHandle::PQHandle() :
|
||||
_pqConnection(), _pqStore(&_pqConnection) {
|
||||
}
|
||||
|
||||
PQHandle::~PQHandle() {
|
||||
_pqConnection.disconnect();
|
||||
}
|
||||
|
||||
void PQHandle::storeUser(const std::string& mail, const std::string& passwd, const std::string& uid) {
|
||||
UserStore dbUser(mail, passwd, uid);
|
||||
_pqStore.storeModel(dbUser);
|
||||
}
|
||||
|
||||
int PQHandle::loadUser(const std::string& mail, const std::string& passwd, const std::string& uid) {
|
||||
const UserStore dbUser(mail, passwd, uid);
|
||||
_userData = std::move(_pqStore.loadModel(dbUser));
|
||||
if (_userData.size() > 0) {
|
||||
const int uid = std::stoi(_userData["userid"]);
|
||||
return uid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void PQHandle::close() {
|
||||
_pqConnection.disconnect();
|
||||
}
|
||||
|
||||
void PQHandle::initTables() {
|
||||
std::string tmUid = "0";
|
||||
std::string tmUser = std::string("a");
|
||||
std::string tmPw = std::string("b");
|
||||
UserStore dbUser(tmUser, tmPw, tmUid);
|
||||
_pqStore.createNeeds(dbUser);
|
||||
}
|
||||
|
||||
void PQHandle::init() {
|
||||
Log::trace("init database connection");
|
||||
const core::VarPtr& dbName = core::Var::get("db_name", "engine_db");
|
||||
const core::VarPtr& dbHost = core::Var::get("db_host", "localhost");
|
||||
const core::VarPtr& dbPw = core::Var::get("db_pw", "ben711cCefIUit887");
|
||||
const core::VarPtr& dbUser = core::Var::get("db_user", "dbmaster");
|
||||
|
||||
_pqConnection.changeDb(dbName->strVal());
|
||||
_pqConnection.changeHost(dbHost->strVal());
|
||||
_pqConnection.setLoginData(dbUser->strVal(), dbPw->strVal());
|
||||
|
||||
if (_pqConnection.connect() == 0) {
|
||||
Log::debug("database connection established");
|
||||
} else {
|
||||
Log::error("database connection failed");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include "dbpost/PQStore.h"
|
||||
#include "dbpost/PQConnect.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
class PQHandle {
|
||||
private:
|
||||
dbpost::PQConnect _pqConnection;
|
||||
dbpost::PQStore _pqStore;
|
||||
std::unordered_map<std::string, std::string> _userData;
|
||||
public:
|
||||
PQHandle();
|
||||
void init();
|
||||
void close();
|
||||
void initTables();
|
||||
void storeUser(const std::string& uMail, const std::string& uPasswd, const std::string& uid);
|
||||
int loadUser(const std::string& uMail, const std::string& uPasswd, const std::string& uid);
|
||||
virtual ~PQHandle();
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
#include "Persister.h"
|
||||
#include "UserStore.h"
|
||||
#include "core/Log.h"
|
||||
#include "core/Var.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
Persister::Persister() :
|
||||
_connection(), _store(&_connection) {
|
||||
}
|
||||
|
||||
Persister::~Persister() {
|
||||
_connection.disconnect();
|
||||
}
|
||||
|
||||
bool Persister::storeUser(const std::string& mail, const std::string& passwd, const std::string& uid) {
|
||||
UserStore dbUser(mail, passwd, uid);
|
||||
return _store.storeModel(dbUser);
|
||||
}
|
||||
|
||||
int Persister::loadUser(const std::string& mail, const std::string& passwd, const std::string& uid) {
|
||||
const UserStore dbUser(mail, passwd, uid);
|
||||
_userData = std::move(_store.loadModel(dbUser));
|
||||
if (!_userData.empty()) {
|
||||
const int uid = core::string::toInt(_userData["userid"]);
|
||||
return uid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Persister::close() {
|
||||
_connection.disconnect();
|
||||
}
|
||||
|
||||
bool Persister::initTables() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Persister::init() {
|
||||
Log::trace("init database connection");
|
||||
const core::VarPtr& dbName = core::Var::get("db_name", "engine_db");
|
||||
const core::VarPtr& dbHost = core::Var::get("db_host", "localhost");
|
||||
const core::VarPtr& dbPw = core::Var::get("db_pw", "ben711cCefIUit887");
|
||||
const core::VarPtr& dbUser = core::Var::get("db_user", "dbmaster");
|
||||
|
||||
_connection.changeDb(dbName->strVal());
|
||||
_connection.changeHost(dbHost->strVal());
|
||||
_connection.setLoginData(dbUser->strVal(), dbPw->strVal());
|
||||
|
||||
return _connection.connect();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include "persistence/Store.h"
|
||||
#include "persistence/Connection.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
class Persister {
|
||||
private:
|
||||
persistence::Connection _connection;
|
||||
persistence::Store _store;
|
||||
persistence::KeyValueMap _userData;
|
||||
public:
|
||||
Persister();
|
||||
virtual ~Persister();
|
||||
|
||||
bool init();
|
||||
|
||||
void close();
|
||||
|
||||
bool initTables();
|
||||
|
||||
bool storeUser(const std::string& uMail, const std::string& uPasswd, const std::string& uid);
|
||||
|
||||
int loadUser(const std::string& uMail, const std::string& uPasswd, const std::string& uid);
|
||||
};
|
||||
|
||||
}
|
|
@ -8,7 +8,7 @@ void StoreCmd::addComd() {
|
|||
if (args[0] == "help") {
|
||||
Log::info("store useradd <name> <password>\tadd a new users");
|
||||
} else if (args[0] == "init") {
|
||||
PQHandle pq;
|
||||
Persister pq;
|
||||
pq.init();
|
||||
pq.initTables();
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ void StoreCmd::addComd() {
|
|||
const std::string tmUid = "0";
|
||||
const std::string& tmUser = args[1];
|
||||
const std::string& tmPw = args[2];
|
||||
PQHandle pq;
|
||||
pq.init();
|
||||
pq.storeUser(tmUser, tmPw, tmUid);
|
||||
Persister persister;
|
||||
persister.init();
|
||||
persister.storeUser(tmUser, tmPw, tmUid);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "core/Log.h"
|
||||
#include "core/Var.h"
|
||||
#include "core/Command.h"
|
||||
#include "PQHandle.h"
|
||||
#include "Persister.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace backend {
|
||||
|
||||
UserStore::UserStore(const std::string& email, const std::string& password, const std::string& userid) :
|
||||
_email(email), _password(password), _userid(userid) {
|
||||
persistence::PeristenceModel("user_table"), _email(email), _password(password), _userid(userid) {
|
||||
}
|
||||
|
||||
std::string UserStore::getCreate() const {
|
||||
|
@ -23,13 +23,8 @@ void UserStore::update(const std::string& fieldName, const std::string& value) c
|
|||
}
|
||||
}
|
||||
|
||||
std::string UserStore::getTableName() const {
|
||||
static const std::string tabName = "user_table";
|
||||
return tabName;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> UserStore::getFields() const {
|
||||
std::unordered_map<std::string, std::string> storeData;
|
||||
persistence::Fields UserStore::getFields() const {
|
||||
persistence::Fields storeData;
|
||||
storeData["userid"] = _userid;
|
||||
storeData["user_email"] = _email;
|
||||
storeData["user_pw_hash"] = _password;
|
||||
|
|
|
@ -1,30 +1,27 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include "dbpost/StoreInterface.h"
|
||||
#include "persistence/PeristenceModel.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace backend {
|
||||
|
||||
class UserStore: public dbpost::StoreInterface {
|
||||
class UserStore: public persistence::PeristenceModel {
|
||||
private:
|
||||
std::string _email;
|
||||
std::string _password;
|
||||
std::string _userid;
|
||||
std::unordered_map<std::string, std::string> _storage;
|
||||
public:
|
||||
UserStore(const std::string& email, const std::string& password, const std::string& userid);
|
||||
|
||||
std::string getCreate() const override;
|
||||
|
||||
std::unordered_map<std::string, std::string> getFields() const override;
|
||||
persistence::Fields getFields() const override;
|
||||
|
||||
bool isSerial(const std::string& fieldname) const override;
|
||||
|
||||
virtual void update(const std::string& fieldName, const std::string& value) const override;
|
||||
|
||||
std::string getTableName() const override;
|
||||
void update(const std::string& fieldName, const std::string& value) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#include "core/tests/AbstractTest.h"
|
||||
#include "backend/storage/Persister.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
class PersisterTest : public core::AbstractTest {
|
||||
};
|
||||
|
||||
TEST(PersisterTest, testSaveAndLoadUser) {
|
||||
Persister persister;
|
||||
ASSERT_TRUE(persister.init()) << "Could not establish database connection";
|
||||
persister.initTables();
|
||||
// a second call for this will lead to duplicate key constraint errors
|
||||
persister.storeUser("test@somedomain.com", "12345", "0");
|
||||
const int userId = persister.loadUser("test@somedomain.com", "12345", "0");
|
||||
ASSERT_NE(0, userId) << "Could not load user";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "backend/storage/PQHandle.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
TEST(StorageTest, testCreate) {
|
||||
#if 0
|
||||
PQHandle pq;
|
||||
pq.init();
|
||||
pq.initTables();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
|
@ -5,10 +5,5 @@ fips_begin_module(commonlua)
|
|||
fips_deps(core lua52)
|
||||
fips_end_module()
|
||||
|
||||
gtest_begin(commonlua)
|
||||
fips_dir(tests)
|
||||
fips_files(
|
||||
LUATest.cpp
|
||||
)
|
||||
fips_deps(commonlua)
|
||||
gtest_end()
|
||||
gtest_suite_files(tests tests/LUATest.cpp)
|
||||
gtest_suite_deps(tests commonlua)
|
||||
|
|
|
@ -7,10 +7,5 @@ fips_begin_module(cooldown)
|
|||
fips_deps(core)
|
||||
fips_end_module()
|
||||
|
||||
gtest_begin(cooldown)
|
||||
fips_dir(tests)
|
||||
fips_files(
|
||||
CooldownMgrTest.cpp
|
||||
)
|
||||
fips_deps(cooldown)
|
||||
gtest_end()
|
||||
gtest_suite_files(tests tests/CooldownMgrTest.cpp)
|
||||
gtest_suite_deps(tests cooldown)
|
||||
|
|
|
@ -119,6 +119,7 @@ AppState App::onInit() {
|
|||
core::Var::get(name)->setVal(value);
|
||||
}
|
||||
|
||||
Log::init();
|
||||
Log::trace("handle %i command line arguments", _argc);
|
||||
for (int i = 0; i < _argc; ++i) {
|
||||
// every command is started with a '-'
|
||||
|
@ -137,6 +138,8 @@ AppState App::onInit() {
|
|||
Log::trace("Execute %s with %i arguments", command.c_str(), (int)args.size());
|
||||
core::Command::execute(command, args);
|
||||
}
|
||||
// we might have changed the loglevel from the commandline
|
||||
Log::init();
|
||||
return AppState::Running;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ fips_begin_module(core)
|
|||
EventBus.h
|
||||
IFactoryRegistry.h
|
||||
NonCopyable.h
|
||||
String.h
|
||||
String.cpp String.h
|
||||
Input.h
|
||||
QuadTree.h
|
||||
Singleton.h
|
||||
|
@ -20,23 +20,13 @@ fips_begin_module(core)
|
|||
Tokenizer.h
|
||||
TimeProvider.h TimeProvider.cpp
|
||||
)
|
||||
find_package(SDL2 REQUIRED)
|
||||
include_directories(${SDL2_INCLUDE_DIRS})
|
||||
fips_deps(io ${SDL2_LIBRARIES})
|
||||
fips_deps(io)
|
||||
fips_end_module()
|
||||
find_package(SDL2 REQUIRED)
|
||||
message(STATUS "SDL2 libs: ${SDL2_LIBRARIES}")
|
||||
message(STATUS "SDL2 includes: ${SDL2_INCLUDE_DIRS}")
|
||||
target_link_libraries(core ${SDL2_LIBRARIES})
|
||||
target_include_directories(core PUBLIC ${SDL2_INCLUDE_DIRS})
|
||||
|
||||
gtest_begin(core)
|
||||
fips_dir(tests)
|
||||
fips_files(
|
||||
RectTest.cpp
|
||||
ByteStreamTest.cpp
|
||||
ThreadPoolTest.cpp
|
||||
EventBusTest.cpp
|
||||
QuadTreeTest.cpp
|
||||
VarTest.cpp
|
||||
CommandTest.cpp
|
||||
SetTest.cpp
|
||||
TokenizerTest.cpp
|
||||
)
|
||||
fips_deps(core)
|
||||
gtest_end()
|
||||
gtest_suite_files(tests tests/AbstractTest.cpp tests/RectTest.cpp tests/ByteStreamTest.cpp tests/ThreadPoolTest.cpp tests/EventBusTest.cpp tests/QuadTreeTest.cpp tests/VarTest.cpp tests/CommandTest.cpp tests/SetTest.cpp tests/TokenizerTest.cpp)
|
||||
gtest_suite_deps(tests core)
|
||||
|
|
|
@ -3,65 +3,70 @@
|
|||
#include <cstring>
|
||||
#include <SDL.h>
|
||||
|
||||
enum {
|
||||
TRACE = 4, DEBUG = 3, INFO = 2, WARN = 1, ERROR = 0
|
||||
};
|
||||
static constexpr int bufSize = 1024;
|
||||
static SDL_LogPriority _logLevel;
|
||||
|
||||
Log::Log() {
|
||||
_logLevel = core::Var::get("core_loglevel", "2");
|
||||
}
|
||||
|
||||
void Log::vsnprint(const char* msg, va_list args) {
|
||||
char buf[1024];
|
||||
SDL_vsnprintf(buf, sizeof(buf), msg, args);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
if (buf[strlen(buf) - 1] == '\r')
|
||||
SDL_Log("%s\n", buf);
|
||||
else
|
||||
SDL_Log("%s\n", buf);
|
||||
void Log::init() {
|
||||
_logLevel = (SDL_LogPriority)core::Var::get("core_loglevel", std::to_string(SDL_LOG_PRIORITY_INFO))->intVal();
|
||||
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, _logLevel);
|
||||
}
|
||||
|
||||
void Log::trace(const char* msg, ...) {
|
||||
if (get()._logLevel->intVal() < DEBUG)
|
||||
if (_logLevel > SDL_LOG_PRIORITY_VERBOSE)
|
||||
return;
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
get().vsnprint(msg, args);
|
||||
char buf[bufSize];
|
||||
SDL_vsnprintf(buf, sizeof(buf), msg, args);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "%s\n", buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log::debug(const char* msg, ...) {
|
||||
if (get()._logLevel->intVal() < DEBUG)
|
||||
if (_logLevel > SDL_LOG_PRIORITY_DEBUG)
|
||||
return;
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
get().vsnprint(msg, args);
|
||||
char buf[bufSize];
|
||||
SDL_vsnprintf(buf, sizeof(buf), msg, args);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "%s\n", buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log::info(const char* msg, ...) {
|
||||
if (get()._logLevel->intVal() < INFO)
|
||||
if (_logLevel > SDL_LOG_PRIORITY_INFO)
|
||||
return;
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
get().vsnprint(msg, args);
|
||||
char buf[bufSize];
|
||||
SDL_vsnprintf(buf, sizeof(buf), msg, args);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%s\n", buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log::warn(const char* msg, ...) {
|
||||
if (get()._logLevel->intVal() < INFO)
|
||||
if (_logLevel > SDL_LOG_PRIORITY_WARN)
|
||||
return;
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
get().vsnprint(msg, args);
|
||||
char buf[bufSize];
|
||||
SDL_vsnprintf(buf, sizeof(buf), msg, args);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "%s\n", buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log::error(const char* msg, ...) {
|
||||
if (get()._logLevel->intVal() < INFO)
|
||||
if (_logLevel > SDL_LOG_PRIORITY_ERROR)
|
||||
return;
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
get().vsnprint(msg, args);
|
||||
char buf[bufSize];
|
||||
SDL_vsnprintf(buf, sizeof(buf), msg, args);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
|
|
@ -3,25 +3,9 @@
|
|||
#include <cstdio>
|
||||
#include <memory>
|
||||
|
||||
namespace core {
|
||||
class Var;
|
||||
typedef std::shared_ptr<Var> VarPtr;
|
||||
}
|
||||
|
||||
class Log {
|
||||
private:
|
||||
core::VarPtr _logLevel;
|
||||
|
||||
Log();
|
||||
|
||||
static inline Log& get() {
|
||||
static Log log;
|
||||
return log;
|
||||
}
|
||||
|
||||
void vsnprint(const char* msg, va_list args);
|
||||
|
||||
public:
|
||||
static void init();
|
||||
static void trace(const char* msg, ...) __attribute__((format(printf, 1, 2)));
|
||||
static void debug(const char* msg, ...) __attribute__((format(printf, 1, 2)));
|
||||
static void info(const char* msg, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#include "String.h"
|
||||
|
||||
namespace core {
|
||||
namespace string {
|
||||
|
||||
std::string format(const char *msg, ...) {
|
||||
va_list ap;
|
||||
constexpr std::size_t bufSize = 1024;
|
||||
char text[bufSize];
|
||||
|
||||
va_start(ap, msg);
|
||||
SDL_vsnprintf(text, bufSize, msg, ap);
|
||||
text[sizeof(text) - 1] = '\0';
|
||||
va_end(ap);
|
||||
|
||||
return std::string(text);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <stdarg.h>
|
||||
#include <SDL.h>
|
||||
|
||||
namespace core {
|
||||
namespace string {
|
||||
|
@ -89,7 +90,6 @@ inline int getUTF8Next (const char** str)
|
|||
return character;
|
||||
}
|
||||
|
||||
|
||||
inline size_t getUTF8Length(const std::string& str) {
|
||||
size_t result = 0;
|
||||
const char *string = str.c_str();
|
||||
|
@ -102,20 +102,10 @@ inline size_t getUTF8Length(const std::string& str) {
|
|||
return result;
|
||||
}
|
||||
|
||||
inline std::string format(const char *msg, ...) {
|
||||
va_list ap;
|
||||
const std::size_t bufSize = 1024;
|
||||
char text[bufSize];
|
||||
|
||||
va_start(ap, msg);
|
||||
vsnprintf(text, bufSize, msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
return std::string(text);
|
||||
}
|
||||
extern std::string format(const char *msg, ...) SDL_PRINTF_VARARG_FUNC(1);
|
||||
|
||||
inline int toInt(const std::string& str) {
|
||||
return ::atoi(str.c_str());
|
||||
return SDL_atoi(str.c_str());
|
||||
}
|
||||
|
||||
inline int toLong(const std::string& str) {
|
||||
|
@ -127,7 +117,7 @@ inline bool toBool(const std::string& str) {
|
|||
}
|
||||
|
||||
inline float toFloat(const std::string& str) {
|
||||
return atof(str.c_str());
|
||||
return SDL_atof(str.c_str());
|
||||
}
|
||||
|
||||
inline void splitString(const std::string& string, std::vector<std::string>& tokens, const std::string& delimiters = " \t\r\n\f\v") {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#include "AbstractTest.h"
|
||||
#include "core/Log.h"
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
void AbstractTest::SetUp() {
|
||||
Log::init();
|
||||
core::EventBusPtr eventBus = core::EventBusPtr(new core::EventBus());
|
||||
io::FilesystemPtr filesystem = io::FilesystemPtr(new io::Filesystem());
|
||||
_testApp = new TestApp(filesystem,eventBus);
|
||||
}
|
||||
|
||||
void AbstractTest::TearDown() {
|
||||
delete _testApp;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,8 @@
|
|||
#include "core/EventBus.h"
|
||||
#include "io/Filesystem.h"
|
||||
|
||||
#include "stb_image_write.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class AbstractTest: public testing::Test {
|
||||
|
@ -19,15 +21,9 @@ private:
|
|||
TestApp *_testApp;
|
||||
|
||||
public:
|
||||
void SetUp() override {
|
||||
core::EventBusPtr eventBus = core::EventBusPtr(new core::EventBus());
|
||||
io::FilesystemPtr filesystem = io::FilesystemPtr(new io::Filesystem());
|
||||
_testApp = new TestApp(filesystem,eventBus);
|
||||
}
|
||||
void SetUp() override;
|
||||
|
||||
void TearDown() override {
|
||||
delete _testApp;
|
||||
}
|
||||
void TearDown() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
class LocalEnv: public ::testing::Environment {
|
||||
public:
|
||||
virtual ~LocalEnv() {
|
||||
}
|
||||
virtual void SetUp() override {
|
||||
}
|
||||
virtual void TearDown() override {
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" int main (int argc, char *argv[]) {
|
||||
::testing::AddGlobalTestEnvironment(new LocalEnv);
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
#if __cpp_exceptions
|
||||
try {
|
||||
#endif
|
||||
return RUN_ALL_TESTS();
|
||||
#if __cpp_exceptions
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
#include "PQConnect.h"
|
||||
#include "core/Log.h"
|
||||
|
||||
namespace dbpost {
|
||||
|
||||
PQConnect::PQConnect() :
|
||||
_pgConnection(nullptr) {
|
||||
}
|
||||
|
||||
PQConnect::~PQConnect() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
void PQConnect::setLoginData(const std::string& username, const std::string& password) {
|
||||
_password = password;
|
||||
_user = username;
|
||||
}
|
||||
|
||||
void PQConnect::changeDb(const std::string& dbname) {
|
||||
_dbname = dbname;
|
||||
}
|
||||
|
||||
void PQConnect::changeHost(const std::string& host) {
|
||||
_host = host;
|
||||
}
|
||||
|
||||
void PQConnect::changePort(const std::string& port) {
|
||||
_port = port;
|
||||
}
|
||||
|
||||
int PQConnect::connect() {
|
||||
//const std::string conninfo = "hostaddr=" + _host + " port=" + _port + " dbname=" + _dbname + " user=" + _user + " password=" + _password;
|
||||
std::string conninfo = "";
|
||||
|
||||
if (!_host.empty())
|
||||
conninfo += " host=" + _host;
|
||||
if (!_dbname.empty())
|
||||
conninfo += " dbname=" + _dbname;
|
||||
if (!_user.empty())
|
||||
conninfo += " user=" + _user;
|
||||
if (!_password.empty())
|
||||
conninfo += " password=" + _password;
|
||||
if (!_port.empty())
|
||||
conninfo += " port=" + _port;
|
||||
|
||||
Log::info("Connection: %s", conninfo.c_str());
|
||||
|
||||
_pgConnection = PQconnectdb(conninfo.c_str());
|
||||
|
||||
if (PQstatus(_pgConnection) != CONNECTION_OK) {
|
||||
Log::error("Connection to database failed: %s", PQerrorMessage(_pgConnection));
|
||||
disconnect();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PQConnect::disconnect() {
|
||||
PQfinish(_pgConnection);
|
||||
_pgConnection = nullptr;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <postgresql/libpq-fe.h>
|
||||
#include "core/NonCopyable.h"
|
||||
#include "PQConnect.h"
|
||||
#include "StoreInterface.h"
|
||||
|
||||
typedef std::unordered_map<std::string, std::string> TStrStrMap;
|
||||
typedef std::pair<std::string, std::string> TStrStrPair;
|
||||
|
||||
namespace dbpost {
|
||||
|
||||
class PQStore : public core::NonCopyable {
|
||||
private:
|
||||
std::string sqlBuilder(const StoreInterface& model, bool update) const;
|
||||
std::string sqlLoadBuilder(const StoreInterface& model, bool update) const;
|
||||
PQConnect* _connection;
|
||||
bool _usable;
|
||||
PGresult* _res;
|
||||
std::string _lastErrorMsg;
|
||||
ExecStatusType _lastState;
|
||||
int _affectedRows;
|
||||
public:
|
||||
PQStore(PQConnect* conn);
|
||||
bool query(const std::string& query);
|
||||
void trBegin();
|
||||
void trEnd();
|
||||
bool checkLastResult();
|
||||
void storeModel(StoreInterface& model);
|
||||
void createNeeds(const StoreInterface& model);
|
||||
std::unordered_map<std::string, std::string> loadModel(const StoreInterface& model);
|
||||
~PQStore();
|
||||
|
||||
PGresult* result() const;
|
||||
};
|
||||
|
||||
inline PGresult* PQStore::result() const {
|
||||
return _res;
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
#include "StoreInterface.h"
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace dbpost {
|
||||
|
||||
class StoreInterface {
|
||||
public:
|
||||
virtual ~StoreInterface() {
|
||||
}
|
||||
virtual std::string getCreate() const = 0;
|
||||
virtual std::string getTableName() const = 0;
|
||||
virtual std::unordered_map<std::string, std::string> getFields() const = 0;
|
||||
virtual void update(const std::string& fieldName,const std::string& value) const = 0;
|
||||
virtual bool isSerial(const std::string& fieldname) const = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
namespace dbpost {
|
||||
|
||||
TEST(PQStoreTest, testFoo) {
|
||||
}
|
||||
|
||||
}
|
|
@ -25,15 +25,18 @@ public:
|
|||
|
||||
bool OnEvent(const tb::TBWidgetEvent &ev) override {
|
||||
if ((ev.type == tb::EVENT_TYPE_CLICK && ev.target->GetID() == TBIDC("login")) || ev.special_key == tb::TB_KEY_ENTER) {
|
||||
TBWidget *email = ev.target->GetParentWindow()->GetWidgetByID(tb::TBID("email"));
|
||||
TBWidget *password = ev.target->GetParentWindow()->GetWidgetByID(tb::TBID("password"));
|
||||
TBWindow *window = ev.target->GetParentWindow();
|
||||
TBWidget *email = window->GetWidgetByID(tb::TBID("email"));
|
||||
TBWidget *password = window->GetWidgetByID(tb::TBID("password"));
|
||||
|
||||
core::Var::get("cl_email")->setVal(email->GetText().CStr());
|
||||
core::Var::get("cl_password")->setVal(password->GetText().CStr());
|
||||
|
||||
const core::VarPtr& port = core::Var::get("cl_port", "11337");
|
||||
const core::VarPtr& host = core::Var::get("cl_host", "127.0.0.1");
|
||||
Log::info("Trying to connect to server %s:%i", host->strVal().c_str(), port->intVal());
|
||||
if (!_client->connect(port->intVal(), host->strVal())) {
|
||||
Log::info("Failed to connect to server %s:%i", host->strVal().c_str(), port->intVal());
|
||||
tb::TBStr text;
|
||||
text.SetFormatted("Failed to connect");
|
||||
tb::TBMessageWindow *win = new tb::TBMessageWindow(this, TBIDC(""));
|
||||
|
|
|
@ -61,6 +61,10 @@ ENetPeer* Network::connect(uint16_t port, const std::string& hostname, int maxCh
|
|||
address.port = port;
|
||||
|
||||
ENetPeer *peer = enet_host_connect(_client, &address, maxChannels, 0);
|
||||
if (peer == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
enet_host_flush(_client);
|
||||
enet_peer_timeout(peer, ENET_PEER_TIMEOUT_LIMIT, ENET_PEER_TIMEOUT_MINIMUM, ENET_PEER_TIMEOUT_MAXIMUM);
|
||||
return peer;
|
||||
|
@ -93,6 +97,7 @@ void Network::disconnectPeer(ENetPeer *peer, uint32_t timeout) {
|
|||
enet_packet_destroy(event.packet);
|
||||
break;
|
||||
case ENET_EVENT_TYPE_DISCONNECT:
|
||||
_eventBus->publish(DisconnectEvent(event.peer));
|
||||
success = true;
|
||||
break;
|
||||
case ENET_EVENT_TYPE_CONNECT:
|
||||
|
@ -104,6 +109,7 @@ void Network::disconnectPeer(ENetPeer *peer, uint32_t timeout) {
|
|||
/* We've arrived here, so the disconnect attempt didn't */
|
||||
/* succeed yet. Force the connection down. */
|
||||
enet_peer_reset(peer);
|
||||
_eventBus->publish(DisconnectEvent(event.peer));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <enet/enet.h>
|
||||
#include "core/Log.h"
|
||||
|
||||
namespace network {
|
||||
|
||||
|
@ -10,6 +11,7 @@ private:
|
|||
public:
|
||||
NewConnectionEvent(ENetPeer* peer) :
|
||||
_peer(peer) {
|
||||
Log::info("Connect peer %i", peer->connectID);
|
||||
}
|
||||
inline ENetPeer* peer() const {
|
||||
return _peer;
|
||||
|
@ -22,6 +24,7 @@ private:
|
|||
public:
|
||||
DisconnectEvent(ENetPeer* peer) :
|
||||
_peer(peer) {
|
||||
Log::info("Disconnect peer %i", peer->connectID);
|
||||
}
|
||||
inline ENetPeer* peer() const {
|
||||
return _peer;
|
||||
|
|
|
@ -13,6 +13,11 @@ struct Vec2 {
|
|||
y:float;
|
||||
}
|
||||
|
||||
struct IVec2 {
|
||||
x:int;
|
||||
y:int;
|
||||
}
|
||||
|
||||
enum NpcType: int {
|
||||
NONE,
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace network {
|
|||
namespace messages {
|
||||
struct Vec3;
|
||||
struct Vec2;
|
||||
struct IVec2;
|
||||
} // namespace messages
|
||||
} // namespace network
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace messages {
|
|||
|
||||
struct Vec3;
|
||||
struct Vec2;
|
||||
struct IVec2;
|
||||
|
||||
enum NpcType {
|
||||
NpcType_NONE = 0,
|
||||
|
@ -73,6 +74,20 @@ MANUALLY_ALIGNED_STRUCT(4) Vec2 FLATBUFFERS_FINAL_CLASS {
|
|||
};
|
||||
STRUCT_END(Vec2, 8);
|
||||
|
||||
MANUALLY_ALIGNED_STRUCT(4) IVec2 FLATBUFFERS_FINAL_CLASS {
|
||||
private:
|
||||
int32_t x_;
|
||||
int32_t y_;
|
||||
|
||||
public:
|
||||
IVec2(int32_t x, int32_t y)
|
||||
: x_(flatbuffers::EndianScalar(x)), y_(flatbuffers::EndianScalar(y)) { }
|
||||
|
||||
int32_t x() const { return flatbuffers::EndianScalar(x_); }
|
||||
int32_t y() const { return flatbuffers::EndianScalar(y_); }
|
||||
};
|
||||
STRUCT_END(IVec2, 8);
|
||||
|
||||
} // namespace messages
|
||||
} // namespace network
|
||||
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
#include "AccidentalNoise.h"
|
||||
|
||||
namespace noise {
|
||||
|
||||
// TODO: erosion: https://code.google.com/p/accidental-noise-library/wiki/ModuleBasics
|
||||
#if 0
|
||||
impad=anl.CImplicitBufferImplicitAdapter(turb, anl.SEAMLESS_NONE, anl.SMappingRanges(0,4,0,4,0,4), true, 0)
|
||||
erode=anl.CImplicitBufferSimpleErode(impad, 0, 0.35)
|
||||
blur=anl.CImplicitBufferBlur(erode, 3/256)
|
||||
bump=anl.CImplicitBufferBumpMap(blur, -1.5, 3.5, 1.5, 0.5, false)
|
||||
#endif
|
||||
AccidentalNoise::AccidentalNoise() :
|
||||
#if 0
|
||||
groundGradient(0.0, 0.0, 0.0, 1.0, 0.0, 0.0),
|
||||
|
||||
plainFractal(anl::EFractalTypes::BILLOW, anl::GRADIENT, anl::QUINTIC, 1, 0.25, false),
|
||||
plainAutoCorrect(&plainFractal, 0.0, 1.0),
|
||||
plainScaleOffset(&plainAutoCorrect, 0.125, 0.3),
|
||||
plainScaleDomain(&plainScaleOffset, 1.0, 0.0),
|
||||
plainTranslateDomain(&groundGradient, 0.0, &plainScaleDomain, 0.0),
|
||||
|
||||
highlandFractal(anl::EFractalTypes::FBM, anl::GRADIENT, anl::QUINTIC, 2, 0.5, false),
|
||||
highlandAutoCorrect(&highlandFractal, 0.0, 1.0),
|
||||
highlandScaleOffset(&highlandAutoCorrect, 0.15, 0.0),
|
||||
highlandScaleDomain(&highlandScaleOffset, 1.0, 0.0),
|
||||
highlandTranslateDomain(&groundGradient, 0.0, &highlandScaleDomain, 0.0),
|
||||
|
||||
mountainFractal(anl::EFractalTypes::RIDGEDMULTI, anl::GRADIENT, anl::QUINTIC, 4, 0.8, false),
|
||||
mountainAutoCorrect(&mountainFractal, 0.0, 1.0),
|
||||
mountainScaleOffset(&mountainAutoCorrect, 1.5, -0.75),
|
||||
mountainScaleDomain(&mountainScaleOffset, 1.0, 0.5),
|
||||
mountainTranslateDomain(&groundGradient, 0.0, &mountainScaleDomain, 0.0),
|
||||
|
||||
terrainControl(anl::EFractalTypes::BILLOW, anl::GRADIENT, anl::QUINTIC, 1, 0.05, false),
|
||||
terrainAutoCorrect(&terrainControl, 0.0, 1.0),
|
||||
terrainScaleOffset(&terrainAutoCorrect, 10.0, 0.0),
|
||||
terrainScaleDomain(&terrainScaleOffset, 1.0, 0.0),
|
||||
terrainCache(&terrainScaleDomain),
|
||||
|
||||
highlandMountainSelect(&highlandTranslateDomain, &mountainTranslateDomain, &terrainCache, 9.0, 1.5),
|
||||
highlandMountainColorSelect(&highland, &mountain, &terrainCache, 9.0, 0.0),
|
||||
highlandMountainColorCache(&highlandMountainColorSelect),
|
||||
plainHighlandSelect(&plainTranslateDomain, &highlandMountainSelect, &terrainCache, 4.0, 1.5),
|
||||
plainHighlandColorSelect(&plain, &highlandMountainColorSelect, &terrainCache, 4.0, 0.0),
|
||||
|
||||
plainHighlandCache(&plainHighlandSelect),
|
||||
|
||||
groundBase()
|
||||
#endif
|
||||
plainFractal(anl::EFractalTypes::FBM, anl::GRADIENT, anl::QUINTIC, 10, 1.0, false)
|
||||
{
|
||||
#if 0
|
||||
air.setConstant(0.0);
|
||||
plain.setConstant(1.0);
|
||||
highland.setConstant(2.0);
|
||||
mountain.setConstant(3.0);
|
||||
|
||||
groundBase.setLowSource(&plainHighlandColorSelect);
|
||||
groundBase.setHighSource(&air);
|
||||
groundBase.setControlSource(&plainHighlandCache);
|
||||
groundBase.setThreshold(0.5);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AccidentalNoise::setSeed(long seed) {
|
||||
anl::CMWC4096 rnd;
|
||||
rnd.setSeed(seed);
|
||||
#if 0
|
||||
plainFractal.setSeed(rnd.get());
|
||||
highlandFractal.setSeed(rnd.get());
|
||||
mountainFractal.setSeed(rnd.get());
|
||||
terrainControl.setSeed(rnd.get());
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/Random.h"
|
||||
#include "core/Common.h"
|
||||
#include <anl_noise.h>
|
||||
#include <anl_rgba.h>
|
||||
#include <anl_imaging.h>
|
||||
#include <mapping.h>
|
||||
|
||||
namespace noise {
|
||||
|
||||
class AccidentalNoise {
|
||||
private:
|
||||
#if 0
|
||||
anl::CImplicitConstant air;
|
||||
anl::CImplicitConstant plain;
|
||||
anl::CImplicitConstant highland;
|
||||
anl::CImplicitConstant mountain;
|
||||
|
||||
anl::CImplicitGradient groundGradient;
|
||||
|
||||
anl::CImplicitFractal plainFractal;
|
||||
anl::CImplicitAutoCorrect plainAutoCorrect;
|
||||
anl::CImplicitScaleOffset plainScaleOffset;
|
||||
anl::CImplicitScaleDomain plainScaleDomain;
|
||||
anl::CImplicitTranslateDomain plainTranslateDomain;
|
||||
|
||||
anl::CImplicitFractal highlandFractal;
|
||||
anl::CImplicitAutoCorrect highlandAutoCorrect;
|
||||
anl::CImplicitScaleOffset highlandScaleOffset;
|
||||
anl::CImplicitScaleDomain highlandScaleDomain;
|
||||
anl::CImplicitTranslateDomain highlandTranslateDomain;
|
||||
|
||||
anl::CImplicitFractal mountainFractal;
|
||||
anl::CImplicitAutoCorrect mountainAutoCorrect;
|
||||
anl::CImplicitScaleOffset mountainScaleOffset;
|
||||
anl::CImplicitScaleDomain mountainScaleDomain;
|
||||
anl::CImplicitTranslateDomain mountainTranslateDomain;
|
||||
|
||||
anl::CImplicitFractal terrainControl;
|
||||
anl::CImplicitAutoCorrect terrainAutoCorrect;
|
||||
anl::CImplicitScaleOffset terrainScaleOffset;
|
||||
anl::CImplicitScaleDomain terrainScaleDomain;
|
||||
anl::CImplicitCache terrainCache;
|
||||
|
||||
anl::CImplicitSelect highlandMountainSelect;
|
||||
anl::CImplicitSelect highlandMountainColorSelect;
|
||||
anl::CImplicitCache highlandMountainColorCache;
|
||||
anl::CImplicitSelect plainHighlandSelect;
|
||||
anl::CImplicitSelect plainHighlandColorSelect;
|
||||
anl::CImplicitCache plainHighlandCache;
|
||||
|
||||
anl::CImplicitSelect groundBase;
|
||||
#endif
|
||||
anl::CImplicitFractal plainFractal;
|
||||
|
||||
public:
|
||||
AccidentalNoise();
|
||||
|
||||
double get(double x, double y, double z, double worldDimension);
|
||||
|
||||
void setSeed(long seed);
|
||||
};
|
||||
|
||||
inline double AccidentalNoise::get(double x, double y, double z, double worldDimension) {
|
||||
const double scale = 1.0 / worldDimension;
|
||||
return plainFractal.get(x * scale, y * scale, z * scale);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +1,9 @@
|
|||
fips_begin_module(noise)
|
||||
fips_files(
|
||||
PerlinNoise.h PerlinNoise.cpp stb_perlin.h
|
||||
AccidentalNoise.h AccidentalNoise.cpp
|
||||
NoisePPNoise.h NoisePPNoise.cpp
|
||||
WorldShapeNoise.h WorldShapeNoise.cpp
|
||||
SimplexNoise.h SimplexNoise.cpp
|
||||
)
|
||||
fips_deps(core noisepp accidentalnoise)
|
||||
fips_deps(core)
|
||||
fips_end_module()
|
||||
|
||||
gtest_begin(noise)
|
||||
fips_dir(tests)
|
||||
fips_files(
|
||||
AccidentalNoiseTest.cpp
|
||||
PerlinNoiseTest.cpp
|
||||
NoisePPNoiseTest.cpp
|
||||
NoiseTestHelper.h
|
||||
)
|
||||
fips_deps(core noise accidentalnoise)
|
||||
gtest_end()
|
||||
gtest_suite_files(tests tests/SimplexNoiseTest.cpp)
|
||||
gtest_suite_deps(tests core noise)
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
#include "NoisePPNoise.h"
|
||||
#include <Noise.h>
|
||||
#include <NoiseUtils.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace noise {
|
||||
|
||||
void NoisePPNoise::init() {
|
||||
noisepp::ConstantModule lowConstant;
|
||||
lowConstant.setValue(0);
|
||||
|
||||
noisepp::ConstantModule highConstant;
|
||||
highConstant.setValue(1);
|
||||
|
||||
noisepp::BillowModule plainNoise;
|
||||
plainNoise.setOctaveCount(1);
|
||||
plainNoise.setQuality(noisepp::NOISE_QUALITY_STD);
|
||||
plainNoise.setFrequency(0.25);
|
||||
plainNoise.setLacunarity(2.0);
|
||||
plainNoise.setPersistence(1);
|
||||
|
||||
noisepp::PerlinModule highlandNoise;
|
||||
highlandNoise.setOctaveCount(2);
|
||||
highlandNoise.setQuality(noisepp::NOISE_QUALITY_STD);
|
||||
highlandNoise.setFrequency(0.5);
|
||||
highlandNoise.setLacunarity(2.0);
|
||||
highlandNoise.setPersistence(1);
|
||||
|
||||
noisepp::RidgedMultiModule mountainNoise;
|
||||
mountainNoise.setOctaveCount(4);
|
||||
mountainNoise.setQuality(noisepp::NOISE_QUALITY_STD);
|
||||
mountainNoise.setFrequency(0.8);
|
||||
mountainNoise.setLacunarity(2.0);
|
||||
|
||||
noisepp::PerlinModule controlNoise;
|
||||
controlNoise.setOctaveCount(1);
|
||||
controlNoise.setQuality(noisepp::NOISE_QUALITY_STD);
|
||||
controlNoise.setFrequency(0.05);
|
||||
controlNoise.setLacunarity(2.0);
|
||||
controlNoise.setPersistence(1);
|
||||
|
||||
noisepp::SelectModule highlandMountainSelection;
|
||||
highlandMountainSelection.setControlModule(controlNoise);
|
||||
highlandMountainSelection.setSourceModule(0, highlandNoise);
|
||||
highlandMountainSelection.setSourceModule(1, mountainNoise);
|
||||
highlandMountainSelection.setLowerBound(0.2);
|
||||
|
||||
noisepp::SelectModule plainHighlandSelection;
|
||||
plainHighlandSelection.setControlModule(controlNoise);
|
||||
plainHighlandSelection.setSourceModule(0, plainNoise);
|
||||
plainHighlandSelection.setSourceModule(1, highlandMountainSelection);
|
||||
plainHighlandSelection.setLowerBound(0.0);
|
||||
|
||||
_buffer = new noisepp::Real[_w * _h];
|
||||
// create a builder
|
||||
noisepp::utils::PlaneBuilder2D builder;
|
||||
// set the source module
|
||||
builder.setModule(plainHighlandSelection);
|
||||
// set the buffer
|
||||
builder.setDestination(_buffer);
|
||||
// set the buffer size
|
||||
builder.setSize(_w, _h);
|
||||
// set the plane bounds - from (0.5|0) to (1.5|1)
|
||||
builder.setBounds(0.5, 0, 1.5, 1);
|
||||
// build
|
||||
builder.build();
|
||||
|
||||
// create an image
|
||||
noisepp::utils::Image img;
|
||||
img.create(_w, _h);
|
||||
// create the renderer and add some gradients to create a heat-vision like material
|
||||
noisepp::utils::GradientRenderer renderer;
|
||||
// renderer.addGradient (<value>, noisepp::utils::ColourValue(<red>, <green>, <blue>));
|
||||
renderer.addGradient(-1.0, noisepp::utils::ColourValue(0.0f, 0.0f, 0.2f));
|
||||
renderer.addGradient(-0.8, noisepp::utils::ColourValue(0.0f, 0.0f, 0.6f));
|
||||
renderer.addGradient(0.0, noisepp::utils::ColourValue(1.0f, 0.0f, 0.0f));
|
||||
renderer.addGradient(0.6, noisepp::utils::ColourValue(1.0f, 1.0f, 0.0f));
|
||||
renderer.addGradient(1.0, noisepp::utils::ColourValue(1.0f, 1.0f, 1.0f));
|
||||
// render the image
|
||||
renderer.renderImage(img, _buffer);
|
||||
// save the image to an BMP
|
||||
img.saveBMP("output.bmp");
|
||||
|
||||
}
|
||||
|
||||
double NoisePPNoise::get(double x, double y, double z, double worldDimension) {
|
||||
int value = x + y * _h;
|
||||
return _buffer[value];
|
||||
}
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
#include <Noise.h>
|
||||
|
||||
namespace noise {
|
||||
|
||||
class NoisePPNoise {
|
||||
private:
|
||||
noisepp::Real *_buffer;
|
||||
int _w = 64;
|
||||
int _h = 64;
|
||||
|
||||
public:
|
||||
void init();
|
||||
|
||||
double get(double x, double y, double z, double worldDimension);
|
||||
|
||||
void setSeed(long seed) {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#include "PerlinNoise.h"
|
||||
|
||||
#define STB_PERLIN_IMPLEMENTATION
|
||||
#include "stb_perlin.h"
|
||||
|
||||
namespace noise {
|
||||
|
||||
double PerlinNoise::get(double x, double y, double z, double worldDimension) {
|
||||
const double scale = 1.0 / worldDimension;
|
||||
const float height = stb_perlin_noise3(x * scale, y * scale, z * scale, 0, 0, 0);
|
||||
if (::fabs(height) >= y * scale)
|
||||
return 1.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "stb_perlin.h"
|
||||
|
||||
namespace noise {
|
||||
|
||||
class PerlinNoise {
|
||||
public:
|
||||
double get(double x, double y, double z, double worldDimension);
|
||||
|
||||
void setSeed(long seed) {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#include "SimplexNoise.h"
|
||||
#include <glm/gtc/noise.hpp>
|
||||
|
||||
namespace noise {
|
||||
|
||||
template<class VecType>
|
||||
static float Noise(const VecType& pos, int octaves, float persistence, float frequency, float amplitude) {
|
||||
float total = 0.0f;
|
||||
float maxAmplitude = amplitude;
|
||||
for (int i = 0; i < octaves; ++i) {
|
||||
total += glm::simplex(pos * frequency) * amplitude;
|
||||
frequency *= 2.0f;
|
||||
maxAmplitude += amplitude;
|
||||
amplitude *= persistence;
|
||||
}
|
||||
return total / maxAmplitude;
|
||||
}
|
||||
|
||||
float Simplex::Noise2D(const glm::vec2& pos, int octaves, float persistence, float frequency, float amplitude) {
|
||||
return Noise(pos, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
float Simplex::Noise3D(const glm::vec3& pos, int octaves, float persistence, float frequency, float amplitude) {
|
||||
return Noise(pos, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
float Simplex::Noise4D(const glm::vec4& pos, int octaves, float persistence, float frequency, float amplitude) {
|
||||
return Noise(pos, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
#include <glm/vec2.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
namespace noise {
|
||||
|
||||
class Simplex {
|
||||
public:
|
||||
/**
|
||||
* @return A value between [-1,1]
|
||||
* @param[in] octaves the amount of noise calls that contribute to the final result
|
||||
* @param[in] persistence the persistence defines how much of the amplitude will be applied to the next noise call (only makes
|
||||
* sense if you have @c octaves > 1). The higher this value is (ranges from 0-1) the more each new octave will add to the result.
|
||||
* @param[in] frequency the higher the @c frequency the more deviation you get in your noise (wavelength).
|
||||
* @param[in] amplitude the amplitude defines how high the noise will be.
|
||||
*/
|
||||
static float Noise2D(const glm::vec2& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f);
|
||||
/**
|
||||
* @return A value between [-1,1]
|
||||
* @param[in] octaves the amount of noise calls that contribute to the final result
|
||||
* @param[in] persistence the persistence defines how much of the amplitude will be applied to the next noise call (only makes
|
||||
* sense if you have @c octaves > 1). The higher this value is (ranges from 0-1) the more each new octave will add to the result.
|
||||
* @param[in] frequency the higher the @c frequency the more deviation you get in your noise (wavelength).
|
||||
* @param[in] amplitude the amplitude defines how high the noise will be.
|
||||
*/
|
||||
static float Noise3D(const glm::vec3& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f);
|
||||
/**
|
||||
* @return A value between [-1,1]
|
||||
* @param[in] octaves the amount of noise calls that contribute to the final result
|
||||
* @param[in] persistence the persistence defines how much of the amplitude will be applied to the next noise call (only makes
|
||||
* sense if you have @c octaves > 1). The higher this value is (ranges from 0-1) the more each new octave will add to the result.
|
||||
* @param[in] frequency the higher the @c frequency the more deviation you get in your noise (wavelength).
|
||||
* @param[in] amplitude the amplitude defines how high the noise will be.
|
||||
*/
|
||||
static float Noise4D(const glm::vec4& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f);
|
||||
/**
|
||||
* @brief Fills the given target buffer with RGB or RGBA values for the noise (depending on the components).
|
||||
* @param[in] buffer pointer to the target buffer - must be of size @c width * height * 3
|
||||
* @param[in] width the width of the image. Make sure that the target buffer has enough space to
|
||||
* store the needed data for the dimensions you specify here.
|
||||
* @param[in] height the height of the image. Make sure that the target buffer has enough space
|
||||
* to store the needed data for the dimensions you specify here.
|
||||
* @param[in] components 4 for RGBA and 3 for RGB
|
||||
* @param[in] octaves the amount of noise calls that contribute to the final result
|
||||
* @param[in] persistence the persistence defines how much of the amplitude will be applied to the next noise call (only makes
|
||||
* sense if you have @c octaves > 1). The higher this value is (ranges from 0-1) the more each new octave will add to the result.
|
||||
* @param[in] frequency the higher the @c frequency the more deviation you get in your noise (wavelength).
|
||||
* @param[in] amplitude the amplitude defines how high the noise will be.
|
||||
*/
|
||||
static void Noise2DBuffer(uint8_t* buffer, int width, int height, int components, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DBuffer(buffer, width, height, components, glm::vec2(0), octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DBuffer(uint8_t* buffer, int width, int height, int components, const glm::vec2& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DBuffer(buffer, width, height, components, pos, noise::Simplex::Noise2D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DBuffer(uint8_t* buffer, int width, int height, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DBuffer(buffer, width, height, 1, glm::vec2(0), octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DBuffer(uint8_t* buffer, int width, int height, const glm::vec2& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DBuffer(buffer, width, height, 1, pos, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DGray(uint8_t* buffer, int width, int height, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DBuffer(buffer, width, height, 3, glm::vec2(0), octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DGray(uint8_t* buffer, int width, int height, const glm::vec2& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DBuffer(buffer, width, height, 3, pos, noise::Simplex::Noise2D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DGrayA(uint8_t* buffer, int width, int height, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DBuffer(buffer, width, height, 4, glm::vec2(0), octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DGrayA(uint8_t* buffer, int width, int height, const glm::vec2& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DBuffer(buffer, width, height, 4, pos, noise::Simplex::Noise2D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DRGB(uint8_t* buffer, int width, int height, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DChannel(buffer, width, height, 3, glm::vec2(0), octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DRGB(uint8_t* buffer, int width, int height, const glm::vec2& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DChannel(buffer, width, height, 3, pos, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DRGBA(uint8_t* buffer, int width, int height, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DChannel(buffer, width, height, 4, glm::vec2(0), octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DRGBA(uint8_t* buffer, int width, int height, const glm::vec2& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
Noise2DChannel(buffer, width, height, 4, pos, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void Noise2DChannel(uint8_t* buffer, int width, int height, int components, const glm::vec2& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
uint8_t buffer_channel[width * height];
|
||||
for (int channel = 0; channel < components; ++channel) {
|
||||
Noise2DBuffer(buffer_channel, width, height, 1, pos + glm::vec2(channel), noise::Simplex::Noise2D, octaves, persistence, frequency, amplitude);
|
||||
int index = 0;
|
||||
for (int x = 0; x < width; ++x) {
|
||||
for (int y = 0; y < height; ++y, ++index) {
|
||||
buffer[index*3+channel] = buffer_channel[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Func, class ... Args>
|
||||
static void Noise2DBuffer(uint8_t* buffer, int width, int height, int components, const glm::vec2& pos, Func&& func, Args&&... args) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
float noise = func(glm::vec2(x, y) + pos, std::forward<Args>(args)...);
|
||||
float noiseHeight = (noise + 1.0f) * 0.5f;
|
||||
unsigned char color = (unsigned char) (noiseHeight * 255.0f);
|
||||
int index = y * (width * components) + (x * components);
|
||||
const int n = components == 4 ? 3 : components;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
buffer[index++] = color;
|
||||
}
|
||||
if (components == 4) {
|
||||
buffer[index] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DBuffer(uint8_t* buffer, int size, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DBuffer(buffer, size, 1, glm::vec4(0), noise::Simplex::Noise4D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DBuffer(uint8_t* buffer, int size, const glm::vec4& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DBuffer(buffer, size, 1, pos, noise::Simplex::Noise4D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DBuffer(uint8_t* buffer, int size, int components, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DBuffer(buffer, size, components, glm::vec4(0), noise::Simplex::Noise4D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DBuffer(uint8_t* buffer, int size, int components, const glm::vec4& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DBuffer(buffer, size, components, pos, noise::Simplex::Noise4D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DGray(uint8_t* buffer, int size, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DBuffer(buffer, size, 3, glm::vec4(0), noise::Simplex::Noise4D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DGray(uint8_t* buffer, int size, const glm::vec4& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DBuffer(buffer, size, 3, pos, noise::Simplex::Noise4D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DGrayA(uint8_t* buffer, int size, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DBuffer(buffer, size, 4, glm::vec4(0), noise::Simplex::Noise4D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DGrayA(uint8_t* buffer, int size, const glm::vec4& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DBuffer(buffer, size, 4, pos, noise::Simplex::Noise4D, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DRGB(uint8_t* buffer, int size, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DChannel(buffer, size, 3, glm::vec4(0), octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DRGB(uint8_t* buffer, int size, const glm::vec4& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DChannel(buffer, size, 3, pos, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DRGBA(uint8_t* buffer, int size, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DChannel(buffer, size, 4, glm::vec4(0), octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DRGBA(uint8_t* buffer, int size, const glm::vec4& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
SeamlessNoise2DChannel(buffer, size, 4, pos, octaves, persistence, frequency, amplitude);
|
||||
}
|
||||
|
||||
static void SeamlessNoise2DChannel(uint8_t* buffer, int size, int components, const glm::vec4& pos, int octaves = 1, float persistence = 1.0f, float frequency = 1.0f, float amplitude = 1.0f) {
|
||||
uint8_t buffer_channel[size * size];
|
||||
for (int channel = 0; channel < components; ++channel) {
|
||||
SeamlessNoise2DBuffer(buffer_channel, size, 1, pos + glm::vec4(channel), noise::Simplex::Noise4D, octaves, persistence, frequency, amplitude);
|
||||
int index = 0;
|
||||
for (int x = 0; x < size; ++x) {
|
||||
for (int y = 0; y < size; ++y, ++index) {
|
||||
buffer[index*3+channel] = buffer_channel[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Func, class ... Args>
|
||||
static void SeamlessNoise2DBuffer(uint8_t* buffer, int size, int components, const glm::vec4& pos, Func&& func, Args&&... args) {
|
||||
// seamless noise: http://www.gamedev.net/blog/33/entry-2138456-seamless-noise/
|
||||
const float pi2 = 2.0f * glm::pi<float>();
|
||||
const float d = 1.0f / size;
|
||||
float s = 0.0f;
|
||||
for (int x = 0; x < size; x++, s+=d) {
|
||||
const float s_pi2 = s*pi2;
|
||||
const float nx = glm::cos(s_pi2);
|
||||
const float nz = glm::sin(s_pi2);
|
||||
float t = 0.0f;
|
||||
for (int y = 0; y < size; y++, t+=d) {
|
||||
const float t_pi2 = t*pi2;
|
||||
float ny = glm::cos(t_pi2);
|
||||
float nw = glm::sin(t_pi2);
|
||||
float noise = func(glm::vec4(nx,ny,nz,nw) + pos, std::forward<Args>(args)...);
|
||||
noise = (noise + 0.5f) * 1.0;
|
||||
noise = std::min(std::max(noise, 0.0f), 1.0f);
|
||||
unsigned char color = (unsigned char) (noise * 255.0f);
|
||||
int index = y * (size * components) + (x * components);
|
||||
const int fill_components = components == 4 ? 3 : components;
|
||||
for (int i = 0; i < fill_components; ++i) {
|
||||
buffer[index++] = color;
|
||||
}
|
||||
if (components == 4) {
|
||||
buffer[index] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
#include "WorldShapeNoise.h"
|
||||
|
||||
namespace noise {
|
||||
|
||||
WorldShapeNoise::WorldShapeNoise() :
|
||||
_sphere(1.0, 0.5, 0.0, 0.5),
|
||||
_shape(),
|
||||
|
||||
_elevationBase(anl::EFractalTypes::FBM, anl::GRADIENT, anl::QUINTIC, 6, 2, true),
|
||||
_elevationAutoCorrect(&_elevationBase, 0.0, 1.0),
|
||||
|
||||
_elevationTurbulence(anl::EFractalTypes::RIDGEDMULTI, anl::GRADIENT, anl::QUINTIC, 8, 1, true),
|
||||
_elevationTurbulenceAutoCorrect(&_elevationTurbulence, 0.0, 1.0),
|
||||
|
||||
_elevationTurbulenceTranslateDomain(&_elevationAutoCorrect, 0.0, &_elevationTurbulenceAutoCorrect, 0.0),
|
||||
_elevation(anl::MULTIPLY, &_elevationTurbulenceTranslateDomain, &_shape),
|
||||
|
||||
_groundBase()
|
||||
{
|
||||
_shape.setOperation(anl::EASEQUINTIC);
|
||||
_shape.setSource(&_sphere);
|
||||
|
||||
_air.setConstant(0.0);
|
||||
_soil.setConstant(1.0);
|
||||
|
||||
_groundBase.setLowSource(&_soil);
|
||||
_groundBase.setHighSource(&_air);
|
||||
_groundBase.setControlSource(&_elevation);
|
||||
_groundBase.setThreshold(0.5);
|
||||
}
|
||||
|
||||
void WorldShapeNoise::generateImage() {
|
||||
anl::CRGBACompositeChannels composite;
|
||||
|
||||
composite.setMode(anl::RGB);
|
||||
composite.setRedSource(&_shape);
|
||||
composite.setGreenSource(&_shape);
|
||||
composite.setBlueSource(&_shape);
|
||||
composite.setAlphaSource(1.0);
|
||||
|
||||
anl::TArray2D<TVec4D<float>> img(256, 256);
|
||||
|
||||
anl::SMappingRanges ranges;
|
||||
ranges.mapx0 = -1;
|
||||
ranges.mapy0 = -1;
|
||||
ranges.mapx1 = 1;
|
||||
ranges.mapy1 = 1;
|
||||
mapRGBA2D(anl::SEAMLESS_NONE, img ,composite ,ranges, 0);
|
||||
|
||||
//Just for debugging purpose
|
||||
saveRGBAArray((char*)"heightmap.tga", &img);
|
||||
Log::info("+++++++++++++++generateImage");
|
||||
}
|
||||
|
||||
void WorldShapeNoise::setSeed(long seed) {
|
||||
anl::CMWC4096 rnd;
|
||||
rnd.setSeed(seed);
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/Random.h"
|
||||
#include "core/Common.h"
|
||||
#include <anl_noise.h>
|
||||
#include <anl_rgba.h>
|
||||
#include <anl_imaging.h>
|
||||
#include <mapping.h>
|
||||
|
||||
namespace noise {
|
||||
|
||||
class WorldShapeNoise {
|
||||
private:
|
||||
anl::CImplicitSphere _sphere;
|
||||
anl::CImplicitMath _shape;
|
||||
|
||||
anl::CImplicitFractal _elevationBase;
|
||||
anl::CImplicitAutoCorrect _elevationAutoCorrect;
|
||||
|
||||
anl::CImplicitFractal _elevationTurbulence;
|
||||
anl::CImplicitAutoCorrect _elevationTurbulenceAutoCorrect;
|
||||
|
||||
anl::CImplicitTranslateDomain _elevationTurbulenceTranslateDomain;
|
||||
anl::CImplicitMath _elevation;
|
||||
|
||||
anl::CImplicitConstant _air;
|
||||
anl::CImplicitConstant _soil;
|
||||
|
||||
anl::CImplicitSelect _groundBase;
|
||||
|
||||
public:
|
||||
WorldShapeNoise();
|
||||
|
||||
double get(double x, double y, double z, double worldDimension = 128.0);
|
||||
|
||||
void generateImage();
|
||||
|
||||
void setSeed(long seed);
|
||||
};
|
||||
|
||||
inline double WorldShapeNoise::get(double x, double y, double z, double worldDimension) {
|
||||
const double scale = 1.0 / worldDimension;
|
||||
return _groundBase.get(x * scale, y * scale, z * scale);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
// stb_perlin.h - v0.2 - perlin noise
|
||||
// public domain single-file C implementation by Sean Barrett
|
||||
//
|
||||
// to create the implementation,
|
||||
// #define STB_PERLIN_IMPLEMENTATION
|
||||
// in *one* C/CPP file that includes this file.
|
||||
|
||||
|
||||
// Documentation:
|
||||
//
|
||||
// float stb_perlin_noise3( float x,
|
||||
// float y,
|
||||
// float z,
|
||||
// int x_wrap=0,
|
||||
// int y_wrap=0,
|
||||
// int z_wrap=0)
|
||||
//
|
||||
// This function computes a random value at the coordinate (x,y,z).
|
||||
// Adjacent random values are continuous but the noise fluctuates
|
||||
// its randomness with period 1, i.e. takes on wholly unrelated values
|
||||
// at integer points. Specifically, this implements Ken Perlin's
|
||||
// revised noise function from 2002.
|
||||
//
|
||||
// The "wrap" parameters can be used to create wraparound noise that
|
||||
// wraps at powers of two. The numbers MUST be powers of two. Specify
|
||||
// 0 to mean "don't care". (The noise always wraps every 256 due
|
||||
// details of the implementation, even if you ask for larger or no
|
||||
// wrapping.)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
|
||||
#else
|
||||
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
|
||||
#endif
|
||||
|
||||
#ifdef STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
#include <math.h> // floor()
|
||||
|
||||
// not same permutation table as Perlin's reference to avoid copyright issues;
|
||||
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
|
||||
// @OPTIMIZE: should this be unsigned char instead of int for cache?
|
||||
static int stb__perlin_randtab[512] =
|
||||
{
|
||||
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
|
||||
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
|
||||
// and a second copy so we don't need an extra mask or static initializer
|
||||
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
|
||||
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
};
|
||||
|
||||
static float stb__perlin_lerp(float a, float b, float t)
|
||||
{
|
||||
return a + (b-a) * t;
|
||||
}
|
||||
|
||||
// different grad function from Perlin's, but easy to modify to match reference
|
||||
static float stb__perlin_grad(int hash, float x, float y, float z)
|
||||
{
|
||||
static float basis[12][4] =
|
||||
{
|
||||
{ 1, 1, 0 },
|
||||
{ -1, 1, 0 },
|
||||
{ 1,-1, 0 },
|
||||
{ -1,-1, 0 },
|
||||
{ 1, 0, 1 },
|
||||
{ -1, 0, 1 },
|
||||
{ 1, 0,-1 },
|
||||
{ -1, 0,-1 },
|
||||
{ 0, 1, 1 },
|
||||
{ 0,-1, 1 },
|
||||
{ 0, 1,-1 },
|
||||
{ 0,-1,-1 },
|
||||
};
|
||||
|
||||
// perlin's gradient has 12 cases so some get used 1/16th of the time
|
||||
// and some 2/16ths. We reduce bias by changing those fractions
|
||||
// to 5/16ths and 6/16ths, and the same 4 cases get the extra weight.
|
||||
static unsigned char indices[64] =
|
||||
{
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
0,9,1,11,
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
};
|
||||
|
||||
// if you use reference permutation table, change 63 below to 15 to match reference
|
||||
float *grad = basis[indices[hash & 63]];
|
||||
return grad[0]*x + grad[1]*y + grad[2]*z;
|
||||
}
|
||||
|
||||
float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
float u,v,w;
|
||||
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||
float n00,n01,n10,n11;
|
||||
float n0,n1;
|
||||
|
||||
unsigned int x_mask = (x_wrap-1) & 255;
|
||||
unsigned int y_mask = (y_wrap-1) & 255;
|
||||
unsigned int z_mask = (z_wrap-1) & 255;
|
||||
int px = (int) floor(x);
|
||||
int py = (int) floor(y);
|
||||
int pz = (int) floor(z);
|
||||
int x0 = px & x_mask, x1 = (px+1) & x_mask;
|
||||
int y0 = py & y_mask, y1 = (py+1) & y_mask;
|
||||
int z0 = pz & z_mask, z1 = (pz+1) & z_mask;
|
||||
int r0,r1, r00,r01,r10,r11;
|
||||
|
||||
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||
|
||||
x -= px; u = stb__perlin_ease(x);
|
||||
y -= py; v = stb__perlin_ease(y);
|
||||
z -= pz; w = stb__perlin_ease(z);
|
||||
|
||||
r0 = stb__perlin_randtab[x0];
|
||||
r1 = stb__perlin_randtab[x1];
|
||||
|
||||
r00 = stb__perlin_randtab[r0+y0];
|
||||
r01 = stb__perlin_randtab[r0+y1];
|
||||
r10 = stb__perlin_randtab[r1+y0];
|
||||
r11 = stb__perlin_randtab[r1+y1];
|
||||
|
||||
n000 = stb__perlin_grad(stb__perlin_randtab[r00+z0], x , y , z );
|
||||
n001 = stb__perlin_grad(stb__perlin_randtab[r00+z1], x , y , z-1 );
|
||||
n010 = stb__perlin_grad(stb__perlin_randtab[r01+z0], x , y-1, z );
|
||||
n011 = stb__perlin_grad(stb__perlin_randtab[r01+z1], x , y-1, z-1 );
|
||||
n100 = stb__perlin_grad(stb__perlin_randtab[r10+z0], x-1, y , z );
|
||||
n101 = stb__perlin_grad(stb__perlin_randtab[r10+z1], x-1, y , z-1 );
|
||||
n110 = stb__perlin_grad(stb__perlin_randtab[r11+z0], x-1, y-1, z );
|
||||
n111 = stb__perlin_grad(stb__perlin_randtab[r11+z1], x-1, y-1, z-1 );
|
||||
|
||||
n00 = stb__perlin_lerp(n000,n001,w);
|
||||
n01 = stb__perlin_lerp(n010,n011,w);
|
||||
n10 = stb__perlin_lerp(n100,n101,w);
|
||||
n11 = stb__perlin_lerp(n110,n111,w);
|
||||
|
||||
n0 = stb__perlin_lerp(n00,n01,v);
|
||||
n1 = stb__perlin_lerp(n10,n11,v);
|
||||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
#endif // STB_PERLIN_IMPLEMENTATION
|
|
@ -1,21 +0,0 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "noise/AccidentalNoise.h"
|
||||
#include "NoiseTestHelper.h"
|
||||
|
||||
namespace noise {
|
||||
|
||||
TEST(AccidentalNoiseTest, testNoise) {
|
||||
AccidentalNoise noise;
|
||||
noise.setSeed(1L);
|
||||
const int worldHeight = 256;
|
||||
const int worldSize = 32;
|
||||
#if 0
|
||||
anl::CArray3Dd a(worldSize, worldHeight, worldSize);
|
||||
anl::CImplicitModuleBase* m = noise.get();
|
||||
anl::SMappingRanges ranges;
|
||||
anl::map3D(anl::SEAMLESS_NONE, a, *m, ranges);
|
||||
#endif
|
||||
printNoise(noise, worldSize, worldHeight, worldSize);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "noise/NoisePPNoise.h"
|
||||
#include "NoiseTestHelper.h"
|
||||
|
||||
namespace noise {
|
||||
|
||||
TEST(NoisePPNoiseTest, testNoise) {
|
||||
NoisePPNoise noise;
|
||||
noise.setSeed(1L);
|
||||
const int worldHeight = 32;
|
||||
const int worldSize = 32;
|
||||
noise.init();
|
||||
printNoise(noise, worldSize, worldHeight, worldSize);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/Log.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace noise {
|
||||
|
||||
template<class NOISE>
|
||||
inline void printNoise(NOISE& noise, float width, float height, float depth) {
|
||||
for (float y = 0; y < 32; ++y) {
|
||||
Log::info("y: %f", y);
|
||||
Log::info("------------");
|
||||
for (float z = depth-1; z >= 0; --z) {
|
||||
Log::info("%.3f: ", z);
|
||||
std::stringstream sb;
|
||||
for (float x = 0; x < width; ++x) {
|
||||
sb << noise.get(x, y, z, 256.0) << " ";
|
||||
}
|
||||
Log::info("%s", sb.str().c_str());
|
||||
}
|
||||
Log::info("------------");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "noise/PerlinNoise.h"
|
||||
#include "NoiseTestHelper.h"
|
||||
|
||||
namespace noise {
|
||||
|
||||
TEST(PerlinNoiseTest, testNoise) {
|
||||
PerlinNoise noise;
|
||||
noise.setSeed(1L);
|
||||
const int worldHeight = 16;
|
||||
const int worldSize = 16;
|
||||
printNoise(noise, worldSize, worldHeight, worldSize);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
#include "core/tests/AbstractTest.h"
|
||||
#include "noise/SimplexNoise.h"
|
||||
#include <glm/gtc/noise.hpp>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
namespace noise {
|
||||
|
||||
class SimplexNoiseTest: public core::AbstractTest {
|
||||
protected:
|
||||
const int components = 4;
|
||||
const int w = 256;
|
||||
const int h = 256;
|
||||
|
||||
bool WriteImage(const char* name, uint8_t* buffer) {
|
||||
return stbi_write_png(name, w, h, components, buffer, w * components) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SimplexNoiseTest, testLandscapeMountains) {
|
||||
uint8_t buffer[w * h * components];
|
||||
|
||||
for (int x = 0; x < w; ++x) {
|
||||
for (int y = 0; y < h; ++y) {
|
||||
const glm::vec2 pos(x, y);
|
||||
float landscapeNoise = noise::Simplex::Noise2D(pos, 4, 0.3f, 0.01f);
|
||||
ASSERT_LE(landscapeNoise, 1.0f)<< "Noise is bigger than 1.0: " << landscapeNoise;
|
||||
ASSERT_GE(landscapeNoise, -1.0f)<< "Noise is less than -1.0: " << landscapeNoise;
|
||||
float noiseNormalized = (landscapeNoise + 1.0f) * 0.5f;
|
||||
ASSERT_LE(noiseNormalized, 1.0f)<< "Noise is bigger than 1.0: " << noiseNormalized;
|
||||
ASSERT_GE(noiseNormalized, 0.0f)<< "Noise is less than 0.0: " << noiseNormalized;
|
||||
float mountainNoise = noise::Simplex::Noise2D(pos, 4, 0.3f, 0.0075f);
|
||||
float mountainNoiseNormalized = (mountainNoise + 1.0f) * 0.5f;
|
||||
float mountainMultiplier = mountainNoiseNormalized * 2.3f;
|
||||
float noiseHeight = glm::clamp(noiseNormalized * mountainMultiplier, 0.0f, 1.0f);
|
||||
unsigned char color = (unsigned char) (noiseHeight * 255.0f);
|
||||
ASSERT_LE(color, 255)<< "Color is bigger than 255: " << color;
|
||||
ASSERT_GE(color, 0)<< "Color is less than 0: " << color;
|
||||
int index = y * (w * components) + (x * components);
|
||||
const int n = components == 4 ? 3 : components;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
buffer[index++] = color;
|
||||
}
|
||||
if (components == 4)
|
||||
buffer[index] = 255;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(WriteImage("testNoiseLandscapeMountains.png", buffer));
|
||||
}
|
||||
|
||||
TEST_F(SimplexNoiseTest, test2DNoise) {
|
||||
uint8_t buffer[w * h * components];
|
||||
|
||||
for (int x = 0; x < w; ++x) {
|
||||
for (int y = 0; y < h; ++y) {
|
||||
const glm::vec2 pos(x, y);
|
||||
const float noise = Simplex::Noise2D(pos, 2, 1.0f, 0.5f, 1.5f);
|
||||
ASSERT_LE(noise, 1.0f)<< "Noise is bigger than 1.0: " << noise;
|
||||
ASSERT_GE(noise, -1.0f)<< "Noise is less than -1.0: " << noise;
|
||||
float normalized = glm::clamp(noise * 0.5f + 0.5f, 0.0f, 1.0f);
|
||||
ASSERT_LE(normalized, 1.0f)<< "Noise is bigger than 1.0: " << normalized;
|
||||
ASSERT_GE(normalized, 0.0f)<< "Noise is less than 0.0: " << normalized;
|
||||
unsigned char color = (unsigned char) (normalized * 255.0f);
|
||||
ASSERT_LE(color, 255)<< "Color is bigger than 255: " << color;
|
||||
ASSERT_GE(color, 0)<< "Color is less than 0: " << color;
|
||||
int index = y * (w * components) + (x * components);
|
||||
const int n = components == 4 ? 3 : components;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
buffer[index++] = color;
|
||||
}
|
||||
if (components == 4)
|
||||
buffer[index] = 255;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(WriteImage("testNoise2d.png", buffer));
|
||||
}
|
||||
|
||||
TEST_F(SimplexNoiseTest, test2DNoiseGray) {
|
||||
const int width = 100;
|
||||
const int height = 100;
|
||||
const int components = 3;
|
||||
uint8_t buffer[width * height * components];
|
||||
Simplex::Noise2DGray(buffer, width, height, 1, 1.0, 1.0, 1.0);
|
||||
ASSERT_TRUE(stbi_write_png("testNoiseGray.png", width, height, components, buffer, width * components) != 0);
|
||||
}
|
||||
|
||||
TEST_F(SimplexNoiseTest, test2DNoiseColorMap) {
|
||||
const int width = 256;
|
||||
const int height = 256;
|
||||
const int components = 3;
|
||||
uint8_t buffer[width * height * components];
|
||||
noise::Simplex::SeamlessNoise2DRGB(buffer, width, 3, 0.3f, 0.7f);
|
||||
ASSERT_TRUE(stbi_write_png("testNoiseColorMap.png", width, height, components, buffer, width * components) != 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
fips_begin_module(dbpost)
|
||||
fips_begin_module(persistence)
|
||||
fips_files(
|
||||
PQConnect.cpp PQConnect.h
|
||||
PQStore.cpp PQStore.h
|
||||
StoreInterface.cpp StoreInterface.h
|
||||
Connection.cpp Connection.h
|
||||
Store.cpp Store.h
|
||||
PeristenceModel.cpp PeristenceModel.h
|
||||
)
|
||||
set(PostgreSQL_ADDITIONAL_VERSIONS "9.3" "9.4.1")
|
||||
set(PostgreSQL_ADDITIONAL_SEARCH_PATHS "/usr/include/postgresql/9.3/server" "/usr/include/postgresql/9.4/server")
|
||||
|
@ -11,10 +11,5 @@ fips_begin_module(dbpost)
|
|||
fips_deps(core ${PostgreSQL_LIBRARIES})
|
||||
fips_end_module()
|
||||
|
||||
gtest_begin(dbpost)
|
||||
fips_dir(tests)
|
||||
fips_files(
|
||||
PQStoreTest.cpp
|
||||
)
|
||||
fips_deps(dbpost)
|
||||
gtest_end()
|
||||
gtest_suite_files(tests tests/StoreTest.cpp)
|
||||
gtest_suite_deps(tests persistence)
|
|
@ -0,0 +1,66 @@
|
|||
#include "Connection.h"
|
||||
#include "core/Log.h"
|
||||
|
||||
namespace persistence {
|
||||
|
||||
Connection::Connection() :
|
||||
_pgConnection(nullptr), _port(0) {
|
||||
}
|
||||
|
||||
Connection::~Connection() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
void Connection::setLoginData(const std::string& username, const std::string& password) {
|
||||
_password = password;
|
||||
_user = username;
|
||||
}
|
||||
|
||||
void Connection::changeDb(const std::string& dbname) {
|
||||
_dbname = dbname;
|
||||
}
|
||||
|
||||
void Connection::changeHost(const std::string& host) {
|
||||
_host = host;
|
||||
}
|
||||
|
||||
void Connection::changePort(uint16_t port) {
|
||||
_port = port;
|
||||
}
|
||||
|
||||
inline std::string Connection::escape(const std::string& value) const {
|
||||
// TODO: escape ' inside the value
|
||||
return "'" + value + "'";
|
||||
}
|
||||
|
||||
bool Connection::connect() {
|
||||
std::string conninfo = "connect_timeout='2'";
|
||||
|
||||
if (!_host.empty())
|
||||
conninfo += " host=" + escape(_host);
|
||||
if (!_dbname.empty())
|
||||
conninfo += " dbname=" + escape(_dbname);
|
||||
if (!_user.empty())
|
||||
conninfo += " user=" + escape(_user);
|
||||
if (!_password.empty())
|
||||
conninfo += " password=" + escape(_password);
|
||||
if (_port > 0)
|
||||
conninfo += " port=" + escape(std::to_string(_port));
|
||||
|
||||
_pgConnection = PQconnectdb(conninfo.c_str());
|
||||
|
||||
if (PQstatus(_pgConnection) != CONNECTION_OK) {
|
||||
Log::error("Connection to database failed: %s", PQerrorMessage(_pgConnection));
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Connection::disconnect() {
|
||||
PQfinish(_pgConnection);
|
||||
_pgConnection = nullptr;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,29 +3,39 @@
|
|||
#include <string>
|
||||
#include <postgresql/libpq-fe.h>
|
||||
|
||||
namespace dbpost {
|
||||
namespace persistence {
|
||||
|
||||
class PQConnect {
|
||||
class Connection {
|
||||
private:
|
||||
PGconn* _pgConnection;
|
||||
std::string _host;
|
||||
std::string _port;
|
||||
std::string _dbname;
|
||||
std::string _user;
|
||||
std::string _password;
|
||||
uint16_t _port;
|
||||
|
||||
std::string escape(const std::string& value) const;
|
||||
public:
|
||||
PQConnect();
|
||||
~PQConnect();
|
||||
Connection();
|
||||
|
||||
~Connection();
|
||||
|
||||
void setLoginData(const std::string& username, const std::string& password);
|
||||
|
||||
void changeHost(const std::string& host);
|
||||
void changePort(const std::string& port);
|
||||
|
||||
void changePort(uint16_t port);
|
||||
|
||||
void changeDb(const std::string& dbname);
|
||||
|
||||
void disconnect();
|
||||
int connect();
|
||||
|
||||
bool connect();
|
||||
|
||||
PGconn* connection() const;
|
||||
};
|
||||
|
||||
inline PGconn* PQConnect::connection() const {
|
||||
inline PGconn* Connection::connection() const {
|
||||
return _pgConnection;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#include "PeristenceModel.h"
|
||||
|
||||
namespace persistence {
|
||||
|
||||
PeristenceModel::PeristenceModel(const std::string& tableName) :
|
||||
_tableName(tableName) {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace persistence {
|
||||
|
||||
typedef std::unordered_map<std::string, std::string> Fields;
|
||||
|
||||
class PeristenceModel {
|
||||
protected:
|
||||
const std::string _tableName;
|
||||
public:
|
||||
PeristenceModel(const std::string& tableName);
|
||||
|
||||
virtual ~PeristenceModel() {
|
||||
}
|
||||
|
||||
virtual std::string getCreate() const = 0;
|
||||
|
||||
virtual const std::string& getTableName() const {
|
||||
return _tableName;
|
||||
}
|
||||
|
||||
virtual Fields getFields() const = 0;
|
||||
|
||||
virtual void update(const std::string& fieldName,const std::string& value) const = 0;
|
||||
|
||||
virtual bool isSerial(const std::string& fieldname) const = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,31 +1,27 @@
|
|||
#include "PQStore.h"
|
||||
#include "StoreInterface.h"
|
||||
#include "Store.h"
|
||||
#include "core/Log.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace dbpost {
|
||||
namespace persistence {
|
||||
|
||||
PQStore::PQStore(PQConnect* conn) :
|
||||
Store::Store(Connection* conn) :
|
||||
_connection(conn), _usable(true), _res(nullptr), _lastState(PGRES_EMPTY_QUERY), _affectedRows(0) {
|
||||
}
|
||||
|
||||
void PQStore::storeModel(StoreInterface& model) {
|
||||
bool Store::storeModel(PeristenceModel& model) {
|
||||
const std::string& insertSql = sqlBuilder(model, false);
|
||||
|
||||
//trBegin();
|
||||
query(insertSql);
|
||||
//trEnd();
|
||||
return query(insertSql);
|
||||
}
|
||||
|
||||
void PQStore::createNeeds(const StoreInterface& model) {
|
||||
bool Store::createNeeds(const PeristenceModel& model) {
|
||||
const std::string& crSql = model.getCreate();
|
||||
query(crSql);
|
||||
return query(crSql);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> PQStore::loadModel(const StoreInterface& model) {
|
||||
KeyValueMap Store::loadModel(const PeristenceModel& model) {
|
||||
const std::string& loadSql = sqlLoadBuilder(model, false);
|
||||
Log::trace("sql used %s", loadSql.c_str());
|
||||
std::unordered_map<std::string, std::string> dbResult;
|
||||
KeyValueMap dbResult;
|
||||
if (query(loadSql) && _affectedRows == 1) {
|
||||
const int nFields = PQnfields(_res);
|
||||
for (int i = 0; i < nFields; ++i) {
|
||||
|
@ -40,13 +36,13 @@ std::unordered_map<std::string, std::string> PQStore::loadModel(const StoreInter
|
|||
return dbResult;
|
||||
}
|
||||
|
||||
std::string PQStore::sqlBuilder(const StoreInterface& model, bool update) const {
|
||||
std::string Store::sqlBuilder(const PeristenceModel& model, bool update) const {
|
||||
std::stringstream insertSql;
|
||||
insertSql << "INSERT INTO " << model.getTableName() << " ";
|
||||
std::stringstream fieldKeys;
|
||||
std::stringstream valueKeys;
|
||||
|
||||
const std::unordered_map<std::string, std::string>& fields = model.getFields();
|
||||
const Fields& fields = model.getFields();
|
||||
|
||||
std::string add = "";
|
||||
for (auto p = fields.begin(); p != fields.end(); ++p) {
|
||||
|
@ -65,11 +61,11 @@ std::string PQStore::sqlBuilder(const StoreInterface& model, bool update) const
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string PQStore::sqlLoadBuilder(const StoreInterface& model, bool update) const {
|
||||
std::string Store::sqlLoadBuilder(const PeristenceModel& model, bool update) const {
|
||||
std::string loadSql = "SELECT * FROM " + model.getTableName() + " ";
|
||||
std::string fieldKeys = "";
|
||||
|
||||
const std::unordered_map<std::string, std::string>& fields = model.getFields();
|
||||
const Fields& fields = model.getFields();
|
||||
|
||||
std::string add = "";
|
||||
for (auto p = fields.begin(); p != fields.end(); ++p) {
|
||||
|
@ -85,7 +81,7 @@ std::string PQStore::sqlLoadBuilder(const StoreInterface& model, bool update) co
|
|||
return loadSql;
|
||||
}
|
||||
|
||||
void PQStore::trBegin() {
|
||||
void Store::trBegin() {
|
||||
if (!_usable)
|
||||
return;
|
||||
|
||||
|
@ -96,7 +92,7 @@ void PQStore::trBegin() {
|
|||
}
|
||||
}
|
||||
|
||||
void PQStore::trEnd() {
|
||||
void Store::trEnd() {
|
||||
if (!_usable)
|
||||
return;
|
||||
|
||||
|
@ -107,17 +103,16 @@ void PQStore::trEnd() {
|
|||
}
|
||||
}
|
||||
|
||||
bool PQStore::checkLastResult() {
|
||||
bool Store::checkLastResult() {
|
||||
_affectedRows = 0;
|
||||
Log::info("get result");
|
||||
if (_res != nullptr)
|
||||
_lastState = PQresultStatus(_res);
|
||||
else
|
||||
if (_res == nullptr)
|
||||
return false;
|
||||
|
||||
_lastState = PQresultStatus(_res);
|
||||
|
||||
if ((_lastState == PGRES_EMPTY_QUERY) || (_lastState == PGRES_BAD_RESPONSE) || (_lastState == PGRES_FATAL_ERROR)) {
|
||||
PQclear(_res);
|
||||
char* msg = PQerrorMessage(_connection->connection());
|
||||
const char* msg = PQerrorMessage(_connection->connection());
|
||||
_lastErrorMsg = std::string(msg);
|
||||
|
||||
Log::error("Failed to execute sql: %s ", _lastErrorMsg.c_str());
|
||||
|
@ -133,7 +128,7 @@ bool PQStore::checkLastResult() {
|
|||
|
||||
if (_lastState == PGRES_TUPLES_OK) {
|
||||
_affectedRows = PQntuples(_res);
|
||||
Log::info("Data read %i", _affectedRows);
|
||||
Log::trace("Affected rows on read %i", _affectedRows);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -142,7 +137,7 @@ bool PQStore::checkLastResult() {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool PQStore::query(const std::string& query) {
|
||||
bool Store::query(const std::string& query) {
|
||||
if (_usable) {
|
||||
Log::trace("SEND: %s", query.c_str());
|
||||
_res = PQexec(_connection->connection(), query.c_str());
|
||||
|
@ -152,7 +147,7 @@ bool PQStore::query(const std::string& query) {
|
|||
return false;
|
||||
}
|
||||
|
||||
PQStore::~PQStore() {
|
||||
Store::~Store() {
|
||||
// TODO: assigning a nullptr is not possible for a reference
|
||||
//_connection = nullptr;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include "Connection.h"
|
||||
#include "PeristenceModel.h"
|
||||
#include <unordered_map>
|
||||
#include <postgresql/libpq-fe.h>
|
||||
#include "core/NonCopyable.h"
|
||||
|
||||
namespace persistence {
|
||||
|
||||
typedef std::unordered_map<std::string, std::string> KeyValueMap;
|
||||
typedef std::pair<std::string, std::string> KeyValuePair;
|
||||
|
||||
class Store : public core::NonCopyable {
|
||||
private:
|
||||
Connection* _connection;
|
||||
bool _usable;
|
||||
PGresult* _res;
|
||||
std::string _lastErrorMsg;
|
||||
ExecStatusType _lastState;
|
||||
int _affectedRows;
|
||||
|
||||
std::string sqlBuilder(const PeristenceModel& model, bool update) const;
|
||||
|
||||
std::string sqlLoadBuilder(const PeristenceModel& model, bool update) const;
|
||||
public:
|
||||
Store(Connection* conn);
|
||||
~Store();
|
||||
|
||||
bool query(const std::string& query);
|
||||
|
||||
void trBegin();
|
||||
|
||||
void trEnd();
|
||||
|
||||
bool checkLastResult();
|
||||
|
||||
bool storeModel(PeristenceModel& model);
|
||||
|
||||
bool createNeeds(const PeristenceModel& model);
|
||||
|
||||
KeyValueMap loadModel(const PeristenceModel& model);
|
||||
|
||||
PGresult* result() const;
|
||||
};
|
||||
|
||||
inline PGresult* Store::result() const {
|
||||
return _res;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#include "core/tests/AbstractTest.h"
|
||||
#include "persistence/Store.h"
|
||||
|
||||
namespace persistence {
|
||||
|
||||
class StoreTest : public core::AbstractTest {
|
||||
};
|
||||
|
||||
TEST(StoreTest, testFoo) {
|
||||
}
|
||||
|
||||
}
|
|
@ -12,13 +12,5 @@ fips_begin_module(ui)
|
|||
fips_deps(core io video turbobadger ${SDL2_LIBRARIES} ${OPENGL_LIBRARIES})
|
||||
fips_end_module()
|
||||
|
||||
gtest_begin(ui)
|
||||
fips_dir(tests)
|
||||
fips_files(
|
||||
KeybindingParserTest.cpp
|
||||
)
|
||||
find_package(OpenGL)
|
||||
find_package(SDL2 REQUIRED)
|
||||
fips_include_directories(. ${SDL2_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR})
|
||||
fips_deps(core io video turbobadger ui ${SDL2_LIBRARIES} ${OPENGL_LIBRARIES})
|
||||
gtest_end()
|
||||
gtest_suite_files(tests tests/KeybindingParserTest.cpp)
|
||||
gtest_suite_deps(tests ui)
|
||||
|
|
|
@ -294,7 +294,7 @@ core::AppState UIApp::onInit() {
|
|||
return core::AppState::Cleanup;
|
||||
}
|
||||
|
||||
font->RenderGlyphs(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~•·åäöÅÄÖ");
|
||||
font->RenderGlyphs(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~•·åäöÅÄÖ");
|
||||
_root.SetRect(tb::TBRect(0, 0, _width, _height));
|
||||
_root.SetSkinBg(TBIDC("background"));
|
||||
|
||||
|
|
|
@ -4,21 +4,21 @@ namespace util {
|
|||
|
||||
class IProgressMonitor {
|
||||
protected:
|
||||
int _max;
|
||||
int _steps;
|
||||
long _max;
|
||||
long _steps;
|
||||
public:
|
||||
IProgressMonitor(int max = 100) :
|
||||
_max(max), _steps(0) {
|
||||
IProgressMonitor(long max = 100l):
|
||||
_max(max), _steps(0l) {
|
||||
}
|
||||
|
||||
virtual ~IProgressMonitor() {
|
||||
}
|
||||
|
||||
void init(int max) {
|
||||
void init(long max) {
|
||||
_max = max;
|
||||
}
|
||||
|
||||
virtual void step(int steps = 1) {
|
||||
virtual void step(long steps = 1l) {
|
||||
_steps += steps;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "core/Log.h"
|
||||
#include "core/App.h"
|
||||
#include "io/Filesystem.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
namespace video {
|
||||
|
|
|
@ -11,12 +11,5 @@ fips_begin_module(voxel)
|
|||
fips_deps(core io noise zlib ${SDL2_LIBRARIES})
|
||||
fips_end_module()
|
||||
|
||||
gtest_begin(voxel)
|
||||
fips_dir(tests)
|
||||
fips_files(
|
||||
WorldTest.cpp
|
||||
)
|
||||
find_package(SDL2 REQUIRED)
|
||||
include_directories(${SDL2_INCLUDE_DIRS})
|
||||
fips_deps(voxel ${SDL2_LIBRARIES})
|
||||
gtest_end()
|
||||
gtest_suite_files(tests tests/WorldTest.cpp)
|
||||
gtest_suite_deps(tests voxel)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <PolyVox/MaterialDensityPair.h>
|
||||
#include <PolyVox/Mesh.h>
|
||||
#include <PolyVox/Vertex.h>
|
||||
#include <PolyVox/CubicSurfaceExtractor.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "io/File.h"
|
||||
#include "Raycast.h"
|
||||
#include "Voxel.h"
|
||||
#include "core/Random.h"
|
||||
#include "noise/SimplexNoise.h"
|
||||
#include <PolyVox/AStarPathfinder.h>
|
||||
#include <PolyVox/CubicSurfaceExtractor.h>
|
||||
#include <PolyVox/RawVolume.h>
|
||||
|
@ -21,21 +23,30 @@ namespace voxel {
|
|||
#define MAX_HEIGHT 256
|
||||
#define WORLD_FILE_VERSION 1
|
||||
|
||||
void World::Pager::pageIn(const PolyVox::Region& region, WorldData::Chunk* chunk) {
|
||||
if (!_world.load(region, chunk)) {
|
||||
_world.create(region, chunk);
|
||||
_world.save(region, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
void World::Pager::pageOut(const PolyVox::Region& region, WorldData::Chunk* chunk) {
|
||||
_world.save(region, chunk);
|
||||
}
|
||||
|
||||
// http://code.google.com/p/fortressoverseer/source/browse/Overseer/PolyVoxGenerator.cpp
|
||||
World::World() :
|
||||
_volumeData(nullptr), _seed(0), _size(0), _noise(), _worldShapeNoise(), _threadPool(1), _rwLock("World") {
|
||||
_chunkSize = core::Var::get("cl_chunksize", "16", core::CV_READONLY);
|
||||
_pager(*this), _seed(0), _threadPool(1), _rwLock("World") {
|
||||
_chunkSize = core::Var::get("cl_chunksize", "64", core::CV_READONLY);
|
||||
_volumeData = new WorldData(&_pager, 256 * 1024 * 1024, _chunkSize->intVal());
|
||||
}
|
||||
|
||||
World::~World() {
|
||||
if (_volumeData)
|
||||
delete _volumeData;
|
||||
_volumeData = nullptr;
|
||||
}
|
||||
|
||||
int World::internalFindFloor(int x, int z) const {
|
||||
for (int i = MAX_HEIGHT - 1; i >= 0; i--) {
|
||||
const int material = getMaterial(x, i, z);
|
||||
int World::findChunkFloor(int chunkSize, WorldData::Chunk* chunk, int x, int z) {
|
||||
for (int i = chunkSize - 1; i >= 0; i--) {
|
||||
const int material = chunk->getVoxel(x, i, z).getMaterial();
|
||||
if (material != AIR && material != CLOUDS) {
|
||||
return i + 1;
|
||||
}
|
||||
|
@ -43,25 +54,16 @@ int World::internalFindFloor(int x, int z) const {
|
|||
return -1;
|
||||
}
|
||||
|
||||
glm::ivec3 World::internalRandomPos(int border) const {
|
||||
const glm::ivec2& pos = randomPosWithoutHeight(border);
|
||||
const int y = internalFindFloor(pos.x, pos.y);
|
||||
return glm::ivec3(pos.x, y, pos.y);
|
||||
}
|
||||
|
||||
glm::ivec2 World::randomPosWithoutHeight(int border) const {
|
||||
if (_size <= 2 * border) {
|
||||
Log::warn("Border %i exceeds size %i", border, _size);
|
||||
return glm::ivec2(0);
|
||||
}
|
||||
std::uniform_int_distribution<int> distribution(border, _size - border);
|
||||
const int x = distribution(_engine);
|
||||
const int z = distribution(_engine);
|
||||
glm::ivec2 World::randomPosWithoutHeight(const PolyVox::Region& region) {
|
||||
std::uniform_int_distribution<int> distributionX(region.getLowerX(), region.getUpperX());
|
||||
std::uniform_int_distribution<int> distributionZ(region.getLowerZ(), region.getUpperZ());
|
||||
const int x = distributionX(_engine);
|
||||
const int z = distributionZ(_engine);
|
||||
return glm::ivec2(x, z);
|
||||
}
|
||||
|
||||
glm::ivec3 World::randomPos(int border) const {
|
||||
const glm::ivec2& pos = randomPosWithoutHeight(border);
|
||||
glm::ivec3 World::randomPos() const {
|
||||
const glm::ivec2 pos(0, 0);
|
||||
const int y = findFloor(pos.x, pos.y);
|
||||
return glm::ivec3(pos.x, y, pos.y);
|
||||
}
|
||||
|
@ -70,15 +72,10 @@ glm::ivec3 World::randomPos(int border) const {
|
|||
// The surface extractor outputs the mesh in an efficient compressed format which
|
||||
// is not directly suitable for rendering.
|
||||
void World::scheduleMeshExtraction(const glm::ivec2& p) {
|
||||
if (p.x < 0 || p.y < 0 || p.x >= _size || p.y >= _size) {
|
||||
Log::debug("skip mesh extraction for %i:%i (%i)", p.x, p.y, _size);
|
||||
return;
|
||||
}
|
||||
|
||||
const int size = _chunkSize->intVal();
|
||||
const glm::ivec2& pos = getGridPos(p);
|
||||
if (_meshesExtracted.find(pos) != _meshesExtracted.end()) {
|
||||
Log::debug("mesh is already extracted for %i:%i (%i)", p.x, p.y, _size);
|
||||
Log::debug("mesh is already extracted for %i:%i", p.x, p.y);
|
||||
return;
|
||||
}
|
||||
_meshesExtracted.insert(pos);
|
||||
|
@ -91,8 +88,9 @@ void World::scheduleMeshExtraction(const glm::ivec2& p) {
|
|||
const PolyVox::Region region(mins, maxs);
|
||||
DecodedMeshData data;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
data.mesh = PolyVox::decodeMesh(PolyVox::extractCubicMesh(_volumeData, region));
|
||||
locked([&] () {
|
||||
data.mesh = PolyVox::decodeMesh(PolyVox::extractCubicMesh(_volumeData, region));
|
||||
});
|
||||
}
|
||||
|
||||
data.translation = pos;
|
||||
|
@ -102,8 +100,13 @@ void World::scheduleMeshExtraction(const glm::ivec2& p) {
|
|||
}
|
||||
|
||||
int World::findFloor(int x, int z) const {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
return internalFindFloor(x, z);
|
||||
for (int i = MAX_HEIGHT - 1; i >= 0; i--) {
|
||||
const int material = getMaterial(x, i, z);
|
||||
if (material != AIR && material != CLOUDS) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void World::allowReExtraction(const glm::ivec2& pos) {
|
||||
|
@ -111,196 +114,210 @@ void World::allowReExtraction(const glm::ivec2& pos) {
|
|||
}
|
||||
|
||||
World::Result World::raycast(const glm::vec3& start, const glm::vec3& end, voxel::Raycast& raycast) {
|
||||
if (_volumeData == nullptr)
|
||||
return World::FAILED;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
PolyVox::RaycastResult result = PolyVox::raycastWithEndpoints(_volumeData, PolyVox::Vector3DFloat(start.x, start.y, start.z),
|
||||
PolyVox::Vector3DFloat(end.x, end.y, end.z), raycast);
|
||||
if (result == PolyVox::RaycastResults::Completed)
|
||||
return World::COMPLETED;
|
||||
return World::INTERUPTED;
|
||||
return locked([&] () {
|
||||
PolyVox::RaycastResult result = PolyVox::raycastWithEndpoints(_volumeData, PolyVox::Vector3DFloat(start.x, start.y, start.z),
|
||||
PolyVox::Vector3DFloat(end.x, end.y, end.z), raycast);
|
||||
if (result == PolyVox::RaycastResults::Completed)
|
||||
return World::COMPLETED;
|
||||
return World::INTERUPTED;
|
||||
});
|
||||
}
|
||||
|
||||
bool World::findPath(const PolyVox::Vector3DInt32& start, const PolyVox::Vector3DInt32& end,
|
||||
std::list<PolyVox::Vector3DInt32>& listResult) {
|
||||
if (_volumeData == nullptr)
|
||||
return false;
|
||||
|
||||
static auto f = [] (const voxel::WorldData* volData, const PolyVox::Vector3DInt32& v3dPos) {
|
||||
voxel::Voxel voxel = volData->getVoxel(v3dPos);
|
||||
return voxel.getDensity() != 0;
|
||||
};
|
||||
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
const PolyVox::AStarPathfinderParams<voxel::WorldData> params(_volumeData, start, end, &listResult, 1.0f, 10000,
|
||||
PolyVox::TwentySixConnected, std::bind(f, std::placeholders::_1, std::placeholders::_2));
|
||||
PolyVox::AStarPathfinder<voxel::WorldData> pf(params);
|
||||
// TODO: move into threadpool
|
||||
pf.execute();
|
||||
locked([&] () {
|
||||
const PolyVox::AStarPathfinderParams<voxel::WorldData> params(_volumeData, start, end, &listResult, 1.0f, 10000,
|
||||
PolyVox::TwentySixConnected, std::bind(f, std::placeholders::_1, std::placeholders::_2));
|
||||
PolyVox::AStarPathfinder<voxel::WorldData> pf(params);
|
||||
// TODO: move into threadpool
|
||||
pf.execute();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
void World::destroy() {
|
||||
if (!_volumeData)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (!_volumeData)
|
||||
return;
|
||||
Log::info("flush the world");
|
||||
delete _volumeData;
|
||||
_volumeData = nullptr;
|
||||
locked([this] () {
|
||||
_volumeData->flushAll();
|
||||
_seed = 0l;
|
||||
Log::info("flush the world");
|
||||
});
|
||||
}
|
||||
|
||||
void World::createCirclePlane(const glm::ivec3& center, int width, int depth, double radius, const Voxel& voxel) {
|
||||
const double xRadius = (width - 1) / 2.0;
|
||||
const double zRadius = (depth - 1) / 2.0;
|
||||
void World::createCirclePlane(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& center, int width, int depth, double radius, const Voxel& voxel) {
|
||||
const int xRadius = width / 2;
|
||||
const int zRadius = depth / 2;
|
||||
const double minRadius = std::min(xRadius, zRadius);
|
||||
const double xRatio = xRadius / (float) minRadius;
|
||||
const double zRatio = zRadius / (float) minRadius;
|
||||
const double ratioX = xRadius / minRadius;
|
||||
const double ratioZ = zRadius / minRadius;
|
||||
|
||||
for (double z = -zRadius; z <= zRadius; ++z) {
|
||||
for (double x = -xRadius; x <= xRadius; ++x) {
|
||||
const double xP = x / xRatio;
|
||||
const double zP = z / zRatio;
|
||||
const double distance = sqrt(pow(xP, 2) + pow(zP, 2));
|
||||
if (distance < radius) {
|
||||
if (_volumeData->getEnclosingRegion().containsPoint(center.x + x, center.y, center.z + z))
|
||||
_volumeData->setVoxel(center.x + x, center.y, center.z + z, voxel);
|
||||
for (int z = -zRadius; z <= zRadius; ++z) {
|
||||
for (int x = -xRadius; x <= xRadius; ++x) {
|
||||
const double distance = glm::sqrt(glm::pow(x / ratioX, 2.0) + glm::pow(z / ratioZ, 2.0));
|
||||
if (distance > radius) {
|
||||
continue;
|
||||
}
|
||||
chunk->setVoxel(center.x + x, center.y, center.z + z, voxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void World::createCube(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel) {
|
||||
const int w = width / 2;
|
||||
const int h = height / 2;
|
||||
const int d = depth / 2;
|
||||
for (int x = -w; x < width - w; ++x) {
|
||||
for (int y = -h; y < height - h; ++y) {
|
||||
for (int z = -d; z < depth - d; ++z) {
|
||||
chunk->setVoxel(pos.x + x, pos.y + y, pos.z + z, voxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void World::createCube(const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int z = 0; z < depth; ++z) {
|
||||
if (_volumeData->getEnclosingRegion().containsPoint(pos.x + x, pos.y + y, pos.z + z)) {
|
||||
_volumeData->setVoxel(pos.x + x, pos.y + y, pos.z + z, voxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void World::createPlane(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int depth, const Voxel& voxel) {
|
||||
createCube(region, chunk, pos, width, 1, depth, voxel);
|
||||
}
|
||||
|
||||
void World::createPlane(const glm::ivec3& pos, int width, int depth, const Voxel& voxel) {
|
||||
createCube(pos, width, 1, depth, voxel);
|
||||
}
|
||||
|
||||
void World::createEllipse(const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel) {
|
||||
const double heightRadius = (height - 1.0) / 2.0;
|
||||
void World::createEllipse(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel) {
|
||||
const int heightLow = height / 2;
|
||||
const int heightHigh = height - heightLow;
|
||||
const double minDimension = std::min(width, depth);
|
||||
const double adjustedMinRadius = (minDimension - 1.0) / 2.0;
|
||||
const double heightFactor = heightRadius / adjustedMinRadius;
|
||||
for (double y = -heightRadius; y <= heightRadius; ++y) {
|
||||
const double adjustedHeight = abs(y / heightFactor);
|
||||
const double circleRadius = sqrt(pow(adjustedMinRadius + 0.5, 2.0) - pow(adjustedHeight, 2.0));
|
||||
const double adjustedMinRadius = minDimension / 2.0;
|
||||
const double heightFactor = heightLow / adjustedMinRadius;
|
||||
for (int y = -heightLow; y <= heightHigh; ++y) {
|
||||
const double percent = glm::abs(y / heightFactor);
|
||||
const double circleRadius = glm::pow(adjustedMinRadius + 0.5, 2.0) - glm::pow(percent, 2.0);
|
||||
const glm::ivec3 planePos(pos.x, pos.y + y, pos.z);
|
||||
createCirclePlane(planePos, width, depth, circleRadius, voxel);
|
||||
createCirclePlane(region, chunk, planePos, width, depth, circleRadius, voxel);
|
||||
}
|
||||
}
|
||||
|
||||
void World::createCone(const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel) {
|
||||
const double heightRadius = height - 0.5;
|
||||
void World::createCone(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel) {
|
||||
const int heightLow = height / 2;
|
||||
const int heightHigh = height - heightLow;
|
||||
const double minDimension = std::min(width, depth);
|
||||
const double minRadius = minDimension / 2.0;
|
||||
for (double y = 0.5; y <= heightRadius; y++) {
|
||||
const double percent = 1 - (y / height);
|
||||
const double circleRadius = percent * minRadius;
|
||||
for (int y = -heightLow; y <= heightHigh; ++y) {
|
||||
const double percent = 1.0 - ((y + heightLow) / double(height));
|
||||
const double circleRadius = glm::pow(percent * minRadius, 2.0);
|
||||
const glm::ivec3 planePos(pos.x, pos.y + y, pos.z);
|
||||
createCirclePlane(planePos, width, depth, circleRadius, voxel);
|
||||
createCirclePlane(region, chunk, planePos, width, depth, circleRadius, voxel);
|
||||
}
|
||||
}
|
||||
|
||||
void World::createDome(const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel) {
|
||||
// TODO:
|
||||
void World::createDome(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel) {
|
||||
const int heightLow = height / 2;
|
||||
const int heightHigh = height - heightLow;
|
||||
const double minDimension = std::min(width, depth);
|
||||
const double minRadius = minDimension / 2.0;
|
||||
const double heightFactor = height / (minDimension - 1.0) / 2.0;
|
||||
for (int y = -heightLow; y <= heightHigh; ++y) {
|
||||
const double percent = glm::abs((y + heightLow) / heightFactor);
|
||||
const double circleRadius = glm::pow(minRadius, 2.0) - glm::pow(percent, 2.0);
|
||||
const glm::ivec3 planePos(pos.x, pos.y + y, pos.z);
|
||||
createCirclePlane(region, chunk, planePos, width, depth, circleRadius, voxel);
|
||||
}
|
||||
}
|
||||
|
||||
void World::addTree(const glm::ivec3& pos, TreeType type, int trunkHeight) {
|
||||
void World::addTree(int chunkSize, const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, TreeType type, int trunkHeight, int trunkWidth, int width, int depth, int height) {
|
||||
const int top = (int) pos.y + trunkHeight;
|
||||
const int sizeX = _volumeData->getWidth();
|
||||
const int sizeY = _volumeData->getDepth();
|
||||
const int sizeZ = _volumeData->getHeight();
|
||||
|
||||
const Voxel voxel(TRUNK, Voxel::getMaxDensity());
|
||||
|
||||
Log::trace("generate tree at %i:%i:%i", pos.x, pos.y, pos.z);
|
||||
|
||||
for (int y = pos.y; y < top; ++y) {
|
||||
const int width = std::max(1, 3 - (y - pos.y));
|
||||
for (int x = pos.x - width; x < pos.x + width; ++x) {
|
||||
for (int z = pos.z - width; z < pos.z + width; ++z) {
|
||||
if ((x >= pos.x + 1 || x < pos.x - 1) && (z >= pos.z + 1 || z < pos.z - 1))
|
||||
const int trunkWidthY = trunkWidth + std::max(0, 2 - (y - pos.y));
|
||||
for (int x = pos.x - trunkWidthY; x < pos.x + trunkWidthY; ++x) {
|
||||
for (int z = pos.z - trunkWidthY; z < pos.z + trunkWidthY; ++z) {
|
||||
if ((x >= pos.x + trunkWidthY || x < pos.x - trunkWidthY) && (z >= pos.z + trunkWidthY || z < pos.z - trunkWidthY)) {
|
||||
continue;
|
||||
if (x < 0 || y < 0 || z < 0 || x >= sizeX || y >= sizeY || z >= sizeZ)
|
||||
continue;
|
||||
|
||||
_volumeData->setVoxel(x, y, z, voxel);
|
||||
}
|
||||
if (y == pos.y) {
|
||||
y = findChunkFloor(chunkSize, chunk, x, z);
|
||||
}
|
||||
chunk->setVoxel(x, y, z, voxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int width = 16;
|
||||
const int depth = 16;
|
||||
const int height = 12;
|
||||
const Voxel leavesVoxel(LEAVES, 1);
|
||||
const glm::ivec3 leafesPos(pos.x, top + height / 2, pos.z);
|
||||
if (type == TreeType::ELLIPSIS) {
|
||||
const int centerLeavesPos = top + height / 2;
|
||||
const glm::ivec3 leafesPos(pos.x, centerLeavesPos, pos.z);
|
||||
createEllipse(leafesPos, width, height, depth, leavesVoxel);
|
||||
createEllipse(region, chunk, leafesPos, width, height, depth, leavesVoxel);
|
||||
} else if (type == TreeType::CONE) {
|
||||
const glm::ivec3 leafesPos(pos.x, top, pos.z);
|
||||
createCone(leafesPos, width, height, depth, leavesVoxel);
|
||||
createCone(region, chunk, leafesPos, width, height, depth, leavesVoxel);
|
||||
} else if (type == TreeType::DOME) {
|
||||
const glm::ivec3 leafesPos(pos.x, top, pos.z);
|
||||
createDome(leafesPos, width, height, depth, leavesVoxel);
|
||||
createDome(region, chunk, leafesPos, width, height, depth, leavesVoxel);
|
||||
} else if (type == TreeType::CUBE) {
|
||||
createCube(region, chunk, leafesPos, width, height, depth, leavesVoxel);
|
||||
// TODO: use CreatePlane
|
||||
createCube(region, chunk, leafesPos, width + 2, height - 2, depth - 2, leavesVoxel);
|
||||
createCube(region, chunk, leafesPos, width - 2, height + 2, depth - 2, leavesVoxel);
|
||||
createCube(region, chunk, leafesPos, width - 2, height - 2, depth + 2, leavesVoxel);
|
||||
}
|
||||
}
|
||||
|
||||
void World::createTrees() {
|
||||
const int amount = 4;
|
||||
Log::debug("generate %i trees", amount);
|
||||
// TODO: don't place trees on top of other trees
|
||||
// TODO: don't use random positions, but decide on the material of some positions
|
||||
for (int i = 0; i < amount; ++i) {
|
||||
const glm::ivec3& pos = internalRandomPos(10);
|
||||
addTree(pos, TreeType::ELLIPSIS);
|
||||
}
|
||||
for (int i = 0; i < amount; ++i) {
|
||||
const glm::ivec3& pos = internalRandomPos(10);
|
||||
addTree(pos, TreeType::CONE);
|
||||
void World::createTrees(int chunkSize, const PolyVox::Region& region, WorldData::Chunk* chunk) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
const int maxSize = 14;
|
||||
const int rndVal = core::random(maxSize, chunkSize - maxSize);
|
||||
// number should be even
|
||||
if (!(rndVal % 2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int rndValZ = core::random(maxSize, chunkSize - maxSize);
|
||||
// TODO: use a noise map to get the position
|
||||
glm::ivec3 pos(rndVal, -1, rndValZ);
|
||||
const int y = findChunkFloor(chunkSize, chunk, pos.x, pos.z);
|
||||
if (y < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pos.y = y;
|
||||
|
||||
const int size = core::random(12, maxSize);
|
||||
const int height = core::random(10, 14);
|
||||
const int trunkHeight = core::random(5, 9);
|
||||
const int treeType = core::random(0, int(TreeType::MAX) - 1);
|
||||
const int trunkWidth = 1;
|
||||
addTree(chunkSize, region, chunk, pos, (TreeType)treeType, trunkHeight, trunkWidth, size, size, height);
|
||||
}
|
||||
}
|
||||
|
||||
void World::createClouds() {
|
||||
void World::createClouds(const PolyVox::Region& region, WorldData::Chunk* chunk) {
|
||||
const int amount = 4;
|
||||
Log::debug("generate %i clouds", amount);
|
||||
|
||||
const Voxel voxel(CLOUDS, Voxel::getMinDensity());
|
||||
for (int i = 0; i < amount; ++i) {
|
||||
const int height = 10;
|
||||
const glm::ivec2& pos = randomPosWithoutHeight();
|
||||
glm::ivec3 cloudCenterPos(pos.x, _size - height, pos.y);
|
||||
createEllipse(cloudCenterPos, 10, height, 10, voxel);
|
||||
const glm::ivec2& pos = randomPosWithoutHeight(region);
|
||||
glm::ivec3 cloudCenterPos(pos.x, region.getUpperY() - height, pos.y);
|
||||
createEllipse(region, chunk, cloudCenterPos, 10, height, 10, voxel);
|
||||
cloudCenterPos.x -= 5;
|
||||
cloudCenterPos.y -= 5 + i;
|
||||
createEllipse(cloudCenterPos, 20, height, 35, voxel);
|
||||
createEllipse(region, chunk, cloudCenterPos, 20, height, 35, voxel);
|
||||
}
|
||||
}
|
||||
|
||||
void World::createUnderground() {
|
||||
void World::createUnderground(const PolyVox::Region& region, WorldData::Chunk* chunk) {
|
||||
glm::ivec3 startPos(1, 1, 1);
|
||||
const Voxel voxel(DIRT, Voxel::getMaxDensity());
|
||||
createPlane(startPos, 10, 10, voxel);
|
||||
createPlane(region, chunk, startPos, 10, 10, voxel);
|
||||
}
|
||||
|
||||
bool World::load(long seed, util::IProgressMonitor* progressMonitor) {
|
||||
bool World::load(const PolyVox::Region& region, WorldData::Chunk* chunk) {
|
||||
const core::App* app = core::App::getInstance();
|
||||
const io::FilesystemPtr& filesystem = app->filesystem();
|
||||
const std::string filename = "world-" + std::to_string(seed) + ".wld";
|
||||
const std::string& filename = core::string::format("world-%li-%i-%i-%i.wld", _seed, region.getCentreX(), region.getCentreY(), region.getCentreZ());
|
||||
const io::FilePtr& f = filesystem->open(filename);
|
||||
if (!f)
|
||||
if (!f->exists()) {
|
||||
return false;
|
||||
destroy();
|
||||
}
|
||||
Log::trace("Try to load world %s", f->getName().c_str());
|
||||
uint8_t *fileBuf;
|
||||
// TODO: load async, put world into state loading, and do the real loading in onFrame if the file is fully loaded
|
||||
|
@ -315,31 +332,19 @@ bool World::load(long seed, util::IProgressMonitor* progressMonitor) {
|
|||
bs.append(fileBuf, fileLen);
|
||||
int len;
|
||||
int version;
|
||||
bs.readFormat("ibli", &len, &version, &_seed, &_size);
|
||||
|
||||
if (progressMonitor)
|
||||
progressMonitor->init(_size * MAX_HEIGHT * _size);
|
||||
bs.readFormat("ib", &len, &version);
|
||||
|
||||
if (version != WORLD_FILE_VERSION) {
|
||||
Log::error("file %s has a wrong version number %i (expected %i)", f->getName().c_str(), version, WORLD_FILE_VERSION);
|
||||
return false;
|
||||
}
|
||||
if (_seed != seed) {
|
||||
Log::error("file %s has a wrong seed %li (expected %li)", f->getName().c_str(), _seed, seed);
|
||||
return false;
|
||||
}
|
||||
if (_size <= 0) {
|
||||
Log::error("file %s has invalid size: %i", f->getName().c_str(), _size);
|
||||
return false;
|
||||
}
|
||||
const int sizeLimit = 256;
|
||||
const int sizeLimit = 1024;
|
||||
if (len > 1000l * 1000l * sizeLimit) {
|
||||
Log::error("extracted memory would be more than %i MB for the file %s", sizeLimit, f->getName().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
_engine.seed(_seed);
|
||||
Log::info("Loading a world with size %i from file %s,uncompressing to %i", _size, f->getName().c_str(), (int) len);
|
||||
Log::info("Loading a world from file %s,uncompressing to %i", f->getName().c_str(), (int) len);
|
||||
|
||||
uint8_t* targetBuf = new uint8_t[len];
|
||||
std::unique_ptr<uint8_t[]> smartTargetBuf(targetBuf);
|
||||
|
@ -354,8 +359,6 @@ bool World::load(long seed, util::IProgressMonitor* progressMonitor) {
|
|||
core::ByteStream voxelBuf(len);
|
||||
voxelBuf.append(targetBuf, len);
|
||||
|
||||
const PolyVox::Region region(0, 0, 0, _size, MAX_HEIGHT, _size);
|
||||
WorldData* volumeData = new WorldData(region);
|
||||
const PolyVox::Vector3DInt32& lower = region.getLowerCorner();
|
||||
const PolyVox::Vector3DInt32& upper = region.getUpperCorner();
|
||||
const int lowerZ = lower.getZ();
|
||||
|
@ -371,29 +374,16 @@ bool World::load(long seed, util::IProgressMonitor* progressMonitor) {
|
|||
const uint8_t material = voxelBuf.readByte();
|
||||
const uint8_t density = voxelBuf.readByte();
|
||||
const Voxel voxel(material, density);
|
||||
volumeData->setVoxel(x, y, z, voxel);
|
||||
if (progressMonitor)
|
||||
progressMonitor->step();
|
||||
_volumeData->setVoxel(x, y, z, voxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (progressMonitor)
|
||||
progressMonitor->done();
|
||||
_volumeData = volumeData;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool World::save(long seed) {
|
||||
if (_volumeData == nullptr) {
|
||||
Log::error("No world created yet");
|
||||
return false;
|
||||
}
|
||||
if (seed != _seed) {
|
||||
Log::error("Seeds don't match");
|
||||
return false;
|
||||
}
|
||||
bool World::save(const PolyVox::Region& region, WorldData::Chunk* chunk) {
|
||||
Log::info("Save chunk");
|
||||
core::ByteStream voxelStream;
|
||||
const PolyVox::Region region(0, 0, 0, _size, MAX_HEIGHT, _size);
|
||||
const PolyVox::Vector3DInt32& lower = region.getLowerCorner();
|
||||
const PolyVox::Vector3DInt32& upper = region.getUpperCorner();
|
||||
const int lowerZ = lower.getZ();
|
||||
|
@ -413,7 +403,7 @@ bool World::save(long seed) {
|
|||
}
|
||||
|
||||
// save the stuff
|
||||
const std::string filename = "world-" + std::to_string(seed) + ".wld";
|
||||
const std::string filename = core::string::format("world-%li-%i-%i-%i.wld", _seed, region.getCentreX(), region.getCentreY(), region.getCentreZ());
|
||||
const core::App* app = core::App::getInstance();
|
||||
const io::FilesystemPtr& filesystem = app->filesystem();
|
||||
|
||||
|
@ -428,7 +418,7 @@ bool World::save(long seed) {
|
|||
return false;
|
||||
}
|
||||
core::ByteStream final;
|
||||
final.addFormat("ibli", voxelSize, WORLD_FILE_VERSION, _seed, _size);
|
||||
final.addFormat("ib", voxelSize, WORLD_FILE_VERSION);
|
||||
final.append(compressedVoxelBuf, neededVoxelBufLen);
|
||||
if (!filesystem->write(filename, final.getBuffer(), final.getSize())) {
|
||||
Log::error("Failed to write file %s", filename.c_str());
|
||||
|
@ -438,52 +428,31 @@ bool World::save(long seed) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void World::create(long seed, int size, util::IProgressMonitor* progressMonitor) {
|
||||
if (_seed == seed)
|
||||
return;
|
||||
_seed = seed;
|
||||
_engine.seed(_seed);
|
||||
_size = size;
|
||||
Log::info("Using seed %li with size %i", seed, size);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (_volumeData != nullptr) {
|
||||
Log::info("Create a new world");
|
||||
destroy();
|
||||
}
|
||||
|
||||
_noise.setSeed(seed);
|
||||
_noise.init();
|
||||
const PolyVox::Region region(0, 0, 0, size - 1, MAX_HEIGHT - 1, size - 1);
|
||||
WorldData* volumeData = new WorldData(region);
|
||||
if (progressMonitor)
|
||||
progressMonitor->init(size * MAX_HEIGHT * size + 2);
|
||||
const PolyVox::Vector3DInt32& lower = region.getLowerCorner();
|
||||
const PolyVox::Vector3DInt32& upper = region.getUpperCorner();
|
||||
for (double z = lower.getZ(); z < upper.getZ(); ++z) {
|
||||
for (double x = lower.getX(); x < upper.getX(); ++x) {
|
||||
const int height = (_noise.get(x, z, 0, 256.0) + 1) * 128;
|
||||
|
||||
for (double h = 0; h <= height; ++h) {
|
||||
if (progressMonitor) {
|
||||
progressMonitor->step();
|
||||
}
|
||||
const Voxel voxel(DIRT, DIRT);
|
||||
volumeData->setVoxel(x, h, z, voxel);
|
||||
}
|
||||
void World::create(const PolyVox::Region& region, WorldData::Chunk* chunk) {
|
||||
Log::info("Create new chunk at %i:%i:%i", region.getCentreX(), region.getCentreY(), region.getCentreZ());
|
||||
const int width = region.getWidthInVoxels();
|
||||
const int depth = region.getDepthInVoxels();
|
||||
const int height = region.getHeightInVoxels();
|
||||
for (double z = 0; z < depth; ++z) {
|
||||
for (double x = 0; x < width; ++x) {
|
||||
const glm::vec2 noisePos2d = glm::vec2(x, z);
|
||||
// TODO: include random here, too
|
||||
const float landscapeNoise = noise::Simplex::Noise2D(noisePos2d, 3, 0.1f, 0.01f);
|
||||
const float noiseNormalized = (landscapeNoise + 1.0f) * 0.5f;
|
||||
const float mountainNoise = noise::Simplex::Noise2D(noisePos2d, 2, 0.3f, 0.00075f);
|
||||
const float mountainNoiseNormalized = (mountainNoise + 1.0f) * 0.5f;
|
||||
const float mountainMultiplier = mountainNoiseNormalized * (mountainNoiseNormalized + 0.5f);
|
||||
const float n = glm::clamp(noiseNormalized * mountainMultiplier, 0.0f, 1.0f);
|
||||
const int ni = n * height;
|
||||
for (int h = 0; h <= ni; ++h) {
|
||||
// TODO: use biommanager
|
||||
const Voxel voxel(DIRT, DIRT);
|
||||
chunk->setVoxel(x, h, z, voxel);
|
||||
}
|
||||
}
|
||||
_volumeData = volumeData;
|
||||
createTrees();
|
||||
if (progressMonitor) {
|
||||
progressMonitor->step();
|
||||
}
|
||||
createClouds();
|
||||
if (progressMonitor) {
|
||||
progressMonitor->step();
|
||||
progressMonitor->done();
|
||||
}
|
||||
}
|
||||
createTrees(_chunkSize->intVal(), region, chunk);
|
||||
createClouds(region, chunk);
|
||||
core::App::getInstance()->eventBus()->publish(WorldCreatedEvent(this));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,20 +7,17 @@
|
|||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
|
||||
#include "noise/AccidentalNoise.h"
|
||||
#include "noise/WorldShapeNoise.h"
|
||||
#include "noise/NoisePPNoise.h"
|
||||
#include "noise/PerlinNoise.h"
|
||||
#include "io/Filesystem.h"
|
||||
#include "WorldData.h"
|
||||
#include "WorldEvents.h"
|
||||
#include "Voxel.h"
|
||||
#include "Raycast.h"
|
||||
#include "util/IProgressMonitor.h"
|
||||
#include "core/ThreadPool.h"
|
||||
#include "core/ReadWriteLock.h"
|
||||
#include "core/Var.h"
|
||||
#include "core/Log.h"
|
||||
|
||||
namespace voxel {
|
||||
|
||||
|
@ -35,15 +32,8 @@ public:
|
|||
World();
|
||||
~World();
|
||||
|
||||
void create(long seed, int size, util::IProgressMonitor* progressMonitor = nullptr);
|
||||
bool load(long seed, util::IProgressMonitor* progressMonitor = nullptr);
|
||||
bool save(long seed);
|
||||
void destroy();
|
||||
|
||||
inline bool isCreated() const {
|
||||
return _volumeData != nullptr;
|
||||
}
|
||||
|
||||
Result raycast(const glm::vec3& start, const glm::vec3& end, voxel::Raycast& raycast);
|
||||
bool findPath(const PolyVox::Vector3DInt32& start, const PolyVox::Vector3DInt32& end, std::list<PolyVox::Vector3DInt32>& listResult);
|
||||
int findFloor(int x, int z) const;
|
||||
|
@ -52,8 +42,7 @@ public:
|
|||
/**
|
||||
* @brief Returns a random position inside the boundaries of the world (on the surface)
|
||||
*/
|
||||
glm::ivec3 randomPos(int border = 0) const;
|
||||
glm::ivec2 randomPosWithoutHeight(int border = 0) const;
|
||||
glm::ivec3 randomPos() const;
|
||||
|
||||
/**
|
||||
* @brief Cuts the given world coordinate down to mesh tile vectors
|
||||
|
@ -98,22 +87,44 @@ public:
|
|||
|
||||
void onFrame(long dt);
|
||||
|
||||
inline int size() const { return _size; }
|
||||
inline long seed() const { return _seed; }
|
||||
|
||||
void setSeed(long seed) {
|
||||
Log::info("Seed is: %li", seed);
|
||||
_seed = seed;
|
||||
_engine.seed(seed);
|
||||
}
|
||||
|
||||
inline bool isCreated() const {
|
||||
return _seed != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
enum class TreeType {
|
||||
DOME,
|
||||
CONE,
|
||||
ELLIPSIS
|
||||
ELLIPSIS,
|
||||
CUBE,
|
||||
MAX
|
||||
};
|
||||
|
||||
WorldData* _volumeData;
|
||||
class Pager: public WorldData::Pager {
|
||||
private:
|
||||
World& _world;
|
||||
public:
|
||||
Pager(World& world) :
|
||||
_world(world) {
|
||||
}
|
||||
|
||||
void pageIn(const PolyVox::Region& region, WorldData::Chunk* chunk) override;
|
||||
|
||||
void pageOut(const PolyVox::Region& region, WorldData::Chunk* chunk) override;
|
||||
};
|
||||
|
||||
Pager _pager;
|
||||
WorldData *_volumeData;
|
||||
mutable std::mt19937 _engine;
|
||||
long _seed;
|
||||
int _size;
|
||||
noise::NoisePPNoise _noise;
|
||||
noise::WorldShapeNoise _worldShapeNoise;
|
||||
|
||||
struct IVec2HashEquals {
|
||||
size_t operator()(const glm::ivec2& k) const {
|
||||
|
@ -126,24 +137,50 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
// assumes that the mutex is already locked
|
||||
glm::ivec3 internalRandomPos(int border = 0) const;
|
||||
int internalFindFloor(int x, int y) const;
|
||||
template<typename Func>
|
||||
inline auto locked(Func&& func) -> typename std::result_of<Func()>::type {
|
||||
if (_mutex.try_lock_for(std::chrono::milliseconds(5000))) {
|
||||
lockGuard lock(_mutex, std::adopt_lock_t());
|
||||
return func();
|
||||
}
|
||||
Log::warn("Most likely a deadlock in the world - execute without locking");
|
||||
return func();
|
||||
}
|
||||
|
||||
void createCirclePlane(const glm::ivec3& center, int width, int depth, double radius, const Voxel& voxel);
|
||||
void createEllipse(const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel);
|
||||
void createCone(const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel);
|
||||
void createDome(const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel);
|
||||
void createCube(const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel);
|
||||
void createPlane(const glm::ivec3& pos, int width, int depth, const Voxel& voxel);
|
||||
template<typename Func>
|
||||
inline auto locked(Func&& func) const -> typename std::result_of<Func()>::type {
|
||||
if (_mutex.try_lock_for(std::chrono::milliseconds(5000))) {
|
||||
lockGuard lock(_mutex, std::adopt_lock_t());
|
||||
return func();
|
||||
}
|
||||
Log::warn("Most likely a deadlock in the world - execute without locking");
|
||||
return func();
|
||||
}
|
||||
|
||||
void addTree(const glm::ivec3& pos, TreeType type, int trunkHeight = 10);
|
||||
void createTrees();
|
||||
void createClouds();
|
||||
void createUnderground();
|
||||
static int findChunkFloor(int chunkSize, WorldData::Chunk* chunk, int x, int y);
|
||||
|
||||
bool load(const PolyVox::Region& region, WorldData::Chunk* chunk);
|
||||
bool save(const PolyVox::Region& region, WorldData::Chunk* chunk);
|
||||
// don't access the volume in anything that is called here
|
||||
void create(const PolyVox::Region& region, WorldData::Chunk* chunk);
|
||||
|
||||
static void createCirclePlane(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& center, int width, int depth, double radius, const Voxel& voxel);
|
||||
static void createEllipse(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel);
|
||||
static void createCone(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel);
|
||||
static void createDome(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel);
|
||||
static void createCube(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int height, int depth, const Voxel& voxel);
|
||||
static void createPlane(const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, int width, int depth, const Voxel& voxel);
|
||||
|
||||
static void addTree(int chunkSize, const PolyVox::Region& region, WorldData::Chunk* chunk, const glm::ivec3& pos, TreeType type, int trunkHeight, int trunkWidth, int width, int depth, int height);
|
||||
static void createTrees(int chunkSize, const PolyVox::Region& region, WorldData::Chunk* chunk);
|
||||
glm::ivec2 randomPosWithoutHeight(const PolyVox::Region& region);
|
||||
void createClouds(const PolyVox::Region& region, WorldData::Chunk* chunk);
|
||||
static void createUnderground(const PolyVox::Region& region, WorldData::Chunk* chunk);
|
||||
|
||||
core::ThreadPool _threadPool;
|
||||
mutable std::mutex _mutex;
|
||||
using mutex = std::recursive_timed_mutex;
|
||||
mutable mutex _mutex;
|
||||
using lockGuard = std::lock_guard<mutex>;
|
||||
core::ReadWriteLock _rwLock;
|
||||
std::deque<DecodedMeshData> _meshQueue;
|
||||
// fast lookup for positions that are already extracted and available in the _meshData vector
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <PolyVox/RawVolume.h>
|
||||
#include <PolyVox/PagedVolume.h>
|
||||
#include "Voxel.h"
|
||||
|
||||
namespace voxel {
|
||||
|
||||
typedef PolyVox::RawVolume<Voxel> WorldData;
|
||||
typedef PolyVox::PagedVolume<Voxel> WorldData;
|
||||
|
||||
}
|
||||
|
|
|
@ -2,35 +2,11 @@
|
|||
#include "voxel/World.h"
|
||||
|
||||
namespace voxel {
|
||||
namespace {
|
||||
const long seed = 1L;
|
||||
const int size = 32;
|
||||
}
|
||||
|
||||
class WorldTest: public core::AbstractTest {
|
||||
};
|
||||
|
||||
TEST_F(WorldTest, testCreateSaveLoad) {
|
||||
World world;
|
||||
world.create(seed, size);
|
||||
ASSERT_TRUE(world.isCreated());
|
||||
ASSERT_EQ(seed, world.seed());
|
||||
ASSERT_EQ(size, world.size());
|
||||
ASSERT_TRUE(world.save(seed));
|
||||
ASSERT_EQ(seed, world.seed());
|
||||
ASSERT_EQ(size, world.size());
|
||||
ASSERT_TRUE(world.load(seed));
|
||||
ASSERT_TRUE(world.isCreated());
|
||||
ASSERT_EQ(seed, world.seed());
|
||||
ASSERT_EQ(size, world.size());
|
||||
}
|
||||
|
||||
TEST_F(WorldTest, testLoad) {
|
||||
World world;
|
||||
ASSERT_TRUE(world.load(seed));
|
||||
ASSERT_TRUE(world.isCreated());
|
||||
ASSERT_EQ(seed, world.seed());
|
||||
ASSERT_EQ(size, world.size());
|
||||
TEST_F(WorldTest, testEmptyFillMe) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ core::AppState Server::onInit() {
|
|||
Log::error("Failed to bind the server socket on %s:%i", host->strVal().c_str(), port->intVal());
|
||||
return core::Cleanup;
|
||||
}
|
||||
Log::error("Server socket is up at %s:%i", host->strVal().c_str(), port->intVal());
|
||||
Log::info("Server socket is up at %s:%i", host->strVal().c_str(), port->intVal());
|
||||
return state;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
fips_begin_app(worldgenerator cmdline)
|
||||
fips_files(
|
||||
WorldGenerator.cpp WorldGenerator.h
|
||||
)
|
||||
|
||||
fips_dir(sauce)
|
||||
fips_files(
|
||||
WorldGeneratorModule.h
|
||||
WorldGeneratorInjector.h
|
||||
)
|
||||
|
||||
fips_deps(voxel core io)
|
||||
copy_data_files(worldgenerator)
|
||||
fips_end_app()
|
|
@ -1,57 +0,0 @@
|
|||
#include "WorldGenerator.h"
|
||||
#include "sauce/WorldGeneratorInjector.h"
|
||||
#include "core/Var.h"
|
||||
|
||||
WorldGenerator::WorldGenerator(voxel::WorldPtr world, core::EventBusPtr eventBus, core::TimeProviderPtr timeProvider, io::FilesystemPtr filesystem) :
|
||||
App(filesystem, eventBus, 15681), _world(world), _timeProvider(timeProvider), _seed(0L), _size(0) {
|
||||
init("engine", "worldgenerator");
|
||||
}
|
||||
|
||||
core::AppState WorldGenerator::onInit() {
|
||||
core::AppState state = App::onInit();
|
||||
const core::VarPtr& seed = core::Var::get("seed");
|
||||
const core::VarPtr& size = core::Var::get("size");
|
||||
|
||||
if (size->strVal().empty()) {
|
||||
Log::error("No size specified: -set size <size>");
|
||||
return core::AppState::Cleanup;
|
||||
} else if (seed->strVal().empty()) {
|
||||
Log::error("No seed specified: -set seed <seed>");
|
||||
return core::AppState::Cleanup;
|
||||
}
|
||||
_seed = seed->longVal();
|
||||
_size = size->intVal();
|
||||
return state;
|
||||
}
|
||||
|
||||
core::AppState WorldGenerator::onRunning() {
|
||||
core::AppState state = core::App::onRunning();
|
||||
|
||||
class ProgressMonitor: public util::IProgressMonitor {
|
||||
public:
|
||||
void step(int steps = 1) override {
|
||||
IProgressMonitor::step(steps);
|
||||
Log::info("max: %i, steps: %i => %f\r", _max, _steps, progress());
|
||||
}
|
||||
void done() override {
|
||||
Log::info("\ndone");
|
||||
}
|
||||
} monitor;
|
||||
|
||||
unsigned long start = _timeProvider->currentTime();
|
||||
_world->create(_seed, _size, &monitor);
|
||||
if (!_world->save(_seed)) {
|
||||
Log::error("Failed to save the world for seed %li", _seed);
|
||||
} else {
|
||||
Log::info("World for seed %li created", _seed);
|
||||
}
|
||||
unsigned long end = _timeProvider->currentTime();
|
||||
unsigned long delta = end - start;
|
||||
Log::info("World generating process took %lu milliseconds", delta);
|
||||
return state;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
getInjector()->get<WorldGenerator>()->startMainLoop(argc, argv);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/App.h"
|
||||
#include "voxel/World.h"
|
||||
#include "core/TimeProvider.h"
|
||||
|
||||
class WorldGenerator: public core::App {
|
||||
private:
|
||||
voxel::WorldPtr _world;
|
||||
core::TimeProviderPtr _timeProvider;
|
||||
long _seed;
|
||||
int _size;
|
||||
public:
|
||||
WorldGenerator(voxel::WorldPtr world, core::EventBusPtr eventBus, core::TimeProviderPtr timeProvider, io::FilesystemPtr filesystem);
|
||||
|
||||
core::AppState onInit() override;
|
||||
core::AppState onRunning() override;
|
||||
};
|
|
@ -1,9 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "WorldGeneratorModule.h"
|
||||
|
||||
inline sauce::shared_ptr<sauce::Injector> getInjector() {
|
||||
sauce::Modules modules;
|
||||
modules.add<WorldGeneratorModule>();
|
||||
return modules.createInjector();
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/AbstractModule.h"
|
||||
#include "voxel/World.h"
|
||||
|
||||
class WorldGeneratorModule: public core::AbstractModule {
|
||||
void configure() const override {
|
||||
core::AbstractModule::configure();
|
||||
bind<WorldGenerator>().in<sauce::SingletonScope>().to<WorldGenerator(voxel::World &, core::EventBus &, core::TimeProvider &, io::Filesystem &)>();
|
||||
bind<voxel::World>().in<sauce::SingletonScope>().to<voxel::World>();
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue