void DefaultWorldGen::drawBackground( | void DefaultWorldGen::drawBackground( | ||||
const Swan::Context &ctx, Cygnet::Renderer &rnd, Swan::Vec2 pos) { | const Swan::Context &ctx, Cygnet::Renderer &rnd, Swan::Vec2 pos) { | ||||
int texmin = 10; | |||||
//int texmax = 20; | |||||
if (pos.y > texmin) { | |||||
/* | |||||
SDL_Texture *tex = bgCave_.texture_.get(); | |||||
Uint8 alpha = std::clamp( | |||||
(pos.y - texmin) / (texmax - texmin), 0.0f, 1.0f) * 255; | |||||
Swan::TexAlphaMod amod(tex, alpha); | |||||
Swan::Draw::parallaxBackground( | |||||
win, tex, std::nullopt, std::nullopt, | |||||
pos.x * Swan::TILE_SIZE, pos.y * Swan::TILE_SIZE, 0.7); | |||||
TODO */ | |||||
} | |||||
// TODO: Do something interesting? | |||||
} | } | ||||
Cygnet::Color DefaultWorldGen::backgroundColor(Swan::Vec2 pos) { | Cygnet::Color DefaultWorldGen::backgroundColor(Swan::Vec2 pos) { |
placeTimer_.tick(dt); | placeTimer_.tick(dt); | ||||
// Break block | // Break block | ||||
if (ctx.game.isMousePressed(SDL_BUTTON_LEFT)) | |||||
if (ctx.game.isMousePressed(GLFW_MOUSE_BUTTON_LEFT)) | |||||
ctx.plane.breakTile(mouseTile_); | ctx.plane.breakTile(mouseTile_); | ||||
// Place block | // Place block | ||||
if (ctx.game.isMousePressed(SDL_BUTTON_RIGHT) && placeTimer_.periodic(0.50)) { | |||||
if (ctx.game.isMousePressed(GLFW_MOUSE_BUTTON_RIGHT) && placeTimer_.periodic(0.50)) { | |||||
if (ctx.plane.getTileID(mouseTile_) == ctx.world.getTileID("@::air")) { | if (ctx.plane.getTileID(mouseTile_) == ctx.world.getTileID("@::air")) { | ||||
ctx.plane.setTile(mouseTile_, "core::torch"); | ctx.plane.setTile(mouseTile_, "core::torch"); | ||||
} | } | ||||
} | } | ||||
// Move left | // Move left | ||||
if (ctx.game.isKeyPressed(SDL_SCANCODE_A) || ctx.game.isKeyPressed(SDL_SCANCODE_LEFT)) { | |||||
if (ctx.game.isKeyPressed(GLFW_KEY_A) || ctx.game.isKeyPressed(GLFW_KEY_LEFT)) { | |||||
physics_.force += Swan::Vec2(-MOVE_FORCE, 0); | physics_.force += Swan::Vec2(-MOVE_FORCE, 0); | ||||
state_ = State::RUNNING_L; | state_ = State::RUNNING_L; | ||||
} | } | ||||
// Move right | // Move right | ||||
if (ctx.game.isKeyPressed(SDL_SCANCODE_D) || ctx.game.isKeyPressed(SDL_SCANCODE_RIGHT)) { | |||||
if (ctx.game.isKeyPressed(GLFW_KEY_D) || ctx.game.isKeyPressed(GLFW_KEY_RIGHT)) { | |||||
physics_.force += Swan::Vec2(MOVE_FORCE, 0); | physics_.force += Swan::Vec2(MOVE_FORCE, 0); | ||||
if (state_ == State::RUNNING_L) | if (state_ == State::RUNNING_L) | ||||
state_ = State::IDLE; | state_ = State::IDLE; | ||||
state_ = State::RUNNING_R; | state_ = State::RUNNING_R; | ||||
} | } | ||||
bool jumpPressed = ctx.game.isKeyPressed(SDL_SCANCODE_SPACE); | |||||
bool jumpPressed = ctx.game.isKeyPressed(GLFW_KEY_SPACE); | |||||
// Jump | // Jump | ||||
if (physics_.onGround && jumpPressed && jumpTimer_.periodic(0.5)) { | if (physics_.onGround && jumpPressed && jumpTimer_.periodic(0.5)) { |
#pragma once | |||||
#include <swan-common/Vector2.h> | |||||
#include <memory> | |||||
#include "util.h" | |||||
struct SDL_Window; | |||||
namespace Cygnet { | |||||
struct WindowState; | |||||
class Window { | |||||
public: | |||||
Window(const char *name, int w, int h); | |||||
~Window(); | |||||
void makeCurrent(); | |||||
void clear(Color color = {}); | |||||
void flip(); | |||||
void onResize(int w, int h); | |||||
SwanCommon::Vec2i size() { return size_; } | |||||
double pixelRatio() { return ratio_; } | |||||
SDL_Window *sdlWindow(); | |||||
private: | |||||
std::unique_ptr<WindowState> state_; | |||||
SwanCommon::Vec2i size_; | |||||
double ratio_; | |||||
}; | |||||
} |
#include <GL/glew.h> | |||||
#include <SDL_opengl.h> | |||||
#ifdef __APPLE__ | |||||
#define GL_SILENCE_DEPRECATION | |||||
#include <OpenGL/gl3.h> | |||||
#else | |||||
#include <GL/gl.h> | |||||
#endif |
operator Color() { return { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f }; } | operator Color() { return { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f }; } | ||||
}; | }; | ||||
struct SDLError: public std::exception { | |||||
SDLError(std::string msg): message(std::move(msg)) {} | |||||
const char *what() const noexcept override { return message.c_str(); } | |||||
std::string message; | |||||
}; | |||||
struct GlError: public std::exception { | struct GlError: public std::exception { | ||||
GlError(std::string msg): message(std::move(msg)) {} | GlError(std::string msg): message(std::move(msg)) {} | ||||
const char *what() const noexcept override { return message.c_str(); } | const char *what() const noexcept override { return message.c_str(); } | ||||
std::string message; | std::string message; | ||||
}; | }; | ||||
void sdlCheck(bool ok); | |||||
void glCheck(); | void glCheck(); | ||||
} | } |
'src/shaders.cc', | 'src/shaders.cc', | ||||
'src/TileAtlas.cc', | 'src/TileAtlas.cc', | ||||
'src/util.cc', | 'src/util.cc', | ||||
'src/Window.cc', | |||||
dependencies: [common, libtracy, libthreads, libsdl2, libgl, libglew], | |||||
dependencies: [common, libtracy, libthreads, libgl, libglfw3], | |||||
install: true, | install: true, | ||||
include_directories: 'include/cygnet')) | include_directories: 'include/cygnet')) |
static constexpr float cw = (float)SwanCommon::CHUNK_WIDTH; | static constexpr float cw = (float)SwanCommon::CHUNK_WIDTH; | ||||
static constexpr GLfloat vertexes[] = { | static constexpr GLfloat vertexes[] = { | ||||
0.0f, 0.0f, // pos 0: top left | 0.0f, 0.0f, // pos 0: top left | ||||
0.0f, ch , // pos 1: bottom left | |||||
0.0f, ch, // pos 1: bottom left | |||||
cw, ch, // pos 2: bottom right | cw, ch, // pos 2: bottom right | ||||
cw, ch, // pos 2: bottom right | cw, ch, // pos 2: bottom right | ||||
cw, 0.0f, // pos 3: top right | cw, 0.0f, // pos 3: top right | ||||
void enable() { | void enable() { | ||||
glUseProgram(id()); | glUseProgram(id()); | ||||
glCheck(); | |||||
glBindBuffer(GL_ARRAY_BUFFER, vbo); | glBindBuffer(GL_ARRAY_BUFFER, vbo); | ||||
glCheck(); | |||||
glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); | glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); | ||||
glCheck(); | |||||
glEnableVertexAttribArray(vertex); | glEnableVertexAttribArray(vertex); | ||||
glCheck(); | glCheck(); | ||||
if constexpr (std::endian::native == std::endian::little) { | if constexpr (std::endian::native == std::endian::little) { | ||||
glTexImage2D( | glTexImage2D( | ||||
GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, | |||||
GL_TEXTURE_2D, 0, GL_RG, | |||||
SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | ||||
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, tiles); | |||||
0, GL_RG, GL_UNSIGNED_BYTE, tiles); | |||||
glCheck(); | glCheck(); | ||||
} else if constexpr (std::endian::native == std::endian::big) { | } else if constexpr (std::endian::native == std::endian::big) { | ||||
uint8_t buf[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT * 2]; | uint8_t buf[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT * 2]; | ||||
} | } | ||||
glTexImage2D( | glTexImage2D( | ||||
GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, | |||||
GL_TEXTURE_2D, 0, GL_RG, | |||||
SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | ||||
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf); | |||||
0, GL_RG, GL_UNSIGNED_BYTE, buf); | |||||
glCheck(); | glCheck(); | ||||
} | } | ||||
if constexpr (std::endian::native == std::endian::little) { | if constexpr (std::endian::native == std::endian::little) { | ||||
glTexSubImage2D( | glTexSubImage2D( | ||||
GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1, | GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1, | ||||
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, &id); | |||||
GL_RG, GL_UNSIGNED_BYTE, &id); | |||||
} else if constexpr (std::endian::native == std::endian::big) { | } else if constexpr (std::endian::native == std::endian::big) { | ||||
uint8_t buf[] = { (uint8_t)(id & 0xff), (uint8_t)((id & 0xff00) >> 8) }; | uint8_t buf[] = { (uint8_t)(id & 0xff), (uint8_t)((id & 0xff00) >> 8) }; | ||||
glTexSubImage2D( | glTexSubImage2D( | ||||
GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1, | GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1, | ||||
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf); | |||||
GL_RG, GL_UNSIGNED_BYTE, buf); | |||||
} | } | ||||
glCheck(); | glCheck(); | ||||
glCheck(); | glCheck(); | ||||
glTexImage2D( | glTexImage2D( | ||||
GL_TEXTURE_2D, 0, GL_LUMINANCE, | |||||
GL_TEXTURE_2D, 0, GL_RED, | |||||
SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | ||||
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | |||||
0, GL_RED, GL_UNSIGNED_BYTE, data); | |||||
glCheck(); | glCheck(); | ||||
return shadow; | return shadow; | ||||
glBindTexture(GL_TEXTURE_2D, shadow.tex); | glBindTexture(GL_TEXTURE_2D, shadow.tex); | ||||
glTexImage2D( | glTexImage2D( | ||||
GL_TEXTURE_2D, 0, GL_LUMINANCE, | |||||
GL_TEXTURE_2D, 0, GL_RED, | |||||
SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | ||||
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | |||||
0, GL_RED, GL_UNSIGNED_BYTE, data); | |||||
glCheck(); | glCheck(); | ||||
} | } | ||||
#include "Window.h" | |||||
#include <SDL.h> | |||||
#include <iostream> | |||||
#include "gl.h" | |||||
#include "util.h" | |||||
namespace Cygnet { | |||||
struct WindowState { | |||||
SDL_Window *window; | |||||
SDL_GLContext glctx; | |||||
}; | |||||
Window::Window(const char *name, int w, int h): | |||||
state_(std::make_unique<WindowState>()) { | |||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); | |||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); | |||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); | |||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | |||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); | |||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); | |||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8); | |||||
SDL_GL_SetSwapInterval(1); | |||||
state_->window = SDL_CreateWindow(name, | |||||
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, | |||||
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | | |||||
SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL); | |||||
sdlCheck(state_->window != NULL); | |||||
state_->glctx = SDL_GL_CreateContext(state_->window); | |||||
glCheck(); | |||||
makeCurrent(); | |||||
glewInit(); | |||||
std::cerr << "OpenGL Version: " << glGetString(GL_VERSION) << '\n'; | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
glEnable(GL_BLEND); | |||||
glCheck(); | |||||
SDL_GetWindowSize(state_->window, &w, &h); | |||||
onResize(w, h); | |||||
} | |||||
Window::~Window() { | |||||
SDL_DestroyWindow(state_->window); | |||||
} | |||||
void Window::makeCurrent() { | |||||
SDL_GL_MakeCurrent(state_->window, state_->glctx); | |||||
glCheck(); | |||||
} | |||||
void Window::clear(Color color) { | |||||
glClearColor(color.r, color.g, color.b, color.a); | |||||
glClear(GL_COLOR_BUFFER_BIT); | |||||
glCheck(); | |||||
} | |||||
void Window::flip() { | |||||
SDL_GL_SwapWindow(state_->window); | |||||
glCheck(); | |||||
} | |||||
void Window::onResize(int w, int h) { | |||||
int dw, dh; | |||||
SDL_GL_GetDrawableSize(state_->window, &dw, &dh); | |||||
glViewport(0, 0, dw, dh); | |||||
glCheck(); | |||||
size_ = {dw, dh}; | |||||
ratio_ = (double)dw / (double)w; | |||||
} | |||||
SDL_Window *Window::sdlWindow() { | |||||
return state_->window; | |||||
} | |||||
} |
namespace Cygnet::Shaders { | namespace Cygnet::Shaders { | ||||
const char *chunkVx = R"glsl( | const char *chunkVx = R"glsl( | ||||
#version 410 | |||||
in vec2 vertex; | |||||
uniform mat3 camera; | uniform mat3 camera; | ||||
uniform vec2 pos; | uniform vec2 pos; | ||||
attribute vec2 vertex; | |||||
varying vec2 v_tileCoord; | |||||
out vec2 v_tileCoord; | |||||
void main() { | void main() { | ||||
vec3 pos = camera * vec3(pos + vertex, 1); | |||||
gl_Position = vec4(pos.xy, 0, 1); | |||||
vec3 p = camera * vec3(pos + vertex, 1); | |||||
gl_Position = vec4(p.xy, 0, 1); | |||||
v_tileCoord = vertex; | v_tileCoord = vertex; | ||||
} | } | ||||
)glsl"; | )glsl"; | ||||
const char *chunkFr = R"glsl( | const char *chunkFr = R"glsl( | ||||
#version 410 | |||||
#define TILE_SIZE 32.0 | #define TILE_SIZE 32.0 | ||||
#define CHUNK_WIDTH 64 | #define CHUNK_WIDTH 64 | ||||
#define CHUNK_HEIGHT 64 | #define CHUNK_HEIGHT 64 | ||||
varying vec2 v_tileCoord; | |||||
in vec2 v_tileCoord; | |||||
uniform sampler2D tileAtlas; | uniform sampler2D tileAtlas; | ||||
uniform vec2 tileAtlasSize; | uniform vec2 tileAtlasSize; | ||||
uniform sampler2D tiles; | uniform sampler2D tiles; | ||||
out vec4 fragColor; | |||||
void main() { | void main() { | ||||
vec2 tilePos = floor(vec2(v_tileCoord.x, v_tileCoord.y)); | vec2 tilePos = floor(vec2(v_tileCoord.x, v_tileCoord.y)); | ||||
vec4 tileColor = texture2D(tiles, tilePos / vec2(CHUNK_WIDTH, CHUNK_HEIGHT)); | |||||
float tileID = floor((tileColor.r * 256.0 + tileColor.a) * 256.0); | |||||
vec4 tileColor = texture(tiles, tilePos / vec2(CHUNK_WIDTH, CHUNK_HEIGHT)); | |||||
float tileID = floor((tileColor.r * 256.0 + tileColor.g) * 256.0); | |||||
// 1/(TILE_SIZE*16) plays the same role here as in the sprite vertex shader. | // 1/(TILE_SIZE*16) plays the same role here as in the sprite vertex shader. | ||||
vec2 offset = v_tileCoord - tilePos; | vec2 offset = v_tileCoord - tilePos; | ||||
pixoffset.x + tileID + offset.x, | pixoffset.x + tileID + offset.x, | ||||
pixoffset.y + floor(tileID / tileAtlasSize.x) + offset.y); | pixoffset.y + floor(tileID / tileAtlasSize.x) + offset.y); | ||||
gl_FragColor = texture2D(tileAtlas, atlasPos / tileAtlasSize); | |||||
fragColor = texture(tileAtlas, atlasPos / tileAtlasSize); | |||||
} | } | ||||
)glsl"; | )glsl"; | ||||
const char *chunkShadowVx = R"glsl( | const char *chunkShadowVx = R"glsl( | ||||
#version 410 | |||||
#define CHUNK_WIDTH 64 | #define CHUNK_WIDTH 64 | ||||
#define CHUNK_HEIGHT 64 | #define CHUNK_HEIGHT 64 | ||||
in vec2 vertex; | |||||
uniform mat3 camera; | uniform mat3 camera; | ||||
uniform vec2 pos; | uniform vec2 pos; | ||||
attribute vec2 vertex; | |||||
varying vec2 v_texCoord; | |||||
out vec2 v_texCoord; | |||||
void main() { | void main() { | ||||
vec3 pos = camera * vec3(pos + vertex, 1); | vec3 pos = camera * vec3(pos + vertex, 1); | ||||
)glsl"; | )glsl"; | ||||
const char *chunkShadowFr = R"glsl( | const char *chunkShadowFr = R"glsl( | ||||
varying vec2 v_texCoord; | |||||
#version 410 | |||||
in vec2 v_texCoord; | |||||
uniform sampler2D tex; | uniform sampler2D tex; | ||||
out vec4 fragColor; | |||||
void main() { | void main() { | ||||
vec4 color = texture2D(tex, v_texCoord); | |||||
gl_FragColor = vec4(0, 0, 0, 1.0 - color.r); | |||||
vec4 color = texture(tex, v_texCoord); | |||||
fragColor = vec4(0, 0, 0, 1.0 - color.r); | |||||
} | } | ||||
)glsl"; | )glsl"; | ||||
const char *tileVx = R"glsl( | const char *tileVx = R"glsl( | ||||
#version 410 | |||||
in vec2 vertex; | |||||
uniform mat3 camera; | uniform mat3 camera; | ||||
uniform mat3 transform; | uniform mat3 transform; | ||||
attribute vec2 vertex; | |||||
varying vec2 v_tileCoord; | |||||
out vec2 v_tileCoord; | |||||
void main() { | void main() { | ||||
vec3 pos = camera * transform * vec3(vertex, 1); | vec3 pos = camera * transform * vec3(vertex, 1); | ||||
)glsl"; | )glsl"; | ||||
const char *tileFr = R"glsl( | const char *tileFr = R"glsl( | ||||
#version 410 | |||||
#define TILE_SIZE 32.0 | #define TILE_SIZE 32.0 | ||||
varying vec2 v_tileCoord; | |||||
in vec2 v_tileCoord; | |||||
uniform sampler2D tileAtlas; | uniform sampler2D tileAtlas; | ||||
uniform vec2 tileAtlasSize; | uniform vec2 tileAtlasSize; | ||||
uniform float tileID; | uniform float tileID; | ||||
out vec4 fragColor; | |||||
void main() { | void main() { | ||||
pixoffset.x + tileID + offset.x, | pixoffset.x + tileID + offset.x, | ||||
pixoffset.y + floor(tileID / tileAtlasSize.x) + offset.y); | pixoffset.y + floor(tileID / tileAtlasSize.x) + offset.y); | ||||
gl_FragColor = texture2D(tileAtlas, atlasPos / tileAtlasSize); | |||||
fragColor = texture(tileAtlas, atlasPos / tileAtlasSize); | |||||
} | } | ||||
)glsl"; | )glsl"; | ||||
const char *spriteVx = R"glsl( | const char *spriteVx = R"glsl( | ||||
#version 410 | |||||
#define TILE_SIZE 32.0 | #define TILE_SIZE 32.0 | ||||
in vec2 vertex; | |||||
uniform mat3 camera; | uniform mat3 camera; | ||||
uniform mat3 transform; | uniform mat3 transform; | ||||
uniform vec2 frameSize; | uniform vec2 frameSize; | ||||
uniform vec2 frameInfo; // frame count, frame index | uniform vec2 frameInfo; // frame count, frame index | ||||
attribute vec2 vertex; | |||||
varying vec2 v_texCoord; | |||||
out vec2 v_texCoord; | |||||
void main() { | void main() { | ||||
// Here, I'm basically treating 1/(TILE_SIZE*16) as half the size of a "pixel". | // Here, I'm basically treating 1/(TILE_SIZE*16) as half the size of a "pixel". | ||||
)glsl"; | )glsl"; | ||||
const char *spriteFr = R"glsl( | const char *spriteFr = R"glsl( | ||||
varying vec2 v_texCoord; | |||||
#version 410 | |||||
in vec2 v_texCoord; | |||||
uniform sampler2D tex; | uniform sampler2D tex; | ||||
out vec4 fragColor; | |||||
void main() { | void main() { | ||||
gl_FragColor = texture2D(tex, v_texCoord); | |||||
fragColor = texture(tex, v_texCoord); | |||||
} | } | ||||
)glsl"; | )glsl"; | ||||
const char *rectVx = R"glsl( | const char *rectVx = R"glsl( | ||||
#version 410 | |||||
in vec2 vertex; | |||||
uniform mat3 camera; | uniform mat3 camera; | ||||
uniform vec2 pos; | uniform vec2 pos; | ||||
uniform vec2 size; | uniform vec2 size; | ||||
attribute vec2 vertex; | |||||
varying vec2 v_coord; | |||||
out vec2 v_coord; | |||||
void main() { | void main() { | ||||
vec3 pos = camera * vec3(pos + vertex * size, 1); | vec3 pos = camera * vec3(pos + vertex * size, 1); | ||||
)glsl"; | )glsl"; | ||||
const char *rectFr = R"glsl( | const char *rectFr = R"glsl( | ||||
#version 410 | |||||
#define THICKNESS 0.02 | #define THICKNESS 0.02 | ||||
varying vec2 v_coord; | |||||
in vec2 v_coord; | |||||
uniform vec2 size; | uniform vec2 size; | ||||
out vec4 fragColor; | |||||
void main() { | void main() { | ||||
vec2 invCoord = size - v_coord; | vec2 invCoord = size - v_coord; | ||||
float minDist = min(v_coord.x, min(v_coord.y, min(invCoord.x, invCoord.y))); | float minDist = min(v_coord.x, min(v_coord.y, min(invCoord.x, invCoord.y))); | ||||
gl_FragColor = vec4(0.6, 0.6, 0.6, 0.8) * float(minDist < THICKNESS); | |||||
fragColor = vec4(0.6, 0.6, 0.6, 0.8) * float(minDist < THICKNESS); | |||||
} | } | ||||
)glsl"; | )glsl"; | ||||
const char *blendVx = R"glsl( | const char *blendVx = R"glsl( | ||||
attribute vec2 vertex; | |||||
attribute vec2 texCoord; | |||||
varying vec2 v_texCoord; | |||||
#version 410 | |||||
in vec2 vertex; | |||||
in vec2 texCoord; | |||||
out vec2 v_texCoord; | |||||
void main() { | void main() { | ||||
gl_Position = vec4(vertex.xy, 0, 1); | gl_Position = vec4(vertex.xy, 0, 1); | ||||
)glsl"; | )glsl"; | ||||
const char *blendFr = R"glsl( | const char *blendFr = R"glsl( | ||||
varying vec2 v_texCoord; | |||||
#version 410 | |||||
in vec2 v_texCoord; | |||||
uniform sampler2D tex; | uniform sampler2D tex; | ||||
out vec4 fragColor; | |||||
void main() { | void main() { | ||||
//gl_FragColor = vec4(v_texCoord.x, v_texCoord.y, 0, 1); | //gl_FragColor = vec4(v_texCoord.x, v_texCoord.y, 0, 1); | ||||
gl_FragColor = texture2D(tex, v_texCoord); | |||||
fragColor = texture(tex, v_texCoord); | |||||
} | } | ||||
)glsl"; | )glsl"; | ||||
#include "util.h" | #include "util.h" | ||||
#include <SDL.h> | |||||
#include "gl.h" | #include "gl.h" | ||||
namespace Cygnet { | namespace Cygnet { | ||||
#undef errcase | #undef errcase | ||||
} | } | ||||
void sdlCheck(bool ok) { | |||||
if (!ok) { | |||||
throw SDLError(SDL_GetError()); | |||||
} | |||||
} | |||||
void glCheck() { | void glCheck() { | ||||
GLenum err = glGetError(); | GLenum err = glGetError(); | ||||
if (err != GL_NO_ERROR) { | if (err != GL_NO_ERROR) { |
#pragma once | #pragma once | ||||
#include <SDL.h> | |||||
#include <cygnet/Renderer.h> | #include <cygnet/Renderer.h> | ||||
#include "common.h" | #include "common.h" |
#include <map> | #include <map> | ||||
#include <string> | #include <string> | ||||
#include <optional> | #include <optional> | ||||
#include <SDL.h> | |||||
#include <GLFW/glfw3.h> | |||||
#include <cygnet/Renderer.h> | #include <cygnet/Renderer.h> | ||||
#include <cygnet/util.h> | #include <cygnet/util.h> | ||||
public: | public: | ||||
void createWorld(const std::string &worldgen, const std::vector<std::string> &modPaths); | void createWorld(const std::string &worldgen, const std::vector<std::string> &modPaths); | ||||
void onKeyDown(SDL_Keysym sym) { | |||||
pressedKeys_[sym.scancode] = true; | |||||
didPressKeys_[sym.scancode] = true; | |||||
void onKeyDown(int scancode) { | |||||
pressedKeys_[scancode] = true; | |||||
didPressKeys_[scancode] = true; | |||||
} | } | ||||
void onKeyUp(SDL_Keysym sym) { | |||||
pressedKeys_[sym.scancode] = false; | |||||
didReleaseKeys_[sym.scancode] = true; | |||||
void onKeyUp(int scancode) { | |||||
pressedKeys_[scancode] = false; | |||||
didReleaseKeys_[scancode] = true; | |||||
} | } | ||||
void onMouseMove(Sint32 x, Sint32 y) { | |||||
mousePos_ = (Vec2{(float)x, (float)y} / (Vec2)cam_.size) * renderer_.winScale(); | |||||
void onMouseMove(float x, float y) { | |||||
mousePos_ = (Vec2{x, y} / (Vec2)cam_.size) * renderer_.winScale(); | |||||
} | } | ||||
void onMouseDown(Sint32 x, Sint32 y, Uint8 button) { | |||||
onMouseMove(x, y); | |||||
void onMouseDown(int button) { | |||||
pressedButtons_[button] = true; | pressedButtons_[button] = true; | ||||
didPressButtons_[button] = true; | didPressButtons_[button] = true; | ||||
} | } | ||||
void onMouseUp(Sint32 x, Sint32 y, Uint8 button) { | |||||
onMouseMove(x, y); | |||||
void onMouseUp(int button) { | |||||
pressedButtons_[button] = false; | pressedButtons_[button] = false; | ||||
didReleaseButtons_[button] = true; | didReleaseButtons_[button] = true; | ||||
} | } | ||||
void onScrollWheel(Sint32 y) { | |||||
didScroll_ = (y > 0 ? 1 : -1 ); | |||||
void onScrollWheel(double dy) { | |||||
didScroll_ += dy; | |||||
} | } | ||||
bool isKeyPressed(SDL_Scancode code) { return pressedKeys_[code]; } | |||||
bool wasKeyPressed(SDL_Scancode code) { return didPressKeys_[code]; } | |||||
bool wasKeyReleased(SDL_Scancode code) { return didReleaseKeys_[code]; } | |||||
bool isKeyPressed(int key) { return pressedKeys_[glfwGetKeyScancode(key)]; } | |||||
bool wasKeyPressed(int key) { return didPressKeys_[glfwGetKeyScancode(key)]; } | |||||
bool wasKeyReleased(int key) { return didReleaseKeys_[glfwGetKeyScancode(key)]; } | |||||
Vec2 getMousePos() { return mousePos_; } | Vec2 getMousePos() { return mousePos_; } | ||||
bool isMousePressed(Uint8 button) { return pressedButtons_[button]; } | |||||
bool wasMousePressed(Uint8 button) { return didPressButtons_[button]; } | |||||
bool wasMouseReleased(Uint8 button) { return didReleaseButtons_[button]; } | |||||
int wasWheelScrolled() { return didScroll_; } | |||||
bool isMousePressed(int button) { return pressedButtons_[button]; } | |||||
bool wasMousePressed(int button) { return didPressButtons_[button]; } | |||||
bool wasMouseReleased(int button) { return didReleaseButtons_[button]; } | |||||
double wasWheelScrolled() { return didScroll_; } | |||||
TilePos getMouseTile(); | TilePos getMouseTile(); | ||||
Cygnet::RenderCamera cam_{.zoom = 0.125}; | Cygnet::RenderCamera cam_{.zoom = 0.125}; | ||||
private: | private: | ||||
std::bitset<SDL_NUM_SCANCODES> pressedKeys_; | |||||
std::bitset<SDL_NUM_SCANCODES> didPressKeys_; | |||||
std::bitset<SDL_NUM_SCANCODES> didReleaseKeys_; | |||||
std::bitset<512> pressedKeys_; | |||||
std::bitset<512> didPressKeys_; | |||||
std::bitset<512> didReleaseKeys_; | |||||
Vec2 mousePos_; | Vec2 mousePos_; | ||||
std::bitset<SDL_BUTTON_X2> pressedButtons_; | |||||
std::bitset<SDL_BUTTON_X2> didPressButtons_; | |||||
std::bitset<SDL_BUTTON_X2> didReleaseButtons_; | |||||
std::bitset<8> pressedButtons_; | |||||
std::bitset<8> didPressButtons_; | |||||
std::bitset<8> didReleaseButtons_; | |||||
int didScroll_ = 0; | |||||
double didScroll_ = 0; | |||||
}; | }; | ||||
} | } |
#include <vector> | #include <vector> | ||||
#include <memory> | #include <memory> | ||||
#include <type_traits> | #include <type_traits> | ||||
#include <SDL.h> | |||||
#include "Tile.h" | #include "Tile.h" | ||||
#include "Item.h" | #include "Item.h" |
#include <vector> | #include <vector> | ||||
#include <string> | #include <string> | ||||
#include <random> | #include <random> | ||||
#include <SDL.h> | |||||
#include <cygnet/Renderer.h> | #include <cygnet/Renderer.h> | ||||
#include <cygnet/ResourceManager.h> | #include <cygnet/ResourceManager.h> | ||||
#include <cygnet/util.h> | #include <cygnet/util.h> |
#pragma once | #pragma once | ||||
#include <memory> | #include <memory> | ||||
#include <SDL.h> | |||||
#include <cygnet/util.h> | #include <cygnet/util.h> | ||||
#include "common.h" | #include "common.h" |
#pragma once | #pragma once | ||||
#include <SDL.h> | |||||
#include <optional> | #include <optional> | ||||
#include <initializer_list> | #include <initializer_list> | ||||
#include <utility> | #include <utility> | ||||
Cygnet::Color linearGradient( | Cygnet::Color linearGradient( | ||||
float val, std::initializer_list<std::pair<float, Cygnet::Color>> colors); | float val, std::initializer_list<std::pair<float, Cygnet::Color>> colors); | ||||
/* | |||||
void parallaxBackground( | |||||
Win &win, SDL_Texture *tex, | |||||
std::optional<SDL_Rect> srcrect, std::optional<SDL_Rect> destrect, | |||||
float x, float y, float factor); | |||||
TODO */ | |||||
} | } | ||||
} | } |
#include <SDL.h> | |||||
#include <ostream> | |||||
#include "util.h" | |||||
#include "log.h" | |||||
namespace Swan { | |||||
inline std::ostream &operator<<(std::ostream &os, const SDL_Rect &rect) { | |||||
os | |||||
<< "SDL_Rect(" << rect.x << ", " << rect.y << ", " | |||||
<< rect.w << ", " << rect.h << ")"; | |||||
return os; | |||||
} | |||||
class RenderBlendMode: NonCopyable { | |||||
public: | |||||
RenderBlendMode(SDL_Renderer *rnd, SDL_BlendMode mode): rnd_(rnd) { | |||||
SDL_GetRenderDrawBlendMode(rnd_, &mode_); | |||||
SDL_SetRenderDrawBlendMode(rnd_, mode); | |||||
} | |||||
~RenderBlendMode() { | |||||
SDL_SetRenderDrawBlendMode(rnd_, mode_); | |||||
} | |||||
private: | |||||
SDL_Renderer *rnd_; | |||||
SDL_BlendMode mode_; | |||||
}; | |||||
class RenderDrawColor: NonCopyable { | |||||
public: | |||||
RenderDrawColor(SDL_Renderer *rnd, Uint8 r, Uint8 g, Uint8 b, Uint8 a = 255): rnd_(rnd) { | |||||
SDL_GetRenderDrawColor(rnd_, &r_, &g_, &b_, &a_); | |||||
SDL_SetRenderDrawColor(rnd_, r, g, b, a); | |||||
} | |||||
void change(Uint8 r, Uint8 g, Uint8 b, Uint8 a = 255) { | |||||
SDL_SetRenderDrawColor(rnd_, r, g, b, a); | |||||
} | |||||
~RenderDrawColor() { | |||||
SDL_SetRenderDrawColor(rnd_, r_, g_, b_, a_); | |||||
} | |||||
private: | |||||
SDL_Renderer *rnd_; | |||||
Uint8 r_, g_, b_, a_; | |||||
}; | |||||
class RenderClipRect: NonCopyable { | |||||
public: | |||||
RenderClipRect(SDL_Renderer *rnd, SDL_Rect *rect): rnd_(rnd) { | |||||
enabled_ = SDL_RenderIsClipEnabled(rnd_); | |||||
SDL_RenderGetClipRect(rnd_, &rect_); | |||||
SDL_RenderSetClipRect(rnd_, rect); | |||||
} | |||||
~RenderClipRect() { | |||||
if (enabled_) | |||||
SDL_RenderSetClipRect(rnd_, &rect_); | |||||
else | |||||
SDL_RenderSetClipRect(rnd_, nullptr); | |||||
} | |||||
private: | |||||
SDL_Renderer *rnd_; | |||||
bool enabled_; | |||||
SDL_Rect rect_; | |||||
}; | |||||
class RenderTarget: NonCopyable { | |||||
public: | |||||
RenderTarget(SDL_Renderer *rnd, SDL_Texture *tex): rnd_(rnd) { | |||||
prevTarget_ = SDL_GetRenderTarget(rnd_); | |||||
SDL_SetRenderTarget(rnd_, tex); | |||||
} | |||||
~RenderTarget() { | |||||
SDL_SetRenderTarget(rnd_, prevTarget_); | |||||
} | |||||
private: | |||||
SDL_Renderer *rnd_; | |||||
SDL_Texture *prevTarget_; | |||||
}; | |||||
class TexLock: NonCopyable { | |||||
public: | |||||
TexLock(SDL_Texture *tex, SDL_Rect *rect = nullptr); | |||||
~TexLock() { SDL_UnlockTexture(tex_); } | |||||
int blit(SDL_Rect *destrect, SDL_Surface *srcsurf, SDL_Rect *srcrect = nullptr) { | |||||
return SDL_BlitSurface(srcsurf, srcrect, surf_.get(), destrect); | |||||
} | |||||
private: | |||||
SDL_Texture *tex_; | |||||
CPtr<SDL_Surface, SDL_FreeSurface> surf_; | |||||
}; | |||||
class TexColorMod: NonCopyable { | |||||
public: | |||||
TexColorMod(SDL_Texture *tex, Uint8 r, Uint8 g, Uint8 b): tex_(tex) { | |||||
SDL_GetTextureColorMod(tex_, &r_, &g_, &b_); | |||||
SDL_SetTextureColorMod(tex_, r, g, b); | |||||
} | |||||
~TexColorMod() { | |||||
SDL_SetTextureColorMod(tex_, r_, g_, b_); | |||||
} | |||||
private: | |||||
SDL_Texture *tex_; | |||||
Uint8 r_, g_, b_; | |||||
}; | |||||
class TexAlphaMod: NonCopyable { | |||||
public: | |||||
TexAlphaMod(SDL_Texture *tex, Uint8 alpha): tex_(tex) { | |||||
SDL_GetTextureAlphaMod(tex_, &alpha_); | |||||
SDL_SetTextureAlphaMod(tex_, alpha); | |||||
} | |||||
~TexAlphaMod() { | |||||
SDL_SetTextureAlphaMod(tex_, alpha_); | |||||
} | |||||
private: | |||||
SDL_Texture *tex_; | |||||
Uint8 alpha_; | |||||
}; | |||||
} |
#include <swan/common.h> | #include <swan/common.h> | ||||
#include <swan/log.h> | #include <swan/log.h> | ||||
#include <swan/drawutil.h> | #include <swan/drawutil.h> | ||||
#include <swan/gfxutil.h> | |||||
#include <swan/util.h> | #include <swan/util.h> |
libswan_deps = [ | libswan_deps = [ | ||||
common, libcygnet, libtracy, libthreads, libsdl2, libsdl2_image, | |||||
libcpptoml, libdl, libz] | |||||
common, libcygnet, libtracy, libthreads, libsdl2_image, | |||||
libcpptoml, libdl, libz, libglfw3] | |||||
libswan = declare_dependency( | libswan = declare_dependency( | ||||
include_directories: 'include', | include_directories: 'include', | ||||
'src/drawutil.cc', | 'src/drawutil.cc', | ||||
'src/Entity.cc', | 'src/Entity.cc', | ||||
'src/Game.cc', | 'src/Game.cc', | ||||
'src/gfxutil.cc', | |||||
'src/ItemStack.cc', | 'src/ItemStack.cc', | ||||
'src/LightServer.cc', | 'src/LightServer.cc', | ||||
'src/OS.cc', | 'src/OS.cc', |
#include "log.h" | #include "log.h" | ||||
#include "Clock.h" | #include "Clock.h" | ||||
#include "gfxutil.h" | |||||
#include "World.h" | #include "World.h" | ||||
#include "Game.h" | #include "Game.h" | ||||
void Game::update(float dt) { | void Game::update(float dt) { | ||||
// Zoom the window using the scroll wheel | // Zoom the window using the scroll wheel | ||||
cam_.zoom += (float)wasWheelScrolled() * 0.1f * cam_.zoom; | |||||
cam_.zoom += (float)wasWheelScrolled() * 0.05f * cam_.zoom; | |||||
if (cam_.zoom > 1) | if (cam_.zoom > 1) | ||||
cam_.zoom = 1; | cam_.zoom = 1; | ||||
else if (cam_.zoom < 0.025) | else if (cam_.zoom < 0.025) |
#include "assets.h" | #include "assets.h" | ||||
#include <SDL.h> | |||||
#include <SDL_image.h> | #include <SDL_image.h> | ||||
#include <cpptoml.h> | #include <cpptoml.h> | ||||
#include <string.h> | #include <string.h> |
#include <algorithm> | #include <algorithm> | ||||
#include <cmath> | #include <cmath> | ||||
#include "gfxutil.h" | |||||
namespace Swan { | namespace Swan { | ||||
namespace Draw { | namespace Draw { | ||||
return arr[size - 1].second; | return arr[size - 1].second; | ||||
} | } | ||||
/* | |||||
void parallaxBackground( | |||||
Win &win, SDL_Texture *tex, | |||||
std::optional<SDL_Rect> srcrect, std::optional<SDL_Rect> destrect, | |||||
float x, float y, float factor) { | |||||
SDL_Renderer *rnd = win.renderer_; | |||||
// We only need to set a clip rect if we have a destrect | |||||
std::optional<RenderClipRect> clip; | |||||
if (!srcrect) { | |||||
Uint32 fmt; | |||||
int access, w, h; | |||||
SDL_QueryTexture(tex, &fmt, &access, &w, &h); | |||||
srcrect = SDL_Rect{ 0, 0, w, h }; | |||||
} | |||||
if (destrect) { | |||||
clip.emplace(rnd, &*destrect); | |||||
} else { | |||||
int w, h; | |||||
SDL_RenderGetLogicalSize(rnd, &w, &h); | |||||
destrect = SDL_Rect{ 0, 0, w, h }; | |||||
} | |||||
x = (x * win.zoom_) * -factor; | |||||
y = (y * win.zoom_) * -factor; | |||||
SDL_Rect rect{ | |||||
0, 0, | |||||
(int)((float)srcrect->w * win.zoom_), | |||||
(int)((float)srcrect->h * win.zoom_), | |||||
}; | |||||
rect.x = (int)std::floor((int)x % rect.w); | |||||
if (rect.x > 0) rect.x -= rect.w; | |||||
rect.y = (int)std::floor((int)y % rect.h); | |||||
if (rect.y > 0) rect.y -= rect.h; | |||||
int numx = destrect->w / rect.w + 2; | |||||
int numy = destrect->h / rect.h + 2; | |||||
for (int x = 0; x < numx; ++x) { | |||||
for (int y = 0; y < numy; ++y) { | |||||
SDL_Rect r{ rect.x + x * rect.w, rect.y + y * rect.h, rect.w, rect.h }; | |||||
SDL_RenderCopy(rnd, tex, &*srcrect, &r); | |||||
} | |||||
} | |||||
} | |||||
TODO */ | |||||
} | } | ||||
} | } |
#include "gfxutil.h" | |||||
#include <stdint.h> | |||||
#include "log.h" | |||||
namespace Swan { | |||||
TexLock::TexLock(SDL_Texture *tex, SDL_Rect *rect): tex_(tex) { | |||||
// We must query the texture to get a format... | |||||
uint32_t format; | |||||
int access, texw, texh; | |||||
if (SDL_QueryTexture(tex_, &format, &access, &texw, &texh) < 0) { | |||||
panic << "Failed to query texture: " << SDL_GetError(); | |||||
abort(); | |||||
} | |||||
SDL_Rect lockrect = rect == NULL | |||||
? SDL_Rect{ 0, 0, texw, texh } | |||||
: *rect; | |||||
// ...and convert that format into masks... | |||||
int bpp = 32; | |||||
uint32_t rmask, gmask, bmask, amask; | |||||
if (SDL_PixelFormatEnumToMasks(format, &bpp, &rmask, &gmask, &bmask, &amask) != SDL_TRUE) { | |||||
panic << "Failed to get pixel mask: " << SDL_GetError(); | |||||
abort(); | |||||
} | |||||
// ...and lock the texture... | |||||
uint8_t *pixels; | |||||
int pitch; | |||||
if (SDL_LockTexture(tex_, &lockrect, (void **)&pixels, &pitch) < 0) { | |||||
panic << "Failed to lock texture: " << SDL_GetError(); | |||||
abort(); | |||||
} | |||||
// ...in order to create a surface. | |||||
surf_.reset(SDL_CreateRGBSurfaceFrom( | |||||
pixels, lockrect.w, lockrect.h, | |||||
32, pitch, rmask, gmask, bmask, amask)); | |||||
} | |||||
} |
libdl = meson.get_compiler('cpp').find_library('dl') | libdl = meson.get_compiler('cpp').find_library('dl') | ||||
libz = meson.get_compiler('cpp').find_library('z') | libz = meson.get_compiler('cpp').find_library('z') | ||||
libglew = dependency('glew') | |||||
libglfw3 = dependency('glfw3') | |||||
libgl = dependency('OpenGL') | libgl = dependency('OpenGL') | ||||
#libgl = meson.get_compiler('cpp').find_library('GLESv2') | #libgl = meson.get_compiler('cpp').find_library('GLESv2') | ||||
libsdl2 = dependency('sdl2') | |||||
libsdl2_image = dependency('SDL2_image') | libsdl2_image = dependency('SDL2_image') | ||||
libthreads = dependency('threads') | libthreads = dependency('threads') | ||||
executable('swan', 'src/main.cc', | executable('swan', 'src/main.cc', | ||||
install: true, | install: true, | ||||
install_rpath: get_option('libdir'), | install_rpath: get_option('libdir'), | ||||
dependencies: [libswan, libcygnet, common, libimgui, libsdl2, libsdl2_image]) | |||||
dependencies: [libswan, libcygnet, common, libimgui, libsdl2_image, libgl, libglfw3]) | |||||
install_subdir('assets', install_dir: '') | install_subdir('assets', install_dir: '') |
#include <chrono> | #include <chrono> | ||||
#include <ratio> | #include <ratio> | ||||
#include <SDL.h> | |||||
#define GLFW_INCLUDE_NONE | |||||
#include <GLFW/glfw3.h> | |||||
#include <SDL_image.h> | #include <SDL_image.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <imgui.h> | #include <imgui.h> | ||||
#include <imgui_sdl.h> | |||||
#include <cygnet/gl.h> | |||||
#include <cygnet/Renderer.h> | #include <cygnet/Renderer.h> | ||||
#include <cygnet/Window.h> | |||||
#include <swan/swan.h> | #include <swan/swan.h> | ||||
#define sdlassert(expr, str) errassert(expr, str, SDL_GetError); | #define sdlassert(expr, str) errassert(expr, str, SDL_GetError); | ||||
#define imgassert(expr, str) errassert(expr, str, IMG_GetError); | #define imgassert(expr, str) errassert(expr, str, IMG_GetError); | ||||
// ImGUI and SDL have different numbers for mouse buttons | |||||
int sdlButtonToImGuiButton(uint8_t button) { | |||||
switch (button) { | |||||
case SDL_BUTTON_LEFT: | |||||
return 0; | |||||
case SDL_BUTTON_RIGHT: | |||||
return 1; | |||||
case SDL_BUTTON_MIDDLE: | |||||
return 2; | |||||
case SDL_BUTTON_X1: | |||||
return 3; | |||||
case SDL_BUTTON_X2: | |||||
return 4; | |||||
default: | |||||
warn << "Unknown mouse button: " << button; | |||||
return 4; // Let's call that X2? | |||||
static Game *gameptr; | |||||
static double pixelRatio = 1; | |||||
static void keyCallback(GLFWwindow *, int key, int scancode, int action, int) { | |||||
if (action == GLFW_PRESS) { | |||||
gameptr->onKeyDown(scancode); | |||||
} else if (action == GLFW_RELEASE) { | |||||
gameptr->onKeyUp(scancode); | |||||
} | } | ||||
} | } | ||||
int main(int argc, char **argv) { | |||||
uint32_t winFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; | |||||
uint32_t renderFlags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC; | |||||
float guiScale = 1; | |||||
for (int i = 1; i < argc; ++i) { | |||||
if (strcmp(argv[i], "--lodpi") == 0) { | |||||
winFlags &= ~SDL_WINDOW_ALLOW_HIGHDPI; | |||||
} else if (strcmp(argv[i], "--fullscreen") == 0) { | |||||
winFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; | |||||
} else if (strcmp(argv[i], "--no-vsync") == 0) { | |||||
renderFlags &= ~SDL_RENDERER_PRESENTVSYNC; | |||||
} else if (strcmp(argv[i], "--vulkan") == 0) { | |||||
winFlags |= SDL_WINDOW_VULKAN; | |||||
} else if (strcmp(argv[i], "--sw-render") == 0) { | |||||
renderFlags &= ~SDL_RENDERER_ACCELERATED; | |||||
renderFlags |= SDL_RENDERER_SOFTWARE; | |||||
} else if (strcmp(argv[i], "--2x") == 0) { | |||||
guiScale = 2; | |||||
} else if (strcmp(argv[i], "--gles") == 0) { | |||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles2"); | |||||
} else { | |||||
warn << "Unknown argument: " << argv[i]; | |||||
} | |||||
static void mouseButtonCallback(GLFWwindow *, int button, int action, int) { | |||||
if (action == GLFW_PRESS) { | |||||
gameptr->onMouseDown(button); | |||||
} else if (action == GLFW_RELEASE) { | |||||
gameptr->onMouseUp(button); | |||||
} | } | ||||
} | |||||
sdlassert(SDL_Init(SDL_INIT_VIDEO) >= 0, "Could not initialize SDL"); | |||||
Deferred<SDL_Quit> sdl; | |||||
static void cursorPositionCallback(GLFWwindow *, double xpos, double ypos) { | |||||
gameptr->onMouseMove(xpos * pixelRatio, ypos * pixelRatio); | |||||
} | |||||
static void scrollCallback(GLFWwindow *, double dx, double dy) { | |||||
gameptr->onScrollWheel(dy); | |||||
} | |||||
static void windowSizeCallback(GLFWwindow *window, int width, int height) { | |||||
int dw, dh; | |||||
glfwGetFramebufferSize(window, &dw, &dh); | |||||
glViewport(0, 0, dw, dh); | |||||
Cygnet::glCheck(); | |||||
gameptr->cam_.size = {dw, dh}; | |||||
pixelRatio = (double)dw / (double)width; | |||||
} | |||||
int main(int argc, char **argv) { | |||||
glfwInit(); | |||||
Deferred<glfwTerminate> glfw; | |||||
glfwSetErrorCallback(+[](int error, const char* description) { | |||||
warn << "GLFW Error: " << error << ": " << description; | |||||
}); | |||||
int imgFlags = IMG_INIT_PNG; | int imgFlags = IMG_INIT_PNG; | ||||
imgassert(IMG_Init(imgFlags) == imgFlags, "Could not initialize SDL_Image"); | imgassert(IMG_Init(imgFlags) == imgFlags, "Could not initialize SDL_Image"); | ||||
Deferred<IMG_Quit> sdlImage; | Deferred<IMG_Quit> sdlImage; | ||||
Cygnet::Window window("Project: SWAN", 640 * guiScale, 480 * guiScale); | |||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); | |||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); | |||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | |||||
GLFWwindow *window = glfwCreateWindow(640, 480, "Project: SWAN", nullptr, nullptr); | |||||
if (!window) { | |||||
panic << "Failed to create window"; | |||||
return 1; | |||||
} | |||||
glfwMakeContextCurrent(window); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
glEnable(GL_BLEND); | |||||
// Create one global VAO, so we can pretend VAOs don't exist | |||||
GLuint globalVao; | |||||
glGenVertexArrays(1, &globalVao); | |||||
glBindVertexArray(globalVao); | |||||
// Load and display application icon | // Load and display application icon | ||||
/* | |||||
CPtr<SDL_Surface, SDL_FreeSurface> icon( | CPtr<SDL_Surface, SDL_FreeSurface> icon( | ||||
IMG_Load("assets/icon.png")); | IMG_Load("assets/icon.png")); | ||||
sdlassert(icon, "Could not load icon"); | sdlassert(icon, "Could not load icon"); | ||||
SDL_SetWindowIcon(window.sdlWindow(), icon.get()); | |||||
SDL_SetWindowIcon(window.sdlWindow(), icon.get());*/ | |||||
// Init ImGUI and ImGUI_SDL | // Init ImGUI and ImGUI_SDL | ||||
/* | /* | ||||
// Create a world | // Create a world | ||||
Game game; | Game game; | ||||
game.cam_.size = window.size(); | |||||
std::vector<std::string> mods{ "core.mod" }; | std::vector<std::string> mods{ "core.mod" }; | ||||
game.createWorld("core::default", mods); | game.createWorld("core::default", mods); | ||||
gameptr = &game; | |||||
glfwSetKeyCallback(window, keyCallback); | |||||
glfwSetMouseButtonCallback(window, mouseButtonCallback); | |||||
glfwSetCursorPosCallback(window, cursorPositionCallback); | |||||
glfwSetScrollCallback(window, scrollCallback); | |||||
glfwSetWindowSizeCallback(window, windowSizeCallback); | |||||
// Initialize window size stuff | |||||
{ | |||||
int width, height; | |||||
glfwGetWindowSize(window, &width, &height); | |||||
windowSizeCallback(window, width, height); | |||||
} | |||||
auto prevTime = std::chrono::steady_clock::now(); | auto prevTime = std::chrono::steady_clock::now(); | ||||
float fpsAcc = 0; | float fpsAcc = 0; | ||||
int fCount = 0; | int fCount = 0; | ||||
int slowFrames = 0; | int slowFrames = 0; | ||||
while (1) { | |||||
while (!glfwWindowShouldClose(window)) { | |||||
ZoneScopedN("game loop"); | ZoneScopedN("game loop"); | ||||
SDL_Event evt; | |||||
while (SDL_PollEvent(&evt)) { | |||||
switch (evt.type) { | |||||
case SDL_QUIT: | |||||
goto exit; | |||||
break; | |||||
case SDL_WINDOWEVENT: | |||||
if (evt.window.event == SDL_WINDOWEVENT_RESIZED) { | |||||
window.onResize(evt.window.data1, evt.window.data2); | |||||
//imguiIO.DisplaySize.x = (float)evt.window.data1; | |||||
//imguiIO.DisplaySize.y = (float)evt.window.data2; | |||||
} | |||||
break; | |||||
case SDL_KEYDOWN: | |||||
game.onKeyDown(evt.key.keysym); | |||||
break; | |||||
case SDL_KEYUP: | |||||
game.onKeyUp(evt.key.keysym); | |||||
break; | |||||
case SDL_MOUSEMOTION: | |||||
/* | |||||
imguiIO.MousePos.x = (float)evt.motion.x; | |||||
imguiIO.MousePos.y = (float)evt.motion.y; | |||||
if (!imguiIO.WantCaptureMouse) */ | |||||
game.onMouseMove( | |||||
evt.motion.x * window.pixelRatio(), | |||||
evt.motion.y * window.pixelRatio()); | |||||
break; | |||||
case SDL_MOUSEBUTTONDOWN: | |||||
/* | |||||
imguiIO.MouseDown[sdlButtonToImGuiButton(evt.button.button)] = true; | |||||
if (!imguiIO.WantCaptureMouse) */ | |||||
game.onMouseDown( | |||||
evt.button.x * window.pixelRatio(), | |||||
evt.button.y * window.pixelRatio(), | |||||
evt.button.button); | |||||
break; | |||||
case SDL_MOUSEBUTTONUP: | |||||
/* | |||||
imguiIO.MouseDown[sdlButtonToImGuiButton(evt.button.button)] = false; | |||||
if (!imguiIO.WantCaptureMouse) */ | |||||
game.onMouseUp( | |||||
evt.button.x * window.pixelRatio(), | |||||
evt.button.y * window.pixelRatio(), | |||||
evt.button.button); | |||||
break; | |||||
case SDL_MOUSEWHEEL: | |||||
if (evt.wheel.y == 0) { | |||||
break; | |||||
} | |||||
/* | |||||
imguiIO.MouseWheel += (float)evt.wheel.y; | |||||
if (!imguiIO.WantCaptureMouse) */ | |||||
game.onScrollWheel(evt.wheel.y); | |||||
break; | |||||
} | |||||
} | |||||
game.cam_.size = window.size(); | |||||
auto now = std::chrono::steady_clock::now(); | auto now = std::chrono::steady_clock::now(); | ||||
std::chrono::duration<float> dur(now - prevTime); | std::chrono::duration<float> dur(now - prevTime); | ||||
prevTime = now; | prevTime = now; | ||||
} | } | ||||
{ | { | ||||
window.clear(game.backgroundColor()); | |||||
Cygnet::Color color = game.backgroundColor(); | |||||
glClearColor(color.r, color.g, color.b, color.a); | |||||
glClear(GL_COLOR_BUFFER_BIT); | |||||
} | } | ||||
// ImGUI | // ImGUI | ||||
{ | { | ||||
ZoneScopedN("render present"); | ZoneScopedN("render present"); | ||||
window.flip(); | |||||
glfwSwapBuffers(window); | |||||
} | } | ||||
glfwPollEvents(); | |||||
FrameMark | FrameMark | ||||
} | } | ||||
exit: | |||||
return EXIT_SUCCESS; | |||||
} | } |
Subproject commit 6cb719dc505a9328c6b1fdb801acb64d8d703dda |
include_directories: 'fmt/include')) | include_directories: 'fmt/include')) | ||||
libimgui = declare_dependency( | libimgui = declare_dependency( | ||||
include_directories: ['imgui', 'imgui-plot/include', 'imgui_sdl'], | |||||
include_directories: ['imgui', 'imgui-plot/include'], | |||||
link_with: library('imgui', | link_with: library('imgui', | ||||
'imgui/imgui_demo.cpp', | 'imgui/imgui_demo.cpp', | ||||
'imgui/imgui_draw.cpp', | 'imgui/imgui_draw.cpp', | ||||
'imgui/imgui_widgets.cpp', | 'imgui/imgui_widgets.cpp', | ||||
'imgui/imgui.cpp', | 'imgui/imgui.cpp', | ||||
'imgui_sdl/imgui_sdl.cpp', | |||||
'imgui-plot/src/imgui_plot.cpp', | 'imgui-plot/src/imgui_plot.cpp', | ||||
include_directories: ['imgui', 'imgui-plot/include', 'imgui_sdl'], | |||||
dependencies: libsdl2, | |||||
include_directories: ['imgui', 'imgui-plot/include'], | |||||
cpp_args: ['-Wno-sign-compare', '-Wno-deprecated-enum-enum-conversion'])) | cpp_args: ['-Wno-sign-compare', '-Wno-deprecated-enum-enum-conversion'])) | ||||
libmsgpack = declare_dependency( | libmsgpack = declare_dependency( |