1
Fork 0

Updated to new motor things. Made a empty client.

This commit is contained in:
Joshua Moerman 2013-04-16 15:29:55 +02:00
parent c3be4d5d12
commit b949a9d5a8
24 changed files with 997 additions and 803 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "contrib/libwebsockets"]
path = contrib/libwebsockets
url = git://github.com/warmcat/libwebsockets.git

View file

@ -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

@ -0,0 +1 @@
Subproject commit 2577c831f41700d8162b2509198482e4a438b332

View file

@ -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",

View file

@ -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;

View file

@ -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

View file

@ -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
View 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
View 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;
};
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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
View 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
View 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();
};
}

View file

@ -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);

View file

@ -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};
} }
} }
}; };

View file

@ -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
View 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
View 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
View 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};
};
}

View 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
View 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{};
};