Updated to new motor things. Made a empty client.
This commit is contained in:
parent
c3be4d5d12
commit
b949a9d5a8
24 changed files with 997 additions and 803 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "contrib/libwebsockets"]
|
||||||
|
path = contrib/libwebsockets
|
||||||
|
url = git://github.com/warmcat/libwebsockets.git
|
|
@ -43,4 +43,10 @@ include(motor/cmake/join.cmake)
|
||||||
join("${warnings}" " " warnings)
|
join("${warnings}" " " warnings)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${warnings}")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${warnings}")
|
||||||
|
|
||||||
|
|
||||||
|
# websockets lib
|
||||||
|
set(WITHOUT_TESTAPPS ON CACHE INTERNAL "" FORCE)
|
||||||
|
add_subdirectory(${PROJECT_SOURCE_DIR}/contrib/libwebsockets/)
|
||||||
|
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/contrib/libwebsockets/")
|
||||||
|
|
||||||
add_subdirectory("src")
|
add_subdirectory("src")
|
||||||
|
|
1
contrib/libwebsockets
Submodule
1
contrib/libwebsockets
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 2577c831f41700d8162b2509198482e4a438b332
|
|
@ -38,6 +38,7 @@
|
||||||
"-Wno-unused-parameter",
|
"-Wno-unused-parameter",
|
||||||
"-I${folder:${project_path:sdlgame.sublime-project}}",
|
"-I${folder:${project_path:sdlgame.sublime-project}}",
|
||||||
"-I${folder:${project_path:sdlgame.sublime-project}}/motor",
|
"-I${folder:${project_path:sdlgame.sublime-project}}/motor",
|
||||||
|
"-isystem${folder:${project_path:sdlgame.sublime-project}}/contrib/libwebsockets/",
|
||||||
"-isystem${folder:${project_path:sdlgame.sublime-project}}/motor/contrib/assimp-3.0.1270/include",
|
"-isystem${folder:${project_path:sdlgame.sublime-project}}/motor/contrib/assimp-3.0.1270/include",
|
||||||
"-isystem${folder:${project_path:sdlgame.sublime-project}}/motor/contrib/soil",
|
"-isystem${folder:${project_path:sdlgame.sublime-project}}/motor/contrib/soil",
|
||||||
"-isystem${folder:${project_path:sdlgame.sublime-project}}/motor/contrib/bullet/src",
|
"-isystem${folder:${project_path:sdlgame.sublime-project}}/motor/contrib/bullet/src",
|
||||||
|
@ -50,8 +51,8 @@
|
||||||
"-stdlib=libc++",
|
"-stdlib=libc++",
|
||||||
"-DDEBUG=1",
|
"-DDEBUG=1",
|
||||||
"-nostdinc",
|
"-nostdinc",
|
||||||
|
"-isystem/Users/joshua/Documents/Code/libcxx/include/",
|
||||||
"-isystem/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk",
|
"-isystem/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk",
|
||||||
"-isystem/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/c++/v1",
|
|
||||||
"-isystem/System/Library/Frameworks/OpenGL.framework/Versions/Current/Header",
|
"-isystem/System/Library/Frameworks/OpenGL.framework/Versions/Current/Header",
|
||||||
"-isystem/usr/local/include",
|
"-isystem/usr/local/include",
|
||||||
"-isystem/sw/include",
|
"-isystem/sw/include",
|
||||||
|
|
201
src/Base.cpp
201
src/Base.cpp
|
@ -1,82 +1,179 @@
|
||||||
|
|
||||||
#include "Base.hpp"
|
#include "Base.hpp"
|
||||||
|
#include "input.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <motor/basic/bullet_debug_drawer.hpp>
|
||||||
|
|
||||||
namespace games {
|
namespace games {
|
||||||
using namespace motor;
|
using namespace motor;
|
||||||
|
|
||||||
Base::Base(int window_width_, int window_height_)
|
std::ostream& operator<<(std::ostream& out, Input::Mouse::Button const& rh){
|
||||||
: window_width(window_width_), window_height(window_height_)
|
using Button = Input::Mouse::Button;
|
||||||
{}
|
switch(rh){
|
||||||
|
case Button::left: return out << "left";
|
||||||
|
case Button::middle: return out << "middle";
|
||||||
|
case Button::right: return out << "right";
|
||||||
|
case Button::wheeldown: return out << "downscroll";
|
||||||
|
case Button::wheelup: return out << "upscroll";
|
||||||
|
default: {
|
||||||
|
return out << rh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Base::~Base(){}
|
Base::Base(int window_width_, int window_height_, std::shared_ptr<Base>& active_base_)
|
||||||
|
: window_width(window_width_)
|
||||||
|
, window_height(window_height_)
|
||||||
|
, active_base(active_base_)
|
||||||
|
{
|
||||||
|
physics_scene->used_shader = physics_scene->flat_shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
Base::~Base()
|
||||||
|
{
|
||||||
|
resource_cache.free_all_resources();
|
||||||
|
motor::resource_cache.free_all_resources();
|
||||||
|
}
|
||||||
|
|
||||||
bool Base::has_ended(){
|
bool Base::has_ended(){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Base::update(float const dt, std::map<SDLKey, bool> __attribute__((unused)) keys_went_down, std::map<SDLKey, bool> __attribute__((unused)) is_pressed, std::map<SDLKey, bool> __attribute__((unused)) keyw_went_up){
|
void Base::update(float const dt, Input input){
|
||||||
time += dt;
|
time += dt;
|
||||||
|
|
||||||
update_bullet(dt);
|
if(physics_update){
|
||||||
check_collisions();
|
world.physics.update(dt, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Base::update_bullet(float const dt){
|
if(free_camera_mode){
|
||||||
dynamics_world->stepSimulation(dt, 20);
|
handle_camera(dt, input);
|
||||||
|
|
||||||
for (int j=dynamics_world->getNumCollisionObjects()-1; j>=0 ;j--)
|
|
||||||
{
|
|
||||||
btCollisionObject* obj = dynamics_world->getCollisionObjectArray()[j];
|
|
||||||
btRigidBody* body = btRigidBody::upcast(obj);
|
|
||||||
if (body && body->getMotionState())
|
|
||||||
{
|
|
||||||
if(body->getUserPointer() != nullptr){
|
|
||||||
btTransform trans = body->getWorldTransform();
|
|
||||||
Body* b = static_cast<Body*>(body->getUserPointer());
|
|
||||||
b->sync_from_bullet(trans);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Base::check_collisions(){
|
world.ai.update(dt, input, world);
|
||||||
std::vector<std::pair<btCollisionObject const*, btCollisionObject const*>> bullet_objects_colliding;
|
|
||||||
int const manifolds = dynamics_world->getDispatcher()->getNumManifolds();
|
|
||||||
for(int manifold_index = 0; manifold_index < manifolds; ++manifold_index){
|
|
||||||
auto const manifold = dynamics_world->getDispatcher()->getManifoldByIndexInternal(manifold_index);
|
|
||||||
|
|
||||||
btCollisionObject const* first_object = manifold->getBody0();
|
|
||||||
btCollisionObject const* second_object = manifold->getBody1();
|
|
||||||
|
|
||||||
bullet_objects_colliding.emplace_back(first_object, second_object);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto const& c : bullet_objects_colliding){
|
|
||||||
if(!astrant::contains(bullet_objects_in_collision_previous_frame, c)){
|
|
||||||
bullet_objects_entered_collision(c.first, c.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto const& c : bullet_objects_in_collision_previous_frame){
|
|
||||||
if(!astrant::contains(bullet_objects_colliding, c)){
|
|
||||||
bullet_objects_exited_collision(c.first, c.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bullet_objects_in_collision_previous_frame = bullet_objects_colliding;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Base::draw(){
|
void Base::draw(){
|
||||||
//First, clear the screen
|
try {
|
||||||
fbo.unbind();
|
fbo.unbind();
|
||||||
moggle::gl::set_viewport(0, 0, window_width, window_height);
|
moggle::gl::set_viewport(0, 0, window_width, window_height);
|
||||||
moggle::gl::set_clear_color(0.1f, 0.1f, 0.1f, 1.0f);
|
moggle::gl::set_clear_color(0.1f, 0.1f, 0.1f, 1.0f);
|
||||||
moggle::gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
moggle::gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
moggle::gl::enable(GL_DEPTH_TEST);
|
moggle::gl::enable(GL_DEPTH_TEST);
|
||||||
moggle::gl::enable(GL_BLEND);
|
moggle::gl::enable(GL_BLEND);
|
||||||
moggle::gl::blend_equation(GL_FUNC_ADD);
|
|
||||||
moggle::gl::blend_function(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
moggle::gl::blend_function(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
scene->draw();
|
|
||||||
|
if(draw_physics_world){
|
||||||
|
physics_scene->camera = world.scene->camera;
|
||||||
|
|
||||||
|
for(auto mesh : world.physics.get_debug_draw_result(1 | 2 | 8)){
|
||||||
|
assert(mesh != nullptr);
|
||||||
|
|
||||||
|
auto const b = std::make_shared<Body>(mesh);
|
||||||
|
physics_scene->add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
physics_scene->draw();
|
||||||
|
physics_scene->remove_all_bodies();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(draw_physics_world && draw_only_physics_world)){
|
||||||
|
world.scene->draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr bool print_screen = false;
|
||||||
|
if(print_screen){
|
||||||
|
std::vector<moggle::vector4<unsigned char>> pixels(window_width * window_height);
|
||||||
|
moggle::gl::clear_error();
|
||||||
|
glReadPixels(0, 0, window_width, window_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
||||||
|
moggle::gl::print_error();
|
||||||
|
for(int y = 0; y < window_height; ++y){
|
||||||
|
for(int x = 0; x < window_width; ++x){
|
||||||
|
for(int i = 0; i < 4; ++i){
|
||||||
|
std::cout << std::setw(3) << std::setfill('0') << size_t(pixels[y * window_height + x][i]) << ((i != 3) ? " " : "");
|
||||||
|
}
|
||||||
|
std::cout << "|";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (std::runtime_error& e){
|
||||||
|
CERR << "Something went wrong during drawing: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
moggle::gl::clear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
world.hud->used_shader = world.hud->flat_shader;
|
||||||
|
world.hud->draw();
|
||||||
|
} catch (std::runtime_error& e){
|
||||||
|
CERR << "Something went wrong during drawing: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
motor::Body* Base::raycast(moggle::vector2<float> const screen_position) const{
|
||||||
|
motor::Position const view = {0, 0, window_width, window_height};
|
||||||
|
|
||||||
|
motor::Position in = {screen_position[0], screen_position[1], 0.0, 1.f};
|
||||||
|
|
||||||
|
auto const near_point = world.scene->camera.unproject(in, view);
|
||||||
|
in[2] = 1.0f;
|
||||||
|
auto const far_point = world.scene->camera.unproject(in, view);
|
||||||
|
return world.physics.raycast(near_point, far_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Base::handle_camera(const float dt, Input input)
|
||||||
|
{
|
||||||
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
|
|
||||||
|
float const distance = camera_speed * dt;
|
||||||
|
float const rotation = camera_rotation_speed * dt;
|
||||||
|
|
||||||
|
auto const move = [](Camera& p, Position const displacement){
|
||||||
|
p.set_position(p.get_position() + displacement);
|
||||||
|
};
|
||||||
|
|
||||||
|
Camera& b = world.scene->camera;
|
||||||
|
|
||||||
|
auto const m = inverse(b.get_rotation_matrix());
|
||||||
|
Position const down = m*Position{0, -distance, 0};
|
||||||
|
Position const up = m*Position{0, distance, 0};
|
||||||
|
Position const left = m*Position{-distance, 0, 0};
|
||||||
|
Position const right = m*Position{distance, 0, 0};
|
||||||
|
Position const backward = m*Position{0, 0, distance};
|
||||||
|
Position const forward = m*Position{0, 0, -distance};
|
||||||
|
|
||||||
|
if(input.keys_pressed[SDLK_w]){
|
||||||
|
move(b, forward);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.keys_pressed[SDLK_s]){
|
||||||
|
move(b, backward);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.keys_pressed[SDLK_d]){
|
||||||
|
move(b, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.keys_pressed[SDLK_a]){
|
||||||
|
move(b, left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.keys_pressed[SDLK_t]){
|
||||||
|
move(b, up);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.keys_pressed[SDLK_g]){
|
||||||
|
move(b, down);
|
||||||
|
}
|
||||||
|
|
||||||
|
b.add_pitch(-input.mouse.difference[1] * rotation);
|
||||||
|
b.add_yaw(-input.mouse.difference[0] * rotation);
|
||||||
|
|
||||||
|
input.mouse.position[0] = window_width/2;
|
||||||
|
input.mouse.position[1] = window_height/2;
|
||||||
|
SDL_WarpMouse(input.mouse.position[0], input.mouse.position[1]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceCache Base::resource_cache;
|
ResourceCache Base::resource_cache;
|
||||||
|
|
177
src/Base.hpp
177
src/Base.hpp
|
@ -7,165 +7,70 @@
|
||||||
#include <moggle/xxx/mesh.hpp>
|
#include <moggle/xxx/mesh.hpp>
|
||||||
#include <motor/basic/body.hpp>
|
#include <motor/basic/body.hpp>
|
||||||
#include <motor/basic/scene.hpp>
|
#include <motor/basic/scene.hpp>
|
||||||
|
#include <motor/basic/configuration.hpp>
|
||||||
#include <motor/core/fbo.hpp>
|
#include <motor/core/fbo.hpp>
|
||||||
|
|
||||||
#include <astrant-extensions/algorithm.hpp>
|
|
||||||
|
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
|
#include "physics.hpp"
|
||||||
|
#include "ai_world.hpp"
|
||||||
|
|
||||||
//! Returns (f(ax, bx) && f(ay, by)) || (f(ax, by) && f(ay, bx))
|
#include "input.hpp"
|
||||||
//! Useful for instance when you want to compare two pairs if they contain the same elements, but don't care about the order
|
#include "world.hpp"
|
||||||
//! (and we provide an overload for that of course)
|
|
||||||
template <typename First, typename Second, typename Third, typename Fourth, typename CompareFunction>
|
|
||||||
bool order_agnostic_compare(First const& ax, Second const& ay, Third const& bx, Fourth const& by, CompareFunction const& f){
|
|
||||||
return
|
|
||||||
(f(ax, bx) && f(ay, by))
|
|
||||||
||
|
|
||||||
(f(ax, by) && f(ay, bx));
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Figure out what the syntax of this was, then express equal, less{,or equal}, greater{, or equal}.
|
|
||||||
//using order_agnostic_equalness<First, Second, Third, Fourth> = order_agnostic_compare<First, Second, Third, Fourth, std::eq>;
|
|
||||||
|
|
||||||
template <typename First, typename Second, typename Third, typename Fourth>
|
|
||||||
bool order_agnostic_equal(First const& ax, Second const& ay, Third const& bx, Fourth const& by){
|
|
||||||
return ((ax == bx && ay == by) || (ax == by && ay == bx));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename First, typename Second, typename Third, typename Fourth>
|
|
||||||
bool order_agnostic_equal(std::pair<First, Second> const& a, std::pair<Third, Fourth> const& b){
|
|
||||||
return order_agnostic_equalness(a.first, a.second, b.first, b.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace games {
|
namespace games {
|
||||||
using namespace motor;
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Input::Mouse::Button const& rh);
|
||||||
|
|
||||||
struct Base {
|
struct Base {
|
||||||
static ResourceCache resource_cache;
|
static motor::ResourceCache resource_cache;
|
||||||
std::shared_ptr<Scene> scene = std::make_shared<Scene>();
|
std::shared_ptr<motor::Scene> physics_scene = std::make_shared<motor::Scene>();
|
||||||
|
|
||||||
|
World world;
|
||||||
|
std::shared_ptr<motor::Scene>& scene{world.scene};
|
||||||
|
std::shared_ptr<motor::Scene>& hud{world.hud};
|
||||||
|
motor::AIWorld& ai{world.ai};
|
||||||
|
motor::Physics& physics{world.physics};
|
||||||
|
|
||||||
int window_width;
|
int window_width;
|
||||||
int window_height;
|
int window_height;
|
||||||
Fbo fbo{window_width, window_height};
|
motor::Fbo fbo{window_width, window_height};
|
||||||
|
|
||||||
float time = 0.0;
|
float time = 0.0;
|
||||||
|
|
||||||
// So all this is needed to set up Bullet!
|
//! If true, will draw the physics world to the seen. Also see draw_only_physics_world
|
||||||
// You pay for modularity with a lot of code, but perhaps we can wrap this in our own motor::world or something.
|
bool draw_physics_world = false;
|
||||||
std::unique_ptr<btDefaultCollisionConfiguration> collison_configuration{new btDefaultCollisionConfiguration()};
|
|
||||||
std::unique_ptr<btCollisionDispatcher> collision_dispatcher{new btCollisionDispatcher(collison_configuration.get())};
|
|
||||||
btVector3 const world_minimum = btVector3(-1000,-1000,-1000);
|
|
||||||
btVector3 const world_maximum = btVector3(1000,1000,1000);
|
|
||||||
std::unique_ptr<btBroadphaseInterface> overlapping_pair_cache{new btAxisSweep3(world_minimum, world_maximum)};
|
|
||||||
std::unique_ptr<btConstraintSolver> constraint_solver{new btSequentialImpulseConstraintSolver()};
|
|
||||||
std::unique_ptr<btDynamicsWorld> dynamics_world{new btDiscreteDynamicsWorld(collision_dispatcher.get(), overlapping_pair_cache.get(), constraint_solver.get(), collison_configuration.get())};
|
|
||||||
|
|
||||||
Base(int window_width, int window_height);
|
//! If false, will not automatically call motor::Physics::update, which can be useful e.g. when want to step the physics world to catch some bug.
|
||||||
|
bool physics_update = true;
|
||||||
|
|
||||||
|
//! Whether to still draw the real world or not when draw_physics_world is true
|
||||||
|
bool draw_only_physics_world = false;
|
||||||
|
|
||||||
|
//! You can use this to change the Base that is draw/updated in the main loop
|
||||||
|
std::shared_ptr<Base>& active_base;
|
||||||
|
|
||||||
|
Base(int window_width, int window_height, std::shared_ptr<Base>& active_base);
|
||||||
virtual ~Base();
|
virtual ~Base();
|
||||||
|
|
||||||
virtual bool has_ended();
|
virtual bool has_ended();
|
||||||
|
|
||||||
private:
|
virtual void update(float const dt, Input input);
|
||||||
// Contains objects that were colliding in the previous update
|
|
||||||
std::vector<std::pair<btCollisionObject const*, btCollisionObject const*>> bullet_objects_in_collision_previous_frame{};
|
|
||||||
|
|
||||||
public:
|
//! Creates a body and adds it to the world
|
||||||
virtual void update(float const dt, std::map<SDLKey, bool> keys_went_down, std::map<SDLKey, bool> is_pressed, std::map<SDLKey, bool> keys_went_up);
|
template<typename... Args>
|
||||||
|
std::shared_ptr<motor::Body> create_body(Args&&... args){
|
||||||
void update_bullet(float const dt);
|
auto b = std::make_shared<motor::Body>(std::forward<Args>(args)...);
|
||||||
|
add_to_world(b);
|
||||||
void check_collisions();
|
return b;
|
||||||
|
|
||||||
//! A callback for when a collision between two objects occurs.
|
|
||||||
//! TODO: Expand to N-objects?
|
|
||||||
//! The pointers aren't const here so we can call f with the two arguments
|
|
||||||
struct dual_collision_callback {
|
|
||||||
//! The constructor.
|
|
||||||
//! CallbackFunctor must be a valid ctor-parameter for @member f
|
|
||||||
template <typename CallbackFunctor>
|
|
||||||
dual_collision_callback(std::shared_ptr<Body> first_, std::shared_ptr<Body> second_, CallbackFunctor&& c)
|
|
||||||
: first(first_)
|
|
||||||
, second(second_)
|
|
||||||
, f(c)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::shared_ptr<Body> first;
|
|
||||||
std::shared_ptr<Body> second;
|
|
||||||
std::function<void(decltype(first), decltype(second))> f;
|
|
||||||
|
|
||||||
void operator()() {
|
|
||||||
f(first, second);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct single_collision_callback {
|
|
||||||
template <typename CallbackFunctor>
|
|
||||||
single_collision_callback(std::shared_ptr<Body> b_, CallbackFunctor&& c)
|
|
||||||
: b(b_)
|
|
||||||
, f(c)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::shared_ptr<Body> b;
|
|
||||||
std::function<void(decltype(b))> f;
|
|
||||||
|
|
||||||
void operator()() {
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void register_on_enter_collision_callback(dual_collision_callback&& c){
|
|
||||||
on_enter_dual_collision_callback.emplace_back(std::move(c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_on_exit_collision_callback(dual_collision_callback&& c){
|
|
||||||
on_exit_dual_collision_callback.emplace_back(std::move(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_on_enter_collision_callback(single_collision_callback&& c){
|
|
||||||
on_enter_single_collision_callback.emplace_back(std::move(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_on_exit_collision_callback(single_collision_callback&& c){
|
|
||||||
on_exit_single_collision_callback.emplace_back(std::move(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<dual_collision_callback> on_enter_dual_collision_callback{};
|
|
||||||
std::vector<dual_collision_callback> on_exit_dual_collision_callback{};
|
|
||||||
std::vector<single_collision_callback> on_enter_single_collision_callback{};
|
|
||||||
std::vector<single_collision_callback> on_exit_single_collision_callback{};
|
|
||||||
|
|
||||||
void bullet_objects_entered_collision(btCollisionObject const* x, btCollisionObject const* y){
|
|
||||||
for(auto& c : on_enter_dual_collision_callback){
|
|
||||||
if(order_agnostic_equal(c.first->get_physical_body(), c.second->get_physical_body(), x, y)){
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& c : on_enter_single_collision_callback){
|
|
||||||
if(c.b->get_physical_body() == x || c.b->get_physical_body() == y){
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bullet_objects_exited_collision(btCollisionObject const* x, btCollisionObject const* y){
|
|
||||||
for(auto& c : on_exit_dual_collision_callback){
|
|
||||||
if(order_agnostic_equal(c.first->get_physical_body(), c.second->get_physical_body(), x, y)){
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& c : on_exit_single_collision_callback){
|
|
||||||
if(c.b->get_physical_body() == x || c.b->get_physical_body() == y){
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual void draw();
|
virtual void draw();
|
||||||
|
motor::Body* raycast(moggle::vector2<float> const screen_position) const;
|
||||||
|
|
||||||
|
bool free_camera_mode = false;
|
||||||
|
float camera_speed = 35.0f;
|
||||||
|
float camera_rotation_speed = M_PI * .2f;
|
||||||
|
void handle_camera(float const dt, Input input);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace games
|
} // namespace games
|
||||||
|
|
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
project(onegame)
|
project(onegame)
|
||||||
|
|
||||||
find_package(Boost 1.48 REQUIRED)
|
find_package(Boost 1.48 COMPONENTS chrono REQUIRED)
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
|
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
|
@ -55,9 +55,9 @@ include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/../motor/contrib/freetype-gl")
|
||||||
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/../motor/contrib/")
|
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/../motor/contrib/")
|
||||||
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/../motor/moggle/include")
|
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/../motor/moggle/include")
|
||||||
|
|
||||||
add_library(onegame_common Base.cpp)
|
add_library(onegame_common Base.cpp physics.cpp ai_world.cpp)
|
||||||
set(all_friggin_libraries onegame_common ${boost} ${motor} ${moggle} ${assimp} ${zlib} ${opengl} ${sdl} ${openal} ${alure} ${graphics_libs} ${os_libs} ${glew})
|
set(all_friggin_libraries onegame_common ${boost} ${motor} ${moggle} ${assimp} ${zlib} ${opengl} ${sdl} ${openal} ${alure} ${graphics_libs} ${os_libs} ${glew})
|
||||||
|
|
||||||
file(GLOB beamer_sources "beamer/*.cpp")
|
file(GLOB client_sources "client/*.cpp")
|
||||||
add_executable(beamer beamer_main.cpp ${beamer_sources})
|
add_executable(client client_main.cpp ${client_sources})
|
||||||
target_link_libraries(beamer ${all_friggin_libraries})
|
target_link_libraries(client ${all_friggin_libraries} websockets)
|
||||||
|
|
25
src/ai_world.cpp
Normal file
25
src/ai_world.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "ai_world.hpp"
|
||||||
|
|
||||||
|
#include <motor/basic/body.hpp>
|
||||||
|
#include "physics.hpp"
|
||||||
|
#include <motor/basic/scene.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace motor {
|
||||||
|
void AIWorld::update(float dt, Input& input, World& world){
|
||||||
|
auto bodies_copy = bodies;
|
||||||
|
for(auto& b : bodies_copy){
|
||||||
|
if(b->ai){
|
||||||
|
b->ai->update(dt, {*b, input, world});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIWorld::add(std::shared_ptr<Body> b){
|
||||||
|
astrant::append(bodies, {b});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIWorld::remove(std::shared_ptr<Body> b){
|
||||||
|
astrant::remove_element(bodies, b);
|
||||||
|
}
|
||||||
|
}
|
21
src/ai_world.hpp
Normal file
21
src/ai_world.hpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct Input;
|
||||||
|
struct World;
|
||||||
|
|
||||||
|
namespace motor {
|
||||||
|
struct Body;
|
||||||
|
|
||||||
|
struct AIWorld {
|
||||||
|
void update(float dt, Input& input, World& world);
|
||||||
|
|
||||||
|
void add(std::shared_ptr<Body> b);
|
||||||
|
void remove(std::shared_ptr<Body> b);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<Body>> bodies;
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,303 +0,0 @@
|
||||||
#include "beamer.hpp"
|
|
||||||
#include "simplex.h"
|
|
||||||
#include "coordinates.h"
|
|
||||||
#include "procedural_textures.h"
|
|
||||||
|
|
||||||
namespace games {
|
|
||||||
using namespace motor;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
Beamer::House::House(){
|
|
||||||
model = std::make_shared<Body>(resource_cache.get_mesh(::bundle.get_model_path() + "house.obj"));
|
|
||||||
model->set_scale({0.2, 0.2, 0.2});
|
|
||||||
}
|
|
||||||
|
|
||||||
Beamer::Planet::Planet(float const waterlevel, float const displacement, Color const watercolor){
|
|
||||||
srand(::time(0));
|
|
||||||
|
|
||||||
{
|
|
||||||
auto watermesh = std::make_shared<Mesh>(::bundle.get_model_path() + "planet.obj");
|
|
||||||
|
|
||||||
auto const & positions = watermesh->geometry->vertices()->attribute("position").buffer<moggle::hvector4<float>>();
|
|
||||||
auto const & colors = watermesh->geometry->vertices()->attribute("color").buffer<moggle::hvector4<float>>();
|
|
||||||
for(unsigned int i = 0; i < positions->size(); ++i){
|
|
||||||
auto& p = positions->at(i);
|
|
||||||
auto& c = colors->at(i);
|
|
||||||
float r = watercolor[0] * (0.5 + 0.5*simplex_noise(1, p[0], p[1], p[2]));
|
|
||||||
float g = watercolor[1] * (0.5 + 0.5*simplex_noise(1, p[0], p[1], p[2]));
|
|
||||||
float b = watercolor[2];
|
|
||||||
c = {r, g, b, 1.0};
|
|
||||||
}
|
|
||||||
colors->mark_dirty();
|
|
||||||
|
|
||||||
water = std::make_shared<Body>(watermesh);
|
|
||||||
water->set_scale({radius*waterlevel, radius*waterlevel, radius*waterlevel});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto planetmesh = std::make_shared<Mesh>(::bundle.get_model_path() + "planet.obj");
|
|
||||||
|
|
||||||
auto vertices = planetmesh->geometry->vertices();
|
|
||||||
auto const & positions = vertices->attribute("position").buffer<moggle::hvector4<float>>();
|
|
||||||
auto const & normals = vertices->attribute("normal").buffer<moggle::vector3<float>>();
|
|
||||||
auto const & colors = vertices->attribute("color").buffer<moggle::hvector4<float>>();
|
|
||||||
|
|
||||||
moggle::buffer<moggle::vector3<float>> texcoordsbuf(positions->size());
|
|
||||||
vertices->attribute("texture_coordinate", std::move(texcoordsbuf));
|
|
||||||
|
|
||||||
auto const & texcoords = planetmesh->geometry->vertices()->attribute("texture_coordinate").buffer<moggle::vector3<float>>();
|
|
||||||
for(unsigned int i = 0; i < positions->size(); ++i){
|
|
||||||
auto& p = positions->at(i);
|
|
||||||
auto& n = normals->at(i);
|
|
||||||
auto& c = colors->at(i);
|
|
||||||
c = {0,0,0,0};
|
|
||||||
auto& tc= texcoords->at(i);
|
|
||||||
|
|
||||||
auto sp = to_spherical(moggle::vector3<float>{p[0], p[1], p[2]});
|
|
||||||
tc = {0.5 * sp[1] * M_1_PI, sp[2] * M_1_PI + 0.5};
|
|
||||||
if(tc[0] < 0) tc[0] += 1.0;
|
|
||||||
|
|
||||||
float const speed = 0.9;
|
|
||||||
float r = simplex_noise(1, p[0]*speed, p[1]*speed, p[2]*speed);
|
|
||||||
p += displacement * r * n;
|
|
||||||
}
|
|
||||||
auto texture = std::make_shared<moggle::texture>(create_noise_for_sphere(4, 4, [](moggle::vector3<float> position) -> moggle::hvector4<float>{
|
|
||||||
float r = simplex_noise(1, position[0], position[1], position[2]);
|
|
||||||
r += 1.0;
|
|
||||||
r *= 0.5;
|
|
||||||
if(r > 1) r = 1;
|
|
||||||
if(r < 0) r = 0;
|
|
||||||
if(r > 0.75)
|
|
||||||
return {r, r, r};
|
|
||||||
else
|
|
||||||
return {0.2, 0.6, 0.5*r};
|
|
||||||
}));
|
|
||||||
planetmesh->material->diffuse_map = texture;
|
|
||||||
positions->mark_dirty();
|
|
||||||
normals->mark_dirty();
|
|
||||||
|
|
||||||
model = std::make_shared<Body>(planetmesh);
|
|
||||||
model->set_scale({radius, radius, radius});
|
|
||||||
}
|
|
||||||
|
|
||||||
int number_of_houses = astrant::random_value(5, 10);
|
|
||||||
for(int i = 0; i < number_of_houses; ++i){
|
|
||||||
House house;
|
|
||||||
|
|
||||||
float phi = astrant::random_value(0.0, 2 * M_PI);
|
|
||||||
float psi = astrant::random_value(-M_PI_2, M_PI_2);
|
|
||||||
|
|
||||||
Position house_pos = from_spherical(moggle::vector3<float>{radius, phi, psi});
|
|
||||||
// COUT << "house at: " << house_pos << std::endl;
|
|
||||||
house.model->set_position(house_pos);
|
|
||||||
|
|
||||||
houses.push_back(house);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Body>> Beamer::Planet::get_all_bodies() const {
|
|
||||||
std::vector<std::shared_ptr<Body>> ret{model, water};
|
|
||||||
for(auto& h : houses){
|
|
||||||
ret.push_back(h.model);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Beamer::Player{
|
|
||||||
// 3D speed, or 2D?
|
|
||||||
typedef moggle::vector3<float> Speed;
|
|
||||||
|
|
||||||
Position position{0.0, 0.0, 5.0};
|
|
||||||
Speed speed{0.0, 1.0, 0.0};
|
|
||||||
float time{0};
|
|
||||||
float flight_height{5.0};
|
|
||||||
|
|
||||||
void update(float dt){
|
|
||||||
time += dt;
|
|
||||||
|
|
||||||
// move
|
|
||||||
position += dt*speed;
|
|
||||||
|
|
||||||
// clamp to sphere (we will later set it to its radius)
|
|
||||||
normalize(position);
|
|
||||||
|
|
||||||
// accelerator with noise
|
|
||||||
float noisespeed = 0.03;
|
|
||||||
float x = simplex_noise(3, noisespeed*time, 0, 0);
|
|
||||||
float y = simplex_noise(3, 0, noisespeed*time, 0);
|
|
||||||
float z = simplex_noise(3, 0, 0, noisespeed*time);
|
|
||||||
moggle::vector3<float> change{x, y, z};
|
|
||||||
speed += 100.0 * dt * change;
|
|
||||||
|
|
||||||
// make speed follow the sphere
|
|
||||||
float p = dot(speed, position);
|
|
||||||
speed -= p * moggle::vector3<float>(position);
|
|
||||||
normalize(speed);
|
|
||||||
|
|
||||||
// put the ufo in the air :)
|
|
||||||
position *= flight_height;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool Beamer::has_ended(){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Beamer::reset_camera(){
|
|
||||||
scene->camera.set_perspective(80.0f, 4.0f/3.0f, 1.0f, 1000.0f);
|
|
||||||
scene->camera.set_position({0, 0, 5});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Beamer::reset_players(){
|
|
||||||
player.reset(new Player());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Beamer::reset(){
|
|
||||||
reset_camera();
|
|
||||||
reset_players();
|
|
||||||
}
|
|
||||||
|
|
||||||
Beamer::Beamer(int window_width_, int window_height_)
|
|
||||||
: Base(window_width_, window_height_)
|
|
||||||
, player(new Player())
|
|
||||||
{
|
|
||||||
{
|
|
||||||
PointLight p{Position{0.f, 0.0f, 8.0f, 1.0f}, 200.0f, Color{1, 0, 0, 1}};
|
|
||||||
scene->add(std::make_shared<PointLight>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
PointLight p{Position{-4.f, -4.0f, -6.0f, 1.0f}, 200.0f, Color{0, 0, 1, 1}};
|
|
||||||
scene->add(std::make_shared<PointLight>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
PointLight p{Position{4.f, -4.0f, -6.0f, 1.0f}, 200.0f, Color{0, 1, 0, 1}};
|
|
||||||
scene->add(std::make_shared<PointLight>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
PointLight p{Position{0.f, 6.0f, -6.0f, 1.0f}, 200.0f, Color{1, 1, 1, 1}};
|
|
||||||
scene->add(std::make_shared<PointLight>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
reset();
|
|
||||||
|
|
||||||
for(auto& body : planet.get_all_bodies()){
|
|
||||||
scene->add(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Beamer::~Beamer() = default;
|
|
||||||
|
|
||||||
void Beamer::reset_effects(){
|
|
||||||
game_speed = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Beamer::handle_players(float const dt, map<SDLKey, bool> is_pressed){
|
|
||||||
constexpr float paddle_rotation_speed = M_PI*2.0f;
|
|
||||||
float const paddle_rotation = paddle_rotation_speed * dt;
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_UP]){
|
|
||||||
for(auto& model : planet.get_all_bodies()){
|
|
||||||
model->add_pitch(paddle_rotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_DOWN]){
|
|
||||||
for(auto& model : planet.get_all_bodies()){
|
|
||||||
model->add_pitch(-paddle_rotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_LEFT]){
|
|
||||||
for(auto& model : planet.get_all_bodies()){
|
|
||||||
model->add_roll(-paddle_rotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_RIGHT]){
|
|
||||||
for(auto& model : planet.get_all_bodies()){
|
|
||||||
model->add_roll(paddle_rotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_k]){
|
|
||||||
scene->update_shader_pipeline();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool planet_dirty = false;
|
|
||||||
if(is_pressed[SDLK_z] && !is_pressed[SDLK_LSHIFT]){
|
|
||||||
waterlevel += 3.0*dt;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_z] && is_pressed[SDLK_LSHIFT]){
|
|
||||||
waterlevel -= 3.0*dt;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_x] && !is_pressed[SDLK_LSHIFT]){
|
|
||||||
displacement += 3.0*dt;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_x] && is_pressed[SDLK_LSHIFT]){
|
|
||||||
displacement -= 3.0*dt;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_r] && !is_pressed[SDLK_LSHIFT]){
|
|
||||||
watercolor[0] += 0.2;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_r] && is_pressed[SDLK_LSHIFT]){
|
|
||||||
watercolor[0] -= 0.2;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_g] && !is_pressed[SDLK_LSHIFT]){
|
|
||||||
watercolor[1] += 0.2;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_g] && is_pressed[SDLK_LSHIFT]){
|
|
||||||
watercolor[1] -= 0.2;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_b] && !is_pressed[SDLK_LSHIFT]){
|
|
||||||
watercolor[2] += 0.2;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_pressed[SDLK_b] && is_pressed[SDLK_LSHIFT]){
|
|
||||||
watercolor[2] -= 0.2;
|
|
||||||
planet_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(planet_dirty){
|
|
||||||
for(auto const& body : planet.get_all_bodies()){
|
|
||||||
scene->remove(body);
|
|
||||||
}
|
|
||||||
planet = Planet(waterlevel, displacement, watercolor);
|
|
||||||
for(auto const& body : planet.get_all_bodies()){
|
|
||||||
scene->add(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Beamer::update(float const dt, map<SDLKey, bool> keys_went_down, map<SDLKey, bool> is_pressed, map<SDLKey, bool> keys_went_up){
|
|
||||||
Base::update(game_speed*dt, keys_went_down, is_pressed, keys_went_up);
|
|
||||||
handle_players(game_speed*dt, is_pressed);
|
|
||||||
player->update(game_speed*dt);
|
|
||||||
|
|
||||||
scene->camera.set_position(player->position);
|
|
||||||
scene->camera.look_at({0, 0, 0}, player->speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <motor/sound/sound.hpp>
|
|
||||||
#include <motor/basic/texture_label.hpp>
|
|
||||||
|
|
||||||
#include "../Base.hpp"
|
|
||||||
|
|
||||||
namespace games {
|
|
||||||
using namespace motor;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct check_type {
|
|
||||||
template <typename U>
|
|
||||||
bool operator()(shared_ptr<U> const& p){
|
|
||||||
return (dynamic_pointer_cast<T>(p) != nullptr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Beamer : public Base {
|
|
||||||
static constexpr char bundle_name[] = "beamer";
|
|
||||||
|
|
||||||
struct House{
|
|
||||||
std::shared_ptr<Body> model;
|
|
||||||
House();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Planet {
|
|
||||||
float radius{2.5};
|
|
||||||
std::shared_ptr<Body> model;
|
|
||||||
std::shared_ptr<Body> water;
|
|
||||||
|
|
||||||
std::vector<House> houses;
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Body>> get_all_bodies() const;
|
|
||||||
Planet(float const waterlevel, float const displacement, Color const watercolor);
|
|
||||||
};
|
|
||||||
|
|
||||||
float waterlevel = 0.7;
|
|
||||||
float displacement = 0.2;
|
|
||||||
Color watercolor = {0.0, 1.0, 1.0, 1.0};
|
|
||||||
Planet planet{waterlevel, displacement, watercolor};
|
|
||||||
|
|
||||||
struct Player;
|
|
||||||
std::unique_ptr<Player> player;
|
|
||||||
|
|
||||||
float game_speed{1.0};
|
|
||||||
|
|
||||||
Beamer(int window_width, int window_height);
|
|
||||||
~Beamer();
|
|
||||||
|
|
||||||
virtual bool has_ended();
|
|
||||||
virtual void update(float const dt, map<SDLKey, bool> keys_went_down, map<SDLKey, bool> is_pressed, map<SDLKey, bool> keys_went_up);
|
|
||||||
|
|
||||||
void reset_camera();
|
|
||||||
void reset_players();
|
|
||||||
void reset_effects();
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
void handle_players(float const dt, map<SDLKey, bool> is_pressed);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace games
|
|
|
@ -1,45 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <moggle/math/matrix.hpp>
|
|
||||||
#include <astrant-extensions/stream.hpp>
|
|
||||||
|
|
||||||
/*
|
|
||||||
Spherical coordinates: (r, phi1, phi2)
|
|
||||||
where r is the radius, phi1 rotation through y-axis, phi2 rotation determining height
|
|
||||||
This way we can see the sphere as something 2-dimensional (r=1).
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
moggle::vector3<T> from_spherical(moggle::vector3<T> const & p){
|
|
||||||
return {
|
|
||||||
p[0] * cos(p[2]) * cos(p[1]),
|
|
||||||
p[0] * sin(p[2]),
|
|
||||||
p[0] * cos(p[2]) * sin(p[1])
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
moggle::vector3<T> to_spherical(moggle::vector3<T> const & p){
|
|
||||||
float r = sqrt(p[0]*p[0] + p[1]*p[1] + p[2]*p[2]);
|
|
||||||
if(r == 0) return {0.0, 0.0, 0.0};
|
|
||||||
return {
|
|
||||||
r,
|
|
||||||
atan2(p[2], p[0]),
|
|
||||||
asin(p[1] / r)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void test(){
|
|
||||||
for(unsigned int i = 0; i < 20; ++i){
|
|
||||||
auto f = [](moggle::vector3<float> p){return from_spherical(to_spherical(p));};
|
|
||||||
auto g = [](moggle::vector3<float> p){return to_spherical(from_spherical(p));};
|
|
||||||
|
|
||||||
moggle::vector3<float> p{
|
|
||||||
rand() / float(RAND_MAX) - 0.5,
|
|
||||||
rand() / float(RAND_MAX) - 0.5,
|
|
||||||
rand() / float(RAND_MAX) - 0.5
|
|
||||||
};
|
|
||||||
COUT << p << "\n" << f(p) << "\n" << g(p) << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <memory>
|
|
||||||
#include <moggle/core/gl.hpp>
|
|
||||||
#include <moggle/core/texture.hpp>
|
|
||||||
|
|
||||||
#include "coordinates.h"
|
|
||||||
#include "simplex.h"
|
|
||||||
|
|
||||||
// takes size of texture (width x height), and a generator function, which is given positions on the sphere, and should return some kind of pixel
|
|
||||||
template <typename F>
|
|
||||||
inline moggle::texture create_noise_for_sphere(int width, int height, F const & f){
|
|
||||||
std::unique_ptr<GLubyte[]> data(new GLubyte[4 * width * height]);
|
|
||||||
|
|
||||||
auto const & generator = f;
|
|
||||||
|
|
||||||
for(int y = 0; y < height; ++y){
|
|
||||||
for(int x = 0; x < width; ++x){
|
|
||||||
GLubyte* pixel = &data[4 * (y*width + x)];
|
|
||||||
|
|
||||||
moggle::vector3<float> sp{1.0, 2 * M_PI * x/double(width), M_PI * (y/double(height) - 0.5)};
|
|
||||||
auto position = from_spherical(sp);
|
|
||||||
auto result = generator(position);
|
|
||||||
pixel[0] = 255*result[0];
|
|
||||||
pixel[1] = 255*result[1];
|
|
||||||
pixel[2] = 255*result[2];
|
|
||||||
pixel[3] = 255*result[3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
moggle::texture t(width, height);
|
|
||||||
t.bind();
|
|
||||||
moggle::gl::texture_image2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.get());
|
|
||||||
t.set_parameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
t.set_parameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
|
@ -1,131 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
// I couldn't find the one we had for the old sdlgame, but i found this one
|
|
||||||
|
|
||||||
static float grad[12][3] = {
|
|
||||||
{1.0,1.0,0.0},{-1.0,1.0,0.0},{1.0,-1.0,0.0},{-1.0,-1.0,0.0},
|
|
||||||
{1.0,0.0,1.0},{-1.0,0.0,1.0},{1.0,0.0,-1.0},{-1.0,0.0,-1.0},
|
|
||||||
{0.0,1.0,1.0},{0.0,-1.0,1.0},{0.0,1.0,-1.0},{0.0,-1.0,-1.0}
|
|
||||||
};
|
|
||||||
|
|
||||||
static int perm[512] = {151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180};
|
|
||||||
|
|
||||||
inline float dot(float x, float y, float z, float* g){
|
|
||||||
return x*g[0] + y*g[1] + z*g[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float noise(float xin, float yin, float zin){
|
|
||||||
float F3, G3, t, X0, Y0, Z0, x0, y0, z0, s, x1, y1, z1, x2, y2, z2, x3, y3, z3, t0, t1, t2, t3, n0, n1, n2, n3;
|
|
||||||
int i, j, k, ii, jj, kk, i1, j1, k1, i2, j2, k2, gi0, gi1, gi2, gi3;
|
|
||||||
|
|
||||||
F3 = 1.0f/3.0f;
|
|
||||||
s = (xin+yin+zin)*F3;
|
|
||||||
i = std::floor(xin+s);
|
|
||||||
j = std::floor(yin+s);
|
|
||||||
k = std::floor(zin+s);
|
|
||||||
G3 = 1.0/6.0;
|
|
||||||
t = (i+j+k)*G3;
|
|
||||||
X0 = i-t;
|
|
||||||
Y0 = j-t;
|
|
||||||
Z0 = k-t;
|
|
||||||
x0 = xin-X0;
|
|
||||||
y0 = yin-Y0;
|
|
||||||
z0 = zin-Z0;
|
|
||||||
|
|
||||||
if(x0 >= y0){
|
|
||||||
if(y0 >= z0){
|
|
||||||
i1=1; j1=0; k1=0; i2=1; j2=1; k2=0;
|
|
||||||
}
|
|
||||||
else if(x0 >= z0){
|
|
||||||
i1=1; j1=0; k1=0; i2=1; j2=0; k2=1;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
i1=0; j1=0; k1=1; i2=1; j2=0; k2=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
if(y0 < z0){
|
|
||||||
i1=0; j1=0; k1=1; i2=0; j2=1; k2=1;
|
|
||||||
}
|
|
||||||
else if(x0 < z0){
|
|
||||||
i1=0; j1=1; k1=0; i2=0; j2=1; k2=1;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
i1=0; j1=1; k1=0; i2=1; j2=1; k2=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x1 = x0 - i1 + G3;
|
|
||||||
y1 = y0 - j1 + G3;
|
|
||||||
z1 = z0 - k1 + G3;
|
|
||||||
x2 = x0 - i2 + 2.0*G3;
|
|
||||||
y2 = y0 - j2 + 2.0*G3;
|
|
||||||
z2 = z0 - k2 + 2.0*G3;
|
|
||||||
x3 = x0 - 1.0 + 3.0*G3;
|
|
||||||
y3 = y0 - 1.0 + 3.0*G3;
|
|
||||||
z3 = z0 - 1.0 + 3.0*G3;
|
|
||||||
|
|
||||||
ii = i & 255;
|
|
||||||
jj = j & 255;
|
|
||||||
kk = k & 255;
|
|
||||||
|
|
||||||
gi0 = perm[ii+perm[jj+perm[kk]]] % 12;
|
|
||||||
gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1]]] % 12;
|
|
||||||
gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2]]] % 12;
|
|
||||||
gi3 = perm[ii+1+perm[jj+1+perm[kk+1]]] % 12;
|
|
||||||
|
|
||||||
t0 = 0.6 - x0*x0 - y0*y0 - z0*z0;
|
|
||||||
if(t0<0){
|
|
||||||
n0 = 0.0;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
t0 *= t0;
|
|
||||||
n0 = t0 * t0 * dot(x0, y0, z0, grad[gi0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
t1 = 0.6 - x1*x1 - y1*y1 - z1*z1;
|
|
||||||
if(t1<0){
|
|
||||||
n1 = 0.0;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
t1 *= t1;
|
|
||||||
n1 = t1 * t1 * dot(x1, y1, z1, grad[gi1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
t2 = 0.6 - x2*x2 - y2*y2 - z2*z2;
|
|
||||||
if(t2<0){
|
|
||||||
n2 = 0.0;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
t2 *= t2;
|
|
||||||
n2 = t2 * t2 * dot(x2, y2, z2, grad[gi2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
t3 = 0.6 - x3*x3 - y3*y3 - z3*z3;
|
|
||||||
if(t3<0){
|
|
||||||
n3 = 0.0;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
t3 *= t3;
|
|
||||||
n3 = t3 * t3 * dot(x3, y3, z3, grad[gi3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The result is scaled to stay just inside [-1,1]
|
|
||||||
// source: http://webstaff.itn.liu.se/~stegu/simplexnoise/
|
|
||||||
return 32.0*(n0 + n1 + n2 + n3);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float simplex_noise(int octaves, float x, float y, float z){
|
|
||||||
float value = 0.0;
|
|
||||||
int i;
|
|
||||||
for(i=0; i<octaves; i++){
|
|
||||||
value += noise(
|
|
||||||
x*pow(2, i),
|
|
||||||
y*pow(2, i),
|
|
||||||
z*pow(2, i)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
109
src/client/client.cpp
Normal file
109
src/client/client.cpp
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
#include "client.hpp"
|
||||||
|
|
||||||
|
namespace games {
|
||||||
|
int callback_func(libwebsocket_context * context, libwebsocket * wsi, libwebsocket_callback_reasons reason, void * user, void * in, size_t len){
|
||||||
|
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2 + LWS_SEND_BUFFER_POST_PADDING];
|
||||||
|
buf[LWS_SEND_BUFFER_PRE_PADDING] = 'a';
|
||||||
|
buf[LWS_SEND_BUFFER_PRE_PADDING + 1] = '\0';
|
||||||
|
switch(reason){
|
||||||
|
case LWS_CALLBACK_ESTABLISHED:
|
||||||
|
libwebsocket_callback_on_writable(context, wsi);
|
||||||
|
break;
|
||||||
|
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||||
|
std::cout << std::string(static_cast<char*>(in), len) << std::endl;
|
||||||
|
break;
|
||||||
|
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||||
|
libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 1, LWS_WRITE_TEXT);
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static libwebsocket_protocols protocols[] = {
|
||||||
|
{ "uberclient", callback_func, 0 },
|
||||||
|
{ NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Client::has_ended(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Client::Client(int window_width_, int window_height_, std::shared_ptr<Base>& active_base_)
|
||||||
|
: Base(window_width_, window_height_, active_base_)
|
||||||
|
{
|
||||||
|
// *** websockets code ***
|
||||||
|
lws_context_creation_info info;
|
||||||
|
memset(&info, 0, sizeof info);
|
||||||
|
|
||||||
|
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||||
|
info.protocols = protocols;
|
||||||
|
info.gid = -1;
|
||||||
|
info.uid = -1;
|
||||||
|
|
||||||
|
context = libwebsocket_create_context(&info);
|
||||||
|
assert(context);
|
||||||
|
|
||||||
|
std::string address = "127.0.0.1";
|
||||||
|
wsi = libwebsocket_client_connect(context, address.c_str(), 7681, false, "/", address.c_str(), "origin", "uberclient", -1);
|
||||||
|
assert(wsi);
|
||||||
|
// *** ***
|
||||||
|
|
||||||
|
{
|
||||||
|
motor::DirectionalLight p{motor::Position{0, 0, 20}, 1.0f, motor::Color{1, 1, 1, 1}};
|
||||||
|
scene->add(std::make_shared<motor::DirectionalLight>(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
world.physics.set_gravity({0.0, 0.0, 0.0});
|
||||||
|
|
||||||
|
scene->camera.set_perspective(80.0f, 4.0f/3.0f, .5f, 50.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::handle_input(float dt, Input input){
|
||||||
|
using motor::Position;
|
||||||
|
|
||||||
|
if(input.keys_went_down[SDLK_u]){
|
||||||
|
//Iterates over drawing the physics and normal world, drawing only the physics world, and drawing only the normal world.
|
||||||
|
if(!draw_physics_world){
|
||||||
|
draw_physics_world = true;
|
||||||
|
} else {
|
||||||
|
if(draw_only_physics_world){
|
||||||
|
draw_physics_world = false;
|
||||||
|
draw_only_physics_world = false;
|
||||||
|
} else {
|
||||||
|
draw_only_physics_world = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.keys_went_down[SDLK_k]){
|
||||||
|
scene->update_shader_pipeline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::draw(){
|
||||||
|
Base::draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::update(float const dt, Input input){
|
||||||
|
Base::update(dt, input);
|
||||||
|
handle_input(dt, input);
|
||||||
|
|
||||||
|
scene->camera.set_position({0, 0, 20});
|
||||||
|
|
||||||
|
const float poll_interval = 5.0;
|
||||||
|
poll_time += dt;
|
||||||
|
|
||||||
|
int ret = libwebsocket_service(context, 10);
|
||||||
|
if(ret < 0) {
|
||||||
|
CERR << "ERROR: libwebsocket returns < 0\n";
|
||||||
|
}
|
||||||
|
if(poll_time >= poll_interval){
|
||||||
|
libwebsocket_callback_on_writable(context, wsi);
|
||||||
|
poll_time -= poll_interval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Client::~Client(){
|
||||||
|
libwebsocket_context_destroy(context);
|
||||||
|
}
|
||||||
|
}
|
29
src/client/client.hpp
Normal file
29
src/client/client.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <motor/sound/sound.hpp>
|
||||||
|
#include <motor/basic/texture_label.hpp>
|
||||||
|
|
||||||
|
#include <lib/libwebsockets.h>
|
||||||
|
|
||||||
|
#include "../Base.hpp"
|
||||||
|
#include "../input.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace games {
|
||||||
|
struct Client : public Base {
|
||||||
|
static constexpr char bundle_name[] = "client";
|
||||||
|
libwebsocket_context * context{nullptr};
|
||||||
|
libwebsocket * wsi{nullptr};
|
||||||
|
float poll_time{0.0};
|
||||||
|
|
||||||
|
Client(int window_width, int window_height, std::shared_ptr<Base>& active_base);
|
||||||
|
|
||||||
|
virtual bool has_ended();
|
||||||
|
virtual void update(float const dt, Input input);
|
||||||
|
virtual void draw();
|
||||||
|
|
||||||
|
void handle_input(float const dt, Input input);
|
||||||
|
|
||||||
|
~Client();
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
#include "generic_main.hpp"
|
#include "generic_main.hpp"
|
||||||
#include "beamer/beamer.hpp"
|
#include "client/client.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
typedef games::Beamer Game;
|
typedef games::Client Game;
|
||||||
|
|
||||||
constexpr char Game::bundle_name[];
|
constexpr char Game::bundle_name[];
|
||||||
motor::Bundle const bundle(Game::bundle_name);
|
motor::Bundle const bundle(Game::bundle_name);
|
|
@ -6,14 +6,22 @@
|
||||||
#include <moggle/core/gl.hpp>
|
#include <moggle/core/gl.hpp>
|
||||||
#include <motor/sound/sound.hpp>
|
#include <motor/sound/sound.hpp>
|
||||||
|
|
||||||
|
#include "Base.hpp"
|
||||||
|
|
||||||
#ifndef __unused
|
#ifndef __unused
|
||||||
#define __unused __attribute__((unused))
|
#define __unused __attribute__((unused))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::map<void*, std::string> mysterious_pointers;
|
||||||
|
|
||||||
|
#include <motor/sound/sound.hpp>
|
||||||
|
unsigned int motor::al::Buffer::nr_buffers = 0;
|
||||||
|
unsigned int motor::al::Source::nr_sources = 0;
|
||||||
|
|
||||||
template <typename Game>
|
template <typename Game>
|
||||||
struct GenericMain {
|
struct GenericMain {
|
||||||
private:
|
private:
|
||||||
motor::AL al_context;
|
motor::al::AL al_context;
|
||||||
|
|
||||||
int screen_width = 0;
|
int screen_width = 0;
|
||||||
int screen_height = 0;
|
int screen_height = 0;
|
||||||
|
@ -31,9 +39,9 @@ private:
|
||||||
|
|
||||||
SDL_Surface * screen = nullptr;
|
SDL_Surface * screen = nullptr;
|
||||||
if(fullscreen){
|
if(fullscreen){
|
||||||
screen = SDL_SetVideoMode(0, 0, 24, SDL_OPENGL | SDL_FULLSCREEN);
|
screen = SDL_SetVideoMode(0, 0, 32, SDL_OPENGL | SDL_FULLSCREEN);
|
||||||
} else {
|
} else {
|
||||||
screen = SDL_SetVideoMode(wanted_resolution_width, wanted_resolution_height, 24, SDL_OPENGL);
|
screen = SDL_SetVideoMode(wanted_resolution_width, wanted_resolution_height, 32, SDL_OPENGL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!screen){
|
if(!screen){
|
||||||
|
@ -63,10 +71,12 @@ public:
|
||||||
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
void main(T... args){
|
void main(T... args){
|
||||||
std::unique_ptr<Game> game{new Game {screen_width, screen_height, args...}};
|
std::shared_ptr<games::Base> game{new Game {screen_width, screen_height, game, args...}};
|
||||||
|
std::weak_ptr<games::Base> previous_game = game;
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
std::map<SDLKey, bool> keys_pressed;
|
|
||||||
|
Input input;
|
||||||
|
|
||||||
// for calculation fps
|
// for calculation fps
|
||||||
auto fps_time = SDL_GetTicks();
|
auto fps_time = SDL_GetTicks();
|
||||||
|
@ -75,8 +85,10 @@ public:
|
||||||
auto now = SDL_GetTicks();
|
auto now = SDL_GetTicks();
|
||||||
while (!done) {
|
while (!done) {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
std::map<SDLKey, bool> keys_went_down;
|
input.keys_went_down.clear();
|
||||||
std::map<SDLKey, bool> keys_went_up;
|
input.keys_went_up.clear();
|
||||||
|
input.mouse.went_down.clear();
|
||||||
|
input.mouse.went_up.clear();
|
||||||
|
|
||||||
bool any_key_pressed = false;
|
bool any_key_pressed = false;
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
|
@ -87,8 +99,8 @@ public:
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
{
|
{
|
||||||
auto const& key = event.key.keysym.sym;
|
auto const& key = event.key.keysym.sym;
|
||||||
keys_pressed[key] = true;
|
input.keys_pressed[key] = true;
|
||||||
keys_went_down[key] = true;
|
input.keys_went_down[key] = true;
|
||||||
if (key == SDLK_ESCAPE){
|
if (key == SDLK_ESCAPE){
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
|
@ -99,8 +111,37 @@ public:
|
||||||
{
|
{
|
||||||
any_key_pressed = true;
|
any_key_pressed = true;
|
||||||
auto const& key = event.key.keysym.sym;
|
auto const& key = event.key.keysym.sym;
|
||||||
keys_pressed[key] = false;
|
input.keys_pressed[key] = false;
|
||||||
keys_went_up[key] = true;
|
input.keys_went_up[key] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
{
|
||||||
|
input.mouse.difference[0] = event.motion.x - input.mouse.position[0];
|
||||||
|
input.mouse.difference[1] = event.motion.y - input.mouse.position[1];
|
||||||
|
input.mouse.position[0] = event.motion.x;
|
||||||
|
input.mouse.position[1] = event.motion.y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
{
|
||||||
|
auto const b = Input::Mouse::button_from_sdl_button(event.button.button);
|
||||||
|
input.mouse.is_pressed[b] = true;
|
||||||
|
input.mouse.went_down[b] = true;
|
||||||
|
input.mouse.position[0] = event.button.x;
|
||||||
|
input.mouse.position[1] = event.button.y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
{
|
||||||
|
auto const b = Input::Mouse::button_from_sdl_button(event.button.button);
|
||||||
|
input.mouse.is_pressed[b] = false;
|
||||||
|
input.mouse.went_up[b] = true;
|
||||||
|
input.mouse.position[0] = event.button.x;
|
||||||
|
input.mouse.position[1] = event.button.y;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,22 +151,29 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if(any_key_pressed && game->has_ended()){
|
if(any_key_pressed && game->has_ended()){
|
||||||
game.reset(new Game {screen_width, screen_height, args...});
|
game.reset(new Game {screen_width, screen_height, game, args...});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(previous_game.expired()){
|
||||||
|
previous_game = game;
|
||||||
|
now = SDL_GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
float const dt = (SDL_GetTicks() - now)/1000.0f;
|
float const dt = (SDL_GetTicks() - now)/1000.0f;
|
||||||
now = SDL_GetTicks();
|
now = SDL_GetTicks();
|
||||||
game->update(dt, keys_went_down, keys_pressed, keys_went_up);
|
game->update(dt, input);
|
||||||
game->draw();
|
game->draw();
|
||||||
SDL_GL_SwapBuffers();
|
SDL_GL_SwapBuffers();
|
||||||
|
|
||||||
++frame_count_in_second;
|
++frame_count_in_second;
|
||||||
// one second has past
|
// one second has past
|
||||||
if(SDL_GetTicks() - fps_time > 1000.0f){
|
if(SDL_GetTicks() - fps_time > 30.0f * 1000.0f){
|
||||||
fps_time = SDL_GetTicks();
|
fps_time = SDL_GetTicks();
|
||||||
COUT << "Frames in last second: " << frame_count_in_second << std::endl;
|
COUT << "Average FPS: " << frame_count_in_second/30.0f << std::endl;
|
||||||
frame_count_in_second = 0;
|
frame_count_in_second = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.mouse.difference = moggle::vector2<float>{0,0};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
#include <motor/basic/bundle.hpp>
|
#include <motor/basic/bundle.hpp>
|
||||||
|
#include <motor/basic/configuration.hpp>
|
||||||
|
|
||||||
extern motor::Bundle const bundle;
|
extern motor::Bundle const bundle;
|
||||||
|
extern Configuration const configuration;
|
||||||
|
|
||||||
|
extern std::map<void*, std::string> mysterious_pointers;
|
||||||
|
|
44
src/input.hpp
Normal file
44
src/input.hpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <SDL/SDL.h>
|
||||||
|
|
||||||
|
#include <moggle/math/matrix.hpp>
|
||||||
|
|
||||||
|
struct Input {
|
||||||
|
std::map<SDLKey, bool> keys_pressed{};
|
||||||
|
std::map<SDLKey, bool> keys_went_down{};
|
||||||
|
std::map<SDLKey, bool> keys_went_up{};
|
||||||
|
|
||||||
|
struct Mouse {
|
||||||
|
enum Button {
|
||||||
|
left,
|
||||||
|
middle,
|
||||||
|
right,
|
||||||
|
wheelup,
|
||||||
|
wheeldown,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static Button button_from_sdl_button(size_t const sdl_button){
|
||||||
|
switch(sdl_button){
|
||||||
|
case SDL_BUTTON_LEFT: return Button::left;
|
||||||
|
case SDL_BUTTON_MIDDLE: return Button::middle;
|
||||||
|
case SDL_BUTTON_RIGHT: return Button::right;
|
||||||
|
case SDL_BUTTON_WHEELUP: return Button::wheelup;
|
||||||
|
case SDL_BUTTON_WHEELDOWN: return Button::wheeldown;
|
||||||
|
default: {
|
||||||
|
return Mouse::Button(sdl_button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moggle::vector2<float> position{0.0f, 0.0f};
|
||||||
|
moggle::vector2<float> difference{0.0f, 0.0f};
|
||||||
|
|
||||||
|
std::map<Button, bool> went_down{};
|
||||||
|
std::map<Button, bool> is_pressed{};
|
||||||
|
std::map<Button, bool> went_up{};
|
||||||
|
};
|
||||||
|
|
||||||
|
Mouse mouse{};
|
||||||
|
};
|
185
src/physics.cpp
Normal file
185
src/physics.cpp
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
#include "physics.hpp"
|
||||||
|
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
namespace motor {
|
||||||
|
|
||||||
|
void Physics::update(float const dt, size_t const maximum_number_of_steps){
|
||||||
|
in_update = true;
|
||||||
|
|
||||||
|
for(auto & a : attractors){
|
||||||
|
for(auto body : *this){
|
||||||
|
if(!body) continue;
|
||||||
|
auto position = body->getWorldTransform().getOrigin();
|
||||||
|
auto difference = convert<moggle::vector3<float>>(position) - a->position;
|
||||||
|
auto force = dt * a->strength * difference;
|
||||||
|
body->applyCentralImpulse(convert<btVector3>(force));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_bullet(dt, maximum_number_of_steps);
|
||||||
|
check_collisions();
|
||||||
|
|
||||||
|
in_update = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physics::update_bullet(float const dt, size_t const maximum_number_of_steps){
|
||||||
|
dynamics_world->stepSimulation(dt, maximum_number_of_steps);
|
||||||
|
|
||||||
|
debug_draw_up_to_date = false;
|
||||||
|
|
||||||
|
for(auto body : *this){
|
||||||
|
if(!body) continue;
|
||||||
|
if(body->getMotionState()) {
|
||||||
|
if(body->getUserPointer() != nullptr){
|
||||||
|
btTransform trans = body->getWorldTransform();
|
||||||
|
Body* b = static_cast<Body*>(body->getUserPointer());
|
||||||
|
b->sync_from_bullet(trans);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physics::check_collisions(){
|
||||||
|
std::vector<std::pair<btCollisionObject const*, btCollisionObject const*>> bullet_objects_colliding;
|
||||||
|
int const manifolds = dynamics_world->getDispatcher()->getNumManifolds();
|
||||||
|
for(int manifold_index = 0; manifold_index < manifolds; ++manifold_index){
|
||||||
|
auto const manifold = dynamics_world->getDispatcher()->getManifoldByIndexInternal(manifold_index);
|
||||||
|
|
||||||
|
btCollisionObject const* first_object = manifold->getBody0();
|
||||||
|
btCollisionObject const* second_object = manifold->getBody1();
|
||||||
|
|
||||||
|
if(manifold->getNumContacts() > 0){
|
||||||
|
bullet_objects_colliding.emplace_back(first_object, second_object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto const& c : bullet_objects_colliding){
|
||||||
|
if(!astrant::contains(bullet_objects_in_collision_previous_frame, c)){
|
||||||
|
bullet_objects_entered_collision(c.first, c.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto const& c : bullet_objects_in_collision_previous_frame){
|
||||||
|
if(!astrant::contains(bullet_objects_colliding, c)){
|
||||||
|
bullet_objects_exited_collision(c.first, c.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bullet_objects_in_collision_previous_frame = bullet_objects_colliding;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physics::bullet_objects_entered_collision(btCollisionObject const* x, btCollisionObject const* y){
|
||||||
|
for(auto& c : on_enter_dual_collision_callback){
|
||||||
|
if(order_agnostic_equal(c.first->get_physical_body(), c.second->get_physical_body(), x, y)){
|
||||||
|
c();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& c : on_enter_single_collision_callback){
|
||||||
|
if(c.b->get_physical_body() == x || c.b->get_physical_body() == y){
|
||||||
|
c();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& c : on_enter_single_dual_collision_callback){
|
||||||
|
if(c.b->get_physical_body() == x){
|
||||||
|
c(y);
|
||||||
|
} else if (c.b->get_physical_body() == y){
|
||||||
|
c(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physics::bullet_objects_exited_collision(btCollisionObject const* x, btCollisionObject const* y){
|
||||||
|
for(auto& c : on_exit_dual_collision_callback){
|
||||||
|
if(order_agnostic_equal(c.first->get_physical_body(), c.second->get_physical_body(), x, y)){
|
||||||
|
c();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& c : on_exit_single_collision_callback){
|
||||||
|
if(c.b->get_physical_body() == x || c.b->get_physical_body() == y){
|
||||||
|
c();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& c : on_exit_single_dual_collision_callback){
|
||||||
|
if(c.b->get_physical_body() == x){
|
||||||
|
c(y);
|
||||||
|
} else if (c.b->get_physical_body() == y){
|
||||||
|
c(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physics::set_gravity(moggle::vector3<float> gravity){
|
||||||
|
dynamics_world->setGravity(convert<btVector3>(gravity));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physics::add(std::shared_ptr<Body> b){
|
||||||
|
assert(!in_update);
|
||||||
|
assert(b->physics);
|
||||||
|
|
||||||
|
dynamics_world->addRigidBody(b->get_physical_body());
|
||||||
|
debug_draw_up_to_date = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physics::add(std::shared_ptr<Attractor> a){
|
||||||
|
assert(a);
|
||||||
|
attractors.push_back(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physics::remove(std::shared_ptr<Body> b){
|
||||||
|
assert(!in_update);
|
||||||
|
dynamics_world->removeRigidBody(b->get_physical_body());
|
||||||
|
|
||||||
|
auto const remove_callback_dual = [](std::shared_ptr<Body> x, std::vector<dual_collision_callback>& y){
|
||||||
|
y.erase(std::remove_if(y.begin(), y.end(), [&](dual_collision_callback c){
|
||||||
|
return c.first == x || c.second == x;
|
||||||
|
}), y.end());
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const remove_callback_single = [](std::shared_ptr<Body> x, std::vector<single_collision_callback>& y){
|
||||||
|
y.erase(std::remove_if(y.begin(), y.end(), [&](single_collision_callback c){
|
||||||
|
return c.b == x;
|
||||||
|
}), y.end());
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const remove_callback_single_dual = [](std::shared_ptr<Body> x, std::vector<single_dual_collision_callback>& y){
|
||||||
|
y.erase(std::remove_if(y.begin(), y.end(), [&](single_dual_collision_callback c){
|
||||||
|
return c.b == x;
|
||||||
|
}), y.end());
|
||||||
|
};
|
||||||
|
|
||||||
|
remove_callback_dual(b, on_enter_dual_collision_callback);
|
||||||
|
remove_callback_dual(b, on_exit_dual_collision_callback);
|
||||||
|
remove_callback_single(b, on_enter_single_collision_callback);
|
||||||
|
remove_callback_single(b, on_exit_single_collision_callback);
|
||||||
|
remove_callback_single_dual(b, on_enter_single_dual_collision_callback);
|
||||||
|
remove_callback_single_dual(b, on_exit_single_dual_collision_callback);
|
||||||
|
|
||||||
|
debug_draw_up_to_date = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physics::remove(std::shared_ptr<Attractor> a){
|
||||||
|
astrant::remove_element(attractors, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
Body* Physics::raycast(Position const& from, Position const& to) const{
|
||||||
|
btCollisionWorld::ClosestRayResultCallback ray_call(convert<btVector3>(from),convert<btVector3>(to));
|
||||||
|
dynamics_world->rayTest(convert<btVector3>(from), convert<btVector3>(to), ray_call);
|
||||||
|
if (ray_call.hasHit()) {
|
||||||
|
Body* b = static_cast<Body*>(ray_call.m_collisionObject->getUserPointer());
|
||||||
|
btRigidBody const * body = btRigidBody::upcast(ray_call.m_collisionObject);
|
||||||
|
if (body && b) {
|
||||||
|
return b;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
247
src/physics.hpp
Normal file
247
src/physics.hpp
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <motor/basic/body.hpp>
|
||||||
|
#include <motor/basic/bullet_debug_drawer.hpp>
|
||||||
|
|
||||||
|
#include <astrant-extensions/algorithm.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace motor {
|
||||||
|
//! Returns (f(ax, bx) && f(ay, by)) || (f(ax, by) && f(ay, bx))
|
||||||
|
//! Useful for instance when you want to compare two pairs if they contain the same elements, but don't care about the order
|
||||||
|
//! (and we provide an overload for that of course)
|
||||||
|
template <typename First, typename Second, typename Third, typename Fourth, typename CompareFunction>
|
||||||
|
bool order_agnostic_compare(First const& ax, Second const& ay, Third const& bx, Fourth const& by, CompareFunction const& f){
|
||||||
|
return
|
||||||
|
(f(ax, bx) && f(ay, by))
|
||||||
|
||
|
||||||
|
(f(ax, by) && f(ay, bx));
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Figure out what the syntax of this was, then express equal, less{,or equal}, greater{, or equal}.
|
||||||
|
//using order_agnostic_equalness<First, Second, Third, Fourth> = order_agnostic_compare<First, Second, Third, Fourth, std::eq>;
|
||||||
|
|
||||||
|
template <typename First, typename Second, typename Third, typename Fourth>
|
||||||
|
bool order_agnostic_equal(First const& ax, Second const& ay, Third const& bx, Fourth const& by){
|
||||||
|
return ((ax == bx && ay == by) || (ax == by && ay == bx));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename First, typename Second, typename Third, typename Fourth>
|
||||||
|
bool order_agnostic_equal(std::pair<First, Second> const& a, std::pair<Third, Fourth> const& b){
|
||||||
|
return order_agnostic_equalness(a.first, a.second, b.first, b.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Attractor {
|
||||||
|
Position position{0,0,0};
|
||||||
|
float strength{100};
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Interface to bullet,
|
||||||
|
struct Physics {
|
||||||
|
//! iterates over the bodies in the simulation. Assumes all bodies are btRigidBody objects!
|
||||||
|
struct iterator{
|
||||||
|
iterator(std::shared_ptr<btDynamicsWorld> dynamics_world_, int index_)
|
||||||
|
: index(index_)
|
||||||
|
, dynamics_world(dynamics_world_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
iterator& operator++(){
|
||||||
|
++index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator++(int){
|
||||||
|
iterator ret = *this;
|
||||||
|
++*this;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(iterator const & it2){
|
||||||
|
return dynamics_world == it2.dynamics_world && index == it2.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(iterator const & it2){
|
||||||
|
return !(*this == it2);
|
||||||
|
}
|
||||||
|
|
||||||
|
btRigidBody* operator*(){
|
||||||
|
btCollisionObject* obj = dynamics_world->getCollisionObjectArray()[index];
|
||||||
|
btRigidBody* body = btRigidBody::upcast(obj);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
int index{0};
|
||||||
|
std::shared_ptr<btDynamicsWorld> dynamics_world;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! returns body-iterator to the first body
|
||||||
|
iterator begin(){
|
||||||
|
return {dynamics_world, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
//! returns body-iterator after the last body
|
||||||
|
iterator end(){
|
||||||
|
return {dynamics_world, dynamics_world->getNumCollisionObjects()};
|
||||||
|
}
|
||||||
|
|
||||||
|
Physics(){
|
||||||
|
dynamics_world->setDebugDrawer(debug_drawer.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Mesh>> get_debug_draw_result(int const mode) {
|
||||||
|
if(!debug_draw_up_to_date){
|
||||||
|
debug_drawer->clear();
|
||||||
|
debug_drawer->setDebugMode(mode);
|
||||||
|
dynamics_world->debugDrawWorld();
|
||||||
|
debug_drawer->finish();
|
||||||
|
debug_draw_up_to_date = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return debug_drawer->get_meshes();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void update(float const dt, size_t const maximum_number_of_steps);
|
||||||
|
|
||||||
|
//! A callback for when a collision between two objects occurs.
|
||||||
|
//! TODO: Expand to N-objects?
|
||||||
|
//! The pointers aren't const here so we can call f with the two arguments
|
||||||
|
struct dual_collision_callback {
|
||||||
|
//! The constructor.
|
||||||
|
//! CallbackFunctor must be a valid ctor-parameter for @member f
|
||||||
|
template <typename CallbackFunctor>
|
||||||
|
dual_collision_callback(std::shared_ptr<motor::Body> first_, std::shared_ptr<motor::Body> second_, CallbackFunctor&& c)
|
||||||
|
: first(first_)
|
||||||
|
, second(second_)
|
||||||
|
, f(c)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::shared_ptr<motor::Body> first;
|
||||||
|
std::shared_ptr<motor::Body> second;
|
||||||
|
std::function<void(decltype(first), decltype(second))> f;
|
||||||
|
|
||||||
|
void operator()() {
|
||||||
|
f(first, second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct single_collision_callback {
|
||||||
|
template <typename CallbackFunctor>
|
||||||
|
single_collision_callback(std::shared_ptr<motor::Body> b_, CallbackFunctor&& c)
|
||||||
|
: b(b_)
|
||||||
|
, f(c)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::shared_ptr<motor::Body> b;
|
||||||
|
std::function<void(decltype(b))> f;
|
||||||
|
|
||||||
|
void operator()() {
|
||||||
|
f(b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct single_dual_collision_callback {
|
||||||
|
template <typename CallbackFunctor>
|
||||||
|
single_dual_collision_callback(std::shared_ptr<motor::Body> b_, CallbackFunctor&& c)
|
||||||
|
: b(b_)
|
||||||
|
, f(c)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::shared_ptr<motor::Body> b;
|
||||||
|
std::function<void(decltype(b), motor::Body*)> f;
|
||||||
|
|
||||||
|
void operator()(btCollisionObject const* them) {
|
||||||
|
assert(them);
|
||||||
|
if(them->getUserPointer() != nullptr){
|
||||||
|
Body* them_body = static_cast<Body*>(them->getUserPointer());
|
||||||
|
f(b, them_body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void register_on_enter_collision_callback(dual_collision_callback&& c){
|
||||||
|
on_enter_dual_collision_callback.emplace_back(std::move(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_on_exit_collision_callback(dual_collision_callback&& c){
|
||||||
|
on_exit_dual_collision_callback.emplace_back(std::move(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_on_enter_collision_callback(single_collision_callback&& c){
|
||||||
|
on_enter_single_collision_callback.emplace_back(std::move(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_on_exit_collision_callback(single_collision_callback&& c){
|
||||||
|
on_exit_single_collision_callback.emplace_back(std::move(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_on_enter_collision_callback(single_dual_collision_callback&& c){
|
||||||
|
on_enter_single_dual_collision_callback.emplace_back(std::move(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_on_exit_collision_callback(single_dual_collision_callback&& c){
|
||||||
|
on_exit_single_dual_collision_callback.emplace_back(std::move(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Adds an object to the simulation
|
||||||
|
void add(std::shared_ptr<Body> b);
|
||||||
|
|
||||||
|
//! Adds an attractor to the simulation
|
||||||
|
void add(std::shared_ptr<Attractor> a);
|
||||||
|
|
||||||
|
//! Removes object from the simulation, and also removes all the registered callbacks to that object
|
||||||
|
void remove(std::shared_ptr<Body> b);
|
||||||
|
|
||||||
|
//! Adds an attractor to the simulation
|
||||||
|
void remove(std::shared_ptr<Attractor> a);
|
||||||
|
|
||||||
|
//! Sets the force that is applied to all bodies each tick
|
||||||
|
void set_gravity(moggle::vector3<float> gravity);
|
||||||
|
|
||||||
|
btDynamicsWorld const& get_world() const {
|
||||||
|
return *dynamics_world;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<dual_collision_callback> on_enter_dual_collision_callback{};
|
||||||
|
std::vector<dual_collision_callback> on_exit_dual_collision_callback{};
|
||||||
|
std::vector<single_collision_callback> on_enter_single_collision_callback{};
|
||||||
|
std::vector<single_collision_callback> on_exit_single_collision_callback{};
|
||||||
|
std::vector<single_dual_collision_callback> on_enter_single_dual_collision_callback{};
|
||||||
|
std::vector<single_dual_collision_callback> on_exit_single_dual_collision_callback{};
|
||||||
|
|
||||||
|
void bullet_objects_entered_collision(btCollisionObject const* x, btCollisionObject const* y);
|
||||||
|
void bullet_objects_exited_collision(btCollisionObject const* x, btCollisionObject const* y);
|
||||||
|
|
||||||
|
public:
|
||||||
|
motor::Body* raycast(motor::Position const& from, motor::Position const& to) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<btDefaultCollisionConfiguration> collison_configuration{new btDefaultCollisionConfiguration()};
|
||||||
|
std::unique_ptr<btCollisionDispatcher> collision_dispatcher{new btCollisionDispatcher(collison_configuration.get())};
|
||||||
|
btVector3 const world_minimum = btVector3(-1000,-1000,-1000);
|
||||||
|
btVector3 const world_maximum = btVector3(1000,1000,1000);
|
||||||
|
std::unique_ptr<btBroadphaseInterface> overlapping_pair_cache{new btAxisSweep3(world_minimum, world_maximum)};
|
||||||
|
std::unique_ptr<btConstraintSolver> constraint_solver{new btSequentialImpulseConstraintSolver()};
|
||||||
|
std::shared_ptr<btDynamicsWorld> dynamics_world{new btDiscreteDynamicsWorld(collision_dispatcher.get(), overlapping_pair_cache.get(), constraint_solver.get(), collison_configuration.get())};
|
||||||
|
std::unique_ptr<bullet_debug_drawer> debug_drawer{new bullet_debug_drawer};
|
||||||
|
|
||||||
|
void update_bullet(float const dt, size_t const maximum_number_of_steps);
|
||||||
|
|
||||||
|
void check_collisions();
|
||||||
|
|
||||||
|
//! If since the last time get_debug_draw_results was called, update was called.
|
||||||
|
//! ie. update sets it to false, get_debug_draw_results set it to true
|
||||||
|
bool debug_draw_up_to_date = true;
|
||||||
|
|
||||||
|
// Contains objects that were colliding in the previous update
|
||||||
|
std::vector<std::pair<btCollisionObject const*, btCollisionObject const*>> bullet_objects_in_collision_previous_frame{};
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Attractor>> attractors;
|
||||||
|
|
||||||
|
bool in_update{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
39
src/physics_test_triangle_mesh.hpp
Normal file
39
src/physics_test_triangle_mesh.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <motor/sound/sound.hpp>
|
||||||
|
#include <motor/basic/texture_label.hpp>
|
||||||
|
|
||||||
|
#include "Base.hpp"
|
||||||
|
|
||||||
|
namespace games {
|
||||||
|
using namespace motor;
|
||||||
|
|
||||||
|
struct TestTriangleMesh : public Base {
|
||||||
|
static constexpr char bundle_name[] = "general";
|
||||||
|
|
||||||
|
struct Player {
|
||||||
|
moggle::vector3<float> const model_scale{1, 1, 1};
|
||||||
|
std::shared_ptr<Body> model;
|
||||||
|
|
||||||
|
Player(std::string filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
Player player;
|
||||||
|
|
||||||
|
float game_speed{1.0};
|
||||||
|
|
||||||
|
TestTriangleMesh(int window_width, int window_height, std::shared_ptr<Base>& active_base, std::string filename);
|
||||||
|
|
||||||
|
virtual bool has_ended();
|
||||||
|
virtual void update(float const dt, Input input);
|
||||||
|
|
||||||
|
void reset_camera();
|
||||||
|
void reset_players();
|
||||||
|
void reset_effects();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void handle_players(float const dt, Input input);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace games
|
12
src/world.hpp
Normal file
12
src/world.hpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <motor/basic/scene.hpp>
|
||||||
|
#include "ai_world.hpp"
|
||||||
|
#include "physics.hpp"
|
||||||
|
|
||||||
|
struct World {
|
||||||
|
std::shared_ptr<motor::Scene> scene = std::make_shared<motor::Scene>();
|
||||||
|
std::shared_ptr<motor::Scene> hud = std::make_shared<motor::Scene>();
|
||||||
|
motor::AIWorld ai{};
|
||||||
|
motor::Physics physics{};
|
||||||
|
};
|
Reference in a new issue