commit c3be4d5d12d76b4bb8479a65665c55801020fde7 Author: Joshua Moerman Date: Wed Mar 13 13:49:30 2013 +0100 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ecbd5d5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +*.blend1 +*.blend2 +*.bullet +*.sublime-workspace +build-* +CMakeCache.txt +CMakeFiles + +build/ +mingw-build-codeblocks/ +mingw-build/ +onegame.kdev4 + +linux-packages + +#Kdev temp file ignore +*~ +.kdev4 + +windows\-installer/*.bmp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4b253d4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 2.8) + +add_subdirectory("motor") + +include(motor/cmake/set_system_include_flag.cmake) +include(motor/cmake/address_sanitizer.cmake) + +include(motor/cmake/detect_compiler.cmake) +check_compiling_with_clang(COMPILING_WITH_CLANG) +check_compiling_with_gcc(COMPILING_WITH_GCC) + +if(${COMPILING_WITH_CLANG}) + if(APPLE) + include_directories(SYSTEM "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/c++/v1/") + endif() +endif() + +if(MINGW) + include(motor/cmake/enable_gnu11.cmake) +else() + include(motor/cmake/enable_cpp11.cmake) +endif() + +if(UNIX) + #Always compile with debugging symbols + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") +else() + if(MSVC) + message(FATAL_ERROR "Were not supporting MSVC at this time") + elseif(MINGW) + #assume were runnig cross compilation + add_definitions("-DGLEW_STATIC" "-DAL_LIBTYPE_STATIC" "-DALURE_STATIC_LIBRARY" "-DBOOST_THREAD_USE_LIB") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") + else() + message(FATAL_ERROR "Unsupported platform detected") + endif() +endif() + +include(motor/cmake/warning_settings.cmake) +get_sane_warning_flags(warnings) + +include(motor/cmake/join.cmake) +join("${warnings}" " " warnings) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${warnings}") + +add_subdirectory("src") diff --git a/run b/run new file mode 100755 index 0000000..d93f68f --- /dev/null +++ b/run @@ -0,0 +1,37 @@ +#!/bin/bash + +set -o nounset #Error when unset vars are used +set -o errexit #Exit on errors +set -o pipefail #Causes failure when input-pipe-program fails +set -x + +build_configuration="Debug" +if [ ! -z ${1:-} ] +then + build_configuration=$1 +fi + +run_target="modelviewer" +if [ ! -z ${2:-} ] +then + run_target=$2 +fi + +run_command="./build-$build_configuration/src/$run_target ${3:-}" + +if [ $build_configuration = "mingw" ]; then + if [ ! -d "build-$build_configuration" ]; then + if [ $# -ne 2 ]; then + set +x + echo "Trying to run \"./run mingw\" for the first time without toolchain file." + echo "Please specify a cross_compile toolchain file as second argument." + set -x + else + ./vanillabuild $build_configuration $2 && $run_command.exe + fi + else + ./vanillabuild $build_configuration && $run_command.exe + fi +else + ./vanillabuild $build_configuration && $run_command +fi diff --git a/sdlgame.sublime-project b/sdlgame.sublime-project new file mode 100644 index 0000000..f1d84bb --- /dev/null +++ b/sdlgame.sublime-project @@ -0,0 +1,63 @@ +{ + "folders": + [ + { + "path": "." + } + ], + "settings": + { + "sublimeclang_options": + [ + "-std=c++0x", + "-Weverything", + "-Wno-c++98-compat-pedantic", + "-Wno-cast-align", + "-Wno-conditional-uninitialized", + "-Wno-conversion", + "-Wno-covered-switch-default", + "-Wno-deprecated-declarations", + "-Wno-disabled-macro-expansion", + "-Wno-exit-time-destructors", + "-Wno-float-equal", + "-Wno-format-nonliteral", + "-Wno-global-constructors", + "-Wno-lambda-extensions", + "-Wno-missing-noreturn", + "-Wno-missing-prototypes", + "-Wno-newline-eof", + "-Wno-padded", + "-Wno-sign-conversion", + "-Wno-shadow", + "-Wno-switch-enum", + "-Wno-undef", + "-Wno-unreachable-code", + "-Wno-variadic-macros", + "-Wno-vla", + "-Wno-weak-vtables", + "-Wno-unused-parameter", + "-I${folder:${project_path:sdlgame.sublime-project}}", + "-I${folder:${project_path:sdlgame.sublime-project}}/motor", + "-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/bullet/src", + "-isystem${folder:${project_path:sdlgame.sublime-project}}/motor/contrib/freetype-gl", + "-isystem${folder:${project_path:sdlgame.sublime-project}}/motor/moggle/include", + "-isystem${folder:${project_path:sdlgame.sublime-project}}/motor/contrib/", + "-isystem${folder:${project_path:sdlgame.sublime-project}}/sc-includes/", + "-ferror-limit=0", + "-std=c++11", + "-stdlib=libc++", + "-DDEBUG=1", + "-nostdinc", + "-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/usr/local/include", + "-isystem/sw/include", + "-isystem/opt/local/include", + "-isystem/usr/include" + // Add your personal inclusions below here + ] + } +} diff --git a/src/Base.cpp b/src/Base.cpp new file mode 100644 index 0000000..4bff3fb --- /dev/null +++ b/src/Base.cpp @@ -0,0 +1,85 @@ + +#include "Base.hpp" + +namespace games { +using namespace motor; + +Base::Base(int window_width_, int window_height_) +: window_width(window_width_), window_height(window_height_) +{} + +Base::~Base(){} + +bool Base::has_ended(){ + return false; +} + +void Base::update(float const dt, std::map __attribute__((unused)) keys_went_down, std::map __attribute__((unused)) is_pressed, std::map __attribute__((unused)) keyw_went_up){ + time += dt; + + update_bullet(dt); + check_collisions(); +} + +void Base::update_bullet(float const dt){ + dynamics_world->stepSimulation(dt, 20); + + 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->getUserPointer()); + b->sync_from_bullet(trans); + } + } + } +} + +void Base::check_collisions(){ + std::vector> 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(){ + //First, clear the screen + fbo.unbind(); + 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::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + moggle::gl::enable(GL_DEPTH_TEST); + moggle::gl::enable(GL_BLEND); + moggle::gl::blend_equation(GL_FUNC_ADD); + moggle::gl::blend_function(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + scene->draw(); +} + +ResourceCache Base::resource_cache; + + +} diff --git a/src/Base.hpp b/src/Base.hpp new file mode 100644 index 0000000..d098c1a --- /dev/null +++ b/src/Base.hpp @@ -0,0 +1,171 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "globals.hpp" + +//! 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 +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 = order_agnostic_compare; + +template +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 +bool order_agnostic_equal(std::pair const& a, std::pair const& b){ + return order_agnostic_equalness(a.first, a.second, b.first, b.second); +} + + +namespace games { +using namespace motor; + +struct Base { + static ResourceCache resource_cache; + std::shared_ptr scene = std::make_shared(); + + int window_width; + int window_height; + Fbo fbo{window_width, window_height}; + + float time = 0.0; + + // So all this is needed to set up Bullet! + // You pay for modularity with a lot of code, but perhaps we can wrap this in our own motor::world or something. + std::unique_ptr collison_configuration{new btDefaultCollisionConfiguration()}; + std::unique_ptr 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 overlapping_pair_cache{new btAxisSweep3(world_minimum, world_maximum)}; + std::unique_ptr constraint_solver{new btSequentialImpulseConstraintSolver()}; + std::unique_ptr dynamics_world{new btDiscreteDynamicsWorld(collision_dispatcher.get(), overlapping_pair_cache.get(), constraint_solver.get(), collison_configuration.get())}; + + Base(int window_width, int window_height); + virtual ~Base(); + + virtual bool has_ended(); + +private: + // Contains objects that were colliding in the previous update + std::vector> bullet_objects_in_collision_previous_frame{}; + +public: + virtual void update(float const dt, std::map keys_went_down, std::map is_pressed, std::map keys_went_up); + + void update_bullet(float const dt); + + void check_collisions(); + + //! 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 + dual_collision_callback(std::shared_ptr first_, std::shared_ptr second_, CallbackFunctor&& c) + : first(first_) + , second(second_) + , f(c) + {} + + std::shared_ptr first; + std::shared_ptr second; + std::function f; + + void operator()() { + f(first, second); + } + }; + + struct single_collision_callback { + template + single_collision_callback(std::shared_ptr b_, CallbackFunctor&& c) + : b(b_) + , f(c) + {} + + std::shared_ptr b; + std::function 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 on_enter_dual_collision_callback{}; + std::vector on_exit_dual_collision_callback{}; + std::vector on_enter_single_collision_callback{}; + std::vector 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(); +}; + +} // namespace games diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..eca4929 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 2.8) + +project(onegame) + +find_package(Boost 1.48 REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package(OpenGL REQUIRED) +include_directories(${OPENGL_INCLUDE_DIR}) + +find_package(SDL REQUIRED) +include_directories(${SDL_INCLUDE_DIR}) + +set(boost ${Boost_LIBRARIES}) +set(opengl ${OPENGL_LIBRARIES}) +set(sdl ${SDL_LIBRARY}) +set(moggle moggle_xxx) +if(UNIX) + set(motor motor) + set(zlib z) + set(alure alure) + set(assimp assimp) + if(APPLE) + include_directories("/sw/include/") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/sw/lib") + set(os_libs "-framework Cocoa" "-framework IOKit") + set(openal "-framework OpenAL") + else() + set(openal openal) + endif() +else() + if(MSVC) + set(motor motor) + set(assimp assimp) + set(zlib zlib) + set(opengl opengl32.lib) + set(openal openAL32.lib) + set(alure alure32.lib) + set(graphics_libs glew32.lib) + else() + #Assume were crosscompiling + set(motor motor) + set(assimp assimp) + set(zlib zlib) + set(os_libs "${os_libs}" "-lwinmm") + endif() +endif() + +include_directories("${PROJECT_SOURCE_DIR}") +include_directories("${PROJECT_SOURCE_DIR}/..") +include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/../motor/..") +include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/../motor/contrib/assimp-3.0.1270/include") +include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/../motor/contrib/bullet/src") +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/moggle/include") + +add_library(onegame_common Base.cpp) +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") +add_executable(beamer beamer_main.cpp ${beamer_sources}) +target_link_libraries(beamer ${all_friggin_libraries}) diff --git a/src/beamer/beamer.cpp b/src/beamer/beamer.cpp new file mode 100644 index 0000000..cdb1790 --- /dev/null +++ b/src/beamer/beamer.cpp @@ -0,0 +1,303 @@ +#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(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(::bundle.get_model_path() + "planet.obj"); + + auto const & positions = watermesh->geometry->vertices()->attribute("position").buffer>(); + auto const & colors = watermesh->geometry->vertices()->attribute("color").buffer>(); + 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(watermesh); + water->set_scale({radius*waterlevel, radius*waterlevel, radius*waterlevel}); + } + + { + auto planetmesh = std::make_shared(::bundle.get_model_path() + "planet.obj"); + + auto vertices = planetmesh->geometry->vertices(); + auto const & positions = vertices->attribute("position").buffer>(); + auto const & normals = vertices->attribute("normal").buffer>(); + auto const & colors = vertices->attribute("color").buffer>(); + + moggle::buffer> texcoordsbuf(positions->size()); + vertices->attribute("texture_coordinate", std::move(texcoordsbuf)); + + auto const & texcoords = planetmesh->geometry->vertices()->attribute("texture_coordinate").buffer>(); + 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{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(create_noise_for_sphere(4, 4, [](moggle::vector3 position) -> moggle::hvector4{ + 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(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{radius, phi, psi}); + // COUT << "house at: " << house_pos << std::endl; + house.model->set_position(house_pos); + + houses.push_back(house); + } +} + +std::vector> Beamer::Planet::get_all_bodies() const { + std::vector> ret{model, water}; + for(auto& h : houses){ + ret.push_back(h.model); + } + return ret; +} + +struct Beamer::Player{ + // 3D speed, or 2D? + typedef moggle::vector3 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 change{x, y, z}; + speed += 100.0 * dt * change; + + // make speed follow the sphere + float p = dot(speed, position); + speed -= p * moggle::vector3(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(p)); + } + + { + PointLight p{Position{-4.f, -4.0f, -6.0f, 1.0f}, 200.0f, Color{0, 0, 1, 1}}; + scene->add(std::make_shared(p)); + } + + { + PointLight p{Position{4.f, -4.0f, -6.0f, 1.0f}, 200.0f, Color{0, 1, 0, 1}}; + scene->add(std::make_shared(p)); + } + + { + PointLight p{Position{0.f, 6.0f, -6.0f, 1.0f}, 200.0f, Color{1, 1, 1, 1}}; + scene->add(std::make_shared(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 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 keys_went_down, map is_pressed, map 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); +} + +} diff --git a/src/beamer/beamer.hpp b/src/beamer/beamer.hpp new file mode 100644 index 0000000..fb0ec99 --- /dev/null +++ b/src/beamer/beamer.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include +#include + +#include "../Base.hpp" + +namespace games { +using namespace motor; +using namespace std; + +template +struct check_type { + template + bool operator()(shared_ptr const& p){ + return (dynamic_pointer_cast(p) != nullptr); + } +}; + +struct Beamer : public Base { + static constexpr char bundle_name[] = "beamer"; + + struct House{ + std::shared_ptr model; + House(); + }; + + struct Planet { + float radius{2.5}; + std::shared_ptr model; + std::shared_ptr water; + + std::vector houses; + + std::vector> 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; + + float game_speed{1.0}; + + Beamer(int window_width, int window_height); + ~Beamer(); + + virtual bool has_ended(); + virtual void update(float const dt, map keys_went_down, map is_pressed, map keys_went_up); + + void reset_camera(); + void reset_players(); + void reset_effects(); + void reset(); + + void handle_players(float const dt, map is_pressed); +}; + + +} // namespace games diff --git a/src/beamer/coordinates.h b/src/beamer/coordinates.h new file mode 100644 index 0000000..8a36bba --- /dev/null +++ b/src/beamer/coordinates.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +/* + 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 +moggle::vector3 from_spherical(moggle::vector3 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 +moggle::vector3 to_spherical(moggle::vector3 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 p){return from_spherical(to_spherical(p));}; + auto g = [](moggle::vector3 p){return to_spherical(from_spherical(p));}; + + moggle::vector3 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; + } +} \ No newline at end of file diff --git a/src/beamer/procedural_textures.h b/src/beamer/procedural_textures.h new file mode 100644 index 0000000..cea4952 --- /dev/null +++ b/src/beamer/procedural_textures.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include + +#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 +inline moggle::texture create_noise_for_sphere(int width, int height, F const & f){ + std::unique_ptr 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 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; +} \ No newline at end of file diff --git a/src/beamer/simplex.h b/src/beamer/simplex.h new file mode 100644 index 0000000..de21428 --- /dev/null +++ b/src/beamer/simplex.h @@ -0,0 +1,131 @@ +#pragma once + +#include + +// 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 + +typedef games::Beamer Game; + +constexpr char Game::bundle_name[]; +motor::Bundle const bundle(Game::bundle_name); + +int main(int __unused argc, __unused char** argv){ + const bool fullscreen = false; + + const int window_width = 800; + const int window_height = 600; + + GenericMain m(fullscreen, window_width, window_height); + m.main(); + + return 0; +} diff --git a/src/generic_main.hpp b/src/generic_main.hpp new file mode 100644 index 0000000..5fc3e00 --- /dev/null +++ b/src/generic_main.hpp @@ -0,0 +1,131 @@ +#include +#include +#include + +#include +#include +#include + +#ifndef __unused +#define __unused __attribute__((unused)) +#endif + +template +struct GenericMain { +private: + motor::AL al_context; + + int screen_width = 0; + int screen_height = 0; + + void init_sdl(bool const fullscreen, int const wanted_resolution_width, int const wanted_resolution_height){ + SDL_Init(SDL_INIT_VIDEO); + + char const * caption = "onegame"; + SDL_WM_SetCaption(caption, caption); + + auto const double_buffer_result = SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true); + if(double_buffer_result){ + CERR << "Failed to enable double_buffering" << std::endl; + } + + SDL_Surface * screen = nullptr; + if(fullscreen){ + screen = SDL_SetVideoMode(0, 0, 24, SDL_OPENGL | SDL_FULLSCREEN); + } else { + screen = SDL_SetVideoMode(wanted_resolution_width, wanted_resolution_height, 24, SDL_OPENGL); + } + + if(!screen){ + std::string const sdl_error{SDL_GetError()}; + throw std::runtime_error("Failed to create SDL_Screen: " + sdl_error); + } + + screen_width = screen->w; + screen_height = screen->h; + } + + void init_glew(){ + #if defined(TARGET_GLEW) + if (glewInit() != GLEW_OK) { + throw std::runtime_error("Failed to initialize GLEW"); + } + #endif + } + +public: + GenericMain(bool const fullscreen, int const wanted_resolution_width, int const wanted_resolution_height) + : al_context() + { + init_sdl(fullscreen, wanted_resolution_width, wanted_resolution_height); + init_glew(); + } + + template + void main(T... args){ + std::unique_ptr game{new Game {screen_width, screen_height, args...}}; + + bool done = false; + std::map keys_pressed; + + // for calculation fps + auto fps_time = SDL_GetTicks(); + int frame_count_in_second = 0; + + auto now = SDL_GetTicks(); + while (!done) { + SDL_Event event; + std::map keys_went_down; + std::map keys_went_up; + + bool any_key_pressed = false; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + done = true; + break; + case SDL_KEYDOWN: + { + auto const& key = event.key.keysym.sym; + keys_pressed[key] = true; + keys_went_down[key] = true; + if (key == SDLK_ESCAPE){ + done = true; + } + } + break; + + case SDL_KEYUP: + { + any_key_pressed = true; + auto const& key = event.key.keysym.sym; + keys_pressed[key] = false; + keys_went_up[key] = true; + break; + } + + default: + break; + } + } + + if(any_key_pressed && game->has_ended()){ + game.reset(new Game {screen_width, screen_height, args...}); + } + + float const dt = (SDL_GetTicks() - now)/1000.0f; + now = SDL_GetTicks(); + game->update(dt, keys_went_down, keys_pressed, keys_went_up); + game->draw(); + SDL_GL_SwapBuffers(); + + ++frame_count_in_second; + // one second has past + if(SDL_GetTicks() - fps_time > 1000.0f){ + fps_time = SDL_GetTicks(); + COUT << "Frames in last second: " << frame_count_in_second << std::endl; + frame_count_in_second = 0; + } + } + } +}; diff --git a/src/globals.hpp b/src/globals.hpp new file mode 100644 index 0000000..aa99ec4 --- /dev/null +++ b/src/globals.hpp @@ -0,0 +1,3 @@ +#include + +extern motor::Bundle const bundle; diff --git a/vanillabuild b/vanillabuild new file mode 100755 index 0000000..de2da16 --- /dev/null +++ b/vanillabuild @@ -0,0 +1,84 @@ +#!/bin/bash + +set -o nounset #Error when unset vars are used +set -o errexit #Exit on errors +set -o pipefail #Causes failure when input-pipe-program fails +set -x + +######################################################################### +# # +# Usage: vanillabuild [CMakeBuildType=Debug] [path_to_toolchain_file] # +# # +# path_to_toolchain_file will only be used when "CMakeBuildType=mingw" # +# # +# Further the number of cores are detected for certain OSes. # +# Add your own OS specific detection when needed. # +# # +######################################################################### + +set +x + +linux_number_of_cores_command="nproc" +nr_cores=8 +list="None Debug Release RelWithDebInfo MinSizeRel" + +contains() { + for word in $1; do + if [ $word = $2 ]; then + return 1 + fi + done + return 0 +} + +cmake_command='cmake --warn-uninitialized -Wdev' +mingw_cmake_command="$cmake_command -DBUILD_ASSIMP_TOOLS=OFF -DBUILD_DEMOS=OFF -DBUILD_EXTRAS=OFF -DBUILD_STATIC_LIB=ON -Dfreetype-gl_BUILD_DEMOS=OFF" + +if [ $# -ge 1 ]; then + if [ $1 = "mingw" ]; then + if [ -d "build-$1" ]; then + mkdir -p build-$1 + cd build-$1 + $mingw_cmake_command .. + else + if [ ! $# eq 2 ]; then + set -x + echo "Missing cross-build toolchain." + echo "Please give the toolchain file as second argument to this script." + set +x + else + mkdir -p build-$1 + cd build-$1 + $mingw_cmake_command -DCMAKE_TOOLCHAIN_FILE=$2 .. + fi + fi + elif contains "$list" $1 ; then + set -x + echo "No CMake build type detected exiting" + set +x + exit + else + mkdir -p build-$1 + cd build-$1 + $cmake_command -DCMAKE_BUILD_TYPE=$1 .. + fi +else + mkdir -p build-Debug + cd build-Debug + $cmake_command -DCMAKE_BUILD_TYPE=Debug .. +fi + +if [ "$OSTYPE" = "linux-gnu" ]; then + nr_cores=$(eval $linux_number_of_cores_command) +fi +set +x +if [ "$OSTYPE" = "linux-gnu" ]; then + echo "Detected number of cores: $nr_cores" +else + echo "OS detection failed, detected OS: $OSTYPE." + echo "Defaulting number of cores to $nr_cores" +fi +set -x + +make -j$nr_cores +cd ..