cmake_minimum_required(VERSION 3.0) | cmake_minimum_required(VERSION 3.0) | ||||
project(swan) | project(swan) | ||||
find_package(SFML 2.5 COMPONENTS graphics system window REQUIRED) | |||||
find_package(ImGui-SFML REQUIRED) | |||||
set(CMAKE_CXX_CLANG_TIDY | set(CMAKE_CXX_CLANG_TIDY | ||||
clang-tidy | clang-tidy | ||||
--header-filter=.* | --header-filter=.* | ||||
add_subdirectory(third_party) | add_subdirectory(third_party) | ||||
set(libraries | |||||
sfml-graphics sfml-system sfml-window sfml-audio ImGui-SFML::ImGui-SFML | |||||
imgui SDL2 SDL2_image dl z) | |||||
set(libraries imgui SDL2 SDL2_image dl z) | |||||
# We want to be able to use C++20 designated initializers, | # We want to be able to use C++20 designated initializers, | ||||
# but Clang doesn't support them yet. | # but Clang doesn't support them yet. |
#pragma once | #pragma once | ||||
#include <SFML/Graphics.hpp> | |||||
#include "common.h" | #include "common.h" | ||||
#include "BoundingBox.h" | #include "BoundingBox.h" | ||||
#pragma once | #pragma once | ||||
#include <SFML/Graphics/Texture.hpp> | |||||
#include <string.h> | #include <string.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <memory> | #include <memory> | ||||
Chunk(ChunkPos pos): pos_(pos) { | Chunk(ChunkPos pos): pos_(pos) { | ||||
data_.reset(new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]); | data_.reset(new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]); | ||||
visuals_.reset(new Visuals()); | visuals_.reset(new Visuals()); | ||||
visuals_->tex_.create(CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE); | |||||
visuals_->sprite_ = sf::Sprite(visuals_->tex_); | |||||
visuals_->dirty_ = false; | visuals_->dirty_ = false; | ||||
} | } | ||||
private: | private: | ||||
static constexpr float DEACTIVATE_INTERVAL = 20; | static constexpr float DEACTIVATE_INTERVAL = 20; | ||||
static sf::Uint8 *renderbuf; | |||||
static uint8_t *renderbuf; | |||||
bool isCompressed() { return compressed_size_ != -1; } | bool isCompressed() { return compressed_size_ != -1; } | ||||
float deactivate_timer_ = DEACTIVATE_INTERVAL; | float deactivate_timer_ = DEACTIVATE_INTERVAL; | ||||
struct Visuals { | struct Visuals { | ||||
sf::Texture tex_; | |||||
sf::Sprite sprite_; | |||||
std::unique_ptr<SDL_Texture, void (*)(SDL_Texture *)> texture_{nullptr, SDL_DestroyTexture}; | |||||
bool dirty_; | bool dirty_; | ||||
}; | }; | ||||
std::unique_ptr<Visuals> visuals_; | std::unique_ptr<Visuals> visuals_; |
public: | public: | ||||
Game(Win &win): | Game(Win &win): | ||||
win_(win), | win_(win), | ||||
mouse_pos_(0, 0), | |||||
keys_pressed_(sf::Keyboard::Key::KeyCount, false), | |||||
mouse_pressed_(sf::Mouse::Button::ButtonCount, false) {} | |||||
mouse_pos_(0, 0) {} | |||||
void createWorld(const std::string &worldgen); | void createWorld(const std::string &worldgen); | ||||
void onKeyPressed(sf::Keyboard::Key key) { keys_pressed_[(int)key] = true; } | |||||
void onKeyReleased(sf::Keyboard::Key key) { keys_pressed_[(int)key] = false; } | |||||
void onMouseMove(int x, int y) { mouse_pos_ = Vec2i(x, y); } | |||||
void onMousePressed(sf::Mouse::Button button) { mouse_pressed_[(int)button] = true; } | |||||
void onMouseReleased(sf::Mouse::Button button) { mouse_pressed_[(int)button] = false; } | |||||
void onKeyDown(SDL_Keysym sym) { pressed_keys_[sym.scancode] = true; } | |||||
void onKeyUp(SDL_Keysym sym) { pressed_keys_[sym.scancode] = false; } | |||||
void onMouseMove(Sint32 x, Sint32 y) { mouse_pos_ = { x, y }; } | |||||
void onMouseDown(Sint32 x, Sint32 y, Uint8 button) { mouse_pos_ = { x, y }; pressed_buttons_[button] = true; } | |||||
void onMouseUp(Sint32 x, Sint32 y, Uint8 button) { mouse_pos_ = { x, y }; pressed_buttons_[button] = false; } | |||||
bool isKeyPressed(SDL_Scancode code) { return pressed_keys_[code]; } | |||||
TilePos getMouseTile(); | TilePos getMouseTile(); | ||||
Vec2i getMousePos() { return mouse_pos_; } | Vec2i getMousePos() { return mouse_pos_; } | ||||
bool isKeyPressed(sf::Keyboard::Key key) { return keys_pressed_[(int)key]; } | |||||
bool isMousePressed(sf::Mouse::Button button) { return mouse_pressed_[(int)button]; } | |||||
bool isMousePressed(Uint8 button) { return pressed_buttons_[button]; } | |||||
void draw(); | void draw(); | ||||
void update(float dt); | void update(float dt); | ||||
Win &win_; | Win &win_; | ||||
private: | private: | ||||
std::unordered_map<SDL_Scancode, bool> pressed_keys_; | |||||
Vec2i mouse_pos_; | Vec2i mouse_pos_; | ||||
std::vector<bool> keys_pressed_; | |||||
std::vector<bool> mouse_pressed_; | |||||
std::unordered_map<Uint8, bool> pressed_buttons_; | |||||
}; | }; | ||||
} | } |
#pragma once | #pragma once | ||||
#include <SFML/System/Vector2.hpp> | |||||
#include <utility> | #include <utility> | ||||
namespace Swan { | namespace Swan { | ||||
return *this; | return *this; | ||||
} | } | ||||
constexpr operator sf::Vector2<T>() const { | |||||
return sf::Vector2<T>(x, y); | |||||
} | |||||
constexpr operator std::pair<T, T>() const { | constexpr operator std::pair<T, T>() const { | ||||
return std::pair<T, T>(x, y); | return std::pair<T, T>(x, y); | ||||
} | } |
// .translate((pos - cam_) * TILE_SIZE); | // .translate((pos - cam_) * TILE_SIZE); | ||||
} | } | ||||
void draw(const sf::Drawable &drawable) { | |||||
//window_->draw(drawable, transform_); | |||||
} | |||||
Vec2 getSize() { | Vec2 getSize() { | ||||
//sf::Vector2u v = window_->getSize(); | //sf::Vector2u v = window_->getSize(); | ||||
//return Vec2(v.x, v.y) / (TILE_SIZE * scale_); | //return Vec2(v.x, v.y) / (TILE_SIZE * scale_); |
#pragma once | #pragma once | ||||
#include <SFML/Graphics.hpp> | |||||
#include <SFML/System/Vector2.hpp> | |||||
#include "Vector2.h" | #include "Vector2.h" | ||||
namespace Swan { | namespace Swan { |
void Body::outline(Win &win) { | void Body::outline(Win &win) { | ||||
win.setPos(pos_); | win.setPos(pos_); | ||||
sf::RectangleShape rect(size_ * TILE_SIZE); | |||||
rect.setFillColor(sf::Color::Transparent); | |||||
rect.setOutlineColor(sf::Color(128, 128, 128)); | |||||
rect.setOutlineThickness(1); | |||||
win.draw(rect); | |||||
//sf::RectangleShape rect(size_ * TILE_SIZE); | |||||
//rect.setFillColor(sf::Color::Transparent); | |||||
//rect.setOutlineColor(sf::Color(128, 128, 128)); | |||||
//rect.setOutlineThickness(1); | |||||
//win.draw(rect); | |||||
} | } | ||||
void Body::update(WorldPlane &plane, float dt) { | void Body::update(WorldPlane &plane, float dt) { |
#include "Chunk.h" | #include "Chunk.h" | ||||
#include <SFML/System/Clock.hpp> | |||||
#include <zlib.h> | #include <zlib.h> | ||||
#include "World.h" | #include "World.h" | ||||
if (isCompressed()) | if (isCompressed()) | ||||
return; | return; | ||||
sf::Clock clock; | |||||
// We only need a fixed-length temp buffer; | // We only need a fixed-length temp buffer; | ||||
// if the compressed data gets too big, there's no point in compressing | // if the compressed data gets too big, there's no point in compressing | ||||
uint8_t dest[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]; | uint8_t dest[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]; | ||||
visuals_.reset(); | visuals_.reset(); | ||||
compressed_size_ = destlen; | compressed_size_ = destlen; | ||||
fprintf(stderr, "Compressed chunk %i,%i from %lu bytes to %lu bytes in %.3fs.\n", | |||||
pos_.x, pos_.y, CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID), destlen, | |||||
clock.getElapsedTime().asSeconds()); | |||||
fprintf(stderr, "Compressed chunk %i,%i from %lu bytes to %lu bytes.\n", | |||||
pos_.x, pos_.y, CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID), destlen); | |||||
} else if (ret == Z_BUF_ERROR) { | } else if (ret == Z_BUF_ERROR) { | ||||
fprintf(stderr, "Didn't compress chunk %i,%i because compressing it would've made it bigger.\n", | fprintf(stderr, "Didn't compress chunk %i,%i because compressing it would've made it bigger.\n", | ||||
pos_.x, pos_.y); | pos_.x, pos_.y); | ||||
if (!isCompressed()) | if (!isCompressed()) | ||||
return; | return; | ||||
sf::Clock clock; | |||||
uint8_t *dest = new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]; | uint8_t *dest = new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]; | ||||
uLongf destlen = CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID); | uLongf destlen = CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID); | ||||
int ret = uncompress( | int ret = uncompress( | ||||
visuals_->sprite_ = sf::Sprite(); | visuals_->sprite_ = sf::Sprite(); | ||||
visuals_->dirty_ = true; | visuals_->dirty_ = true; | ||||
need_render_ = true; | need_render_ = true; | ||||
fprintf(stderr, "Decompressed chunk %i,%i from %li bytes to %lu bytes in %.3fs.\n", | |||||
pos_.x, pos_.y, compressed_size_, CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID), | |||||
clock.getElapsedTime().asSeconds()); | |||||
fprintf(stderr, "Decompressed chunk %i,%i from %li bytes to %lu bytes.\n", | |||||
pos_.x, pos_.y, compressed_size_, CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)); | |||||
compressed_size_ = -1; | compressed_size_ = -1; | ||||
} | } | ||||
int fcount = 0; | int fcount = 0; | ||||
int slowFrames = 0; | int slowFrames = 0; | ||||
while (1) { | while (1) { | ||||
SDL_Event evt; | |||||
while (SDL_PollEvent(&evt)) { | |||||
switch (evt.type) { | |||||
case SDL_QUIT: | |||||
goto exit; | |||||
break; | |||||
case SDL_KEYDOWN: | |||||
game.onKeyDown(evt.key.keysym); | |||||
break; | |||||
case SDL_KEYUP: | |||||
game.onKeyUp(evt.key.keysym); | |||||
break; | |||||
case SDL_MOUSEMOTION: | |||||
game.onMouseMove(evt.motion.x, evt.motion.y); | |||||
break; | |||||
case SDL_MOUSEBUTTONDOWN: | |||||
game.onMouseDown(evt.button.x, evt.button.y, evt.button.button); | |||||
break; | |||||
case SDL_MOUSEBUTTONUP: | |||||
game.onMouseUp(evt.button.x, evt.button.y, evt.button.button); | |||||
break; | |||||
} | |||||
} | |||||
auto now = std::chrono::steady_clock::now(); | auto now = std::chrono::steady_clock::now(); | ||||
std::chrono::duration<float> dur(prevTime - now); | std::chrono::duration<float> dur(prevTime - now); | ||||
prevTime = now; | prevTime = now; | ||||
SDL_UpdateWindowSurface(window.get()); | SDL_UpdateWindowSurface(window.get()); | ||||
} | } | ||||
exit: | |||||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||||
} | } |