@@ -23,7 +23,11 @@ void PlayerEntity::draw(const Swan::Context &ctx, Cygnet::Renderer &rnd) { | |||
mat.translate({-0.5, 0}).scale({-1, 1}).translate({0.5, 0}); | |||
} | |||
anims_[(int)state_].draw(rnd, mat.translate(body_.pos)); | |||
anims_[(int)state_].draw(rnd, mat.translate( | |||
body_.pos - Swan::Vec2{0.2, 0.1})); | |||
rnd.drawRect(mouseTile_, {1, 1}); | |||
rnd.drawRect(body_.pos, body_.size); | |||
} | |||
void PlayerEntity::update(const Swan::Context &ctx, float dt) { |
@@ -23,10 +23,6 @@ struct RenderSprite { | |||
int frameCount; | |||
}; | |||
struct RenderTile { | |||
uint16_t id; | |||
}; | |||
struct RenderCamera { | |||
SwanCommon::Vec2 pos = {0, 0}; | |||
SwanCommon::Vec2i size = {1, 1}; | |||
@@ -42,6 +38,7 @@ public: | |||
void drawChunk(RenderChunk chunk, SwanCommon::Vec2 pos); | |||
void drawSprite(RenderSprite sprite, Mat3gf mat, int y = 0); | |||
void drawRect(SwanCommon::Vec2 pos, SwanCommon::Vec2 size); | |||
void draw(const RenderCamera &cam); | |||
@@ -71,12 +68,18 @@ private: | |||
RenderSprite sprite; | |||
}; | |||
struct DrawRect { | |||
SwanCommon::Vec2 pos; | |||
SwanCommon::Vec2 size; | |||
}; | |||
SwanCommon::Vec2 winScale_ = {1, 1}; | |||
std::unique_ptr<RendererState> state_; | |||
std::vector<DrawChunk> drawChunks_; | |||
std::vector<DrawSprite> drawSprites_; | |||
std::vector<DrawRect> drawRects_; | |||
}; | |||
inline void Renderer::drawChunk(RenderChunk chunk, SwanCommon::Vec2 pos) { | |||
@@ -87,4 +90,8 @@ inline void Renderer::drawSprite(RenderSprite sprite, Mat3gf mat, int frame) { | |||
drawSprites_.push_back({mat, frame, sprite}); | |||
} | |||
inline void Renderer::drawRect(SwanCommon::Vec2 pos, SwanCommon::Vec2 size) { | |||
drawRects_.push_back({pos, size}); | |||
} | |||
} |
@@ -48,7 +48,7 @@ public: | |||
Renderer &rnd_; | |||
std::unordered_map<std::string, RenderSprite> sprites_; | |||
std::unordered_map<std::string, RenderTile> tiles_; | |||
std::unordered_map<std::string, Renderer::TileID> tiles_; | |||
std::vector<ResourceTileAnimation> tileAnims_; | |||
}; | |||
@@ -2,10 +2,13 @@ | |||
namespace Cygnet::Shaders { | |||
extern const char *chunkVx; | |||
extern const char *chunkFr; | |||
extern const char *spriteVx; | |||
extern const char *spriteFr; | |||
extern const char *chunkVx; | |||
extern const char *chunkFr; | |||
extern const char *rectVx; | |||
extern const char *rectFr; | |||
} |
@@ -73,6 +73,55 @@ struct ChunkProg: public GlProgram { | |||
} | |||
}; | |||
struct RectProg: public GlProgram { | |||
template<typename... T> | |||
RectProg(const T &... shaders): GlProgram(shaders...) { init(); } | |||
~RectProg() { deinit(); } | |||
GLint camera = uniformLoc("camera"); | |||
GLint pos = uniformLoc("pos"); | |||
GLint size = uniformLoc("size"); | |||
GLint vertex = attribLoc("vertex"); | |||
GLuint vbo; | |||
static constexpr GLfloat vertexes[] = { | |||
0.0f, 0.0f, // pos 0: top left | |||
0.0f, 1.0f, // pos 1: bottom left | |||
1.0f, 1.0f, // pos 2: bottom right | |||
1.0f, 1.0f, // pos 2: bottom right | |||
1.0f, 0.0f, // pos 3: top right | |||
0.0f, 0.0f, // pos 0: top left | |||
}; | |||
void enable() { | |||
glUseProgram(id()); | |||
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |||
glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); | |||
glEnableVertexAttribArray(vertex); | |||
glCheck(); | |||
} | |||
void disable() { | |||
glDisableVertexAttribArray(vertex); | |||
glCheck(); | |||
} | |||
void init() { | |||
glGenBuffers(1, &vbo); | |||
glCheck(); | |||
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW); | |||
glCheck(); | |||
} | |||
void deinit() { | |||
glDeleteBuffers(1, &vbo); | |||
glCheck(); | |||
} | |||
}; | |||
struct SpriteProg: public GlProgram { | |||
template<typename... T> | |||
SpriteProg(const T &... shaders): GlProgram(shaders...) { init(); } | |||
@@ -131,9 +180,12 @@ struct RendererState { | |||
GlFrShader spriteFr{Shaders::spriteFr}; | |||
GlVxShader chunkVx{Shaders::chunkVx}; | |||
GlFrShader chunkFr{Shaders::chunkFr}; | |||
GlVxShader rectVx{Shaders::rectVx}; | |||
GlFrShader rectFr{Shaders::rectFr}; | |||
SpriteProg spriteProg{spriteVx, spriteFr}; | |||
ChunkProg chunkProg{chunkVx, chunkFr}; | |||
RectProg rectProg{rectVx, rectFr}; | |||
GLuint atlasTex; | |||
SwanCommon::Vec2 atlasTexSize; | |||
@@ -163,6 +215,7 @@ void Renderer::draw(const RenderCamera &cam) { | |||
auto &chunkProg = state_->chunkProg; | |||
auto &spriteProg = state_->spriteProg; | |||
auto &rectProg = state_->rectProg; | |||
{ | |||
chunkProg.enable(); | |||
@@ -206,6 +259,22 @@ void Renderer::draw(const RenderCamera &cam) { | |||
drawSprites_.clear(); | |||
spriteProg.disable(); | |||
} | |||
{ | |||
rectProg.enable(); | |||
glUniformMatrix3fv(rectProg.camera, 1, GL_TRUE, camMat.data()); | |||
glCheck(); | |||
for (auto [pos, size]: drawRects_) { | |||
glUniform2f(rectProg.pos, pos.x, pos.y); | |||
glUniform2f(rectProg.size, size.x, size.y); | |||
glDrawArrays(GL_TRIANGLES, 0, 6); | |||
glCheck(); | |||
} | |||
drawRects_.clear(); | |||
rectProg.disable(); | |||
} | |||
} | |||
void Renderer::uploadTileAtlas(const void *data, int width, int height) { |
@@ -2,6 +2,46 @@ | |||
namespace Cygnet::Shaders { | |||
const char *chunkVx = R"glsl( | |||
uniform mat3 camera; | |||
uniform vec2 pos; | |||
attribute vec2 vertex; | |||
varying vec2 v_tileCoord; | |||
void main() { | |||
vec3 pos = camera * vec3(pos + vertex, 1); | |||
gl_Position = vec4(pos.xy, 0, 1); | |||
v_tileCoord = vertex; | |||
} | |||
)glsl"; | |||
const char *chunkFr = R"glsl( | |||
precision mediump float; | |||
#define TILE_SIZE 32.0 | |||
#define CHUNK_WIDTH 64 | |||
#define CHUNK_HEIGHT 64 | |||
varying vec2 v_tileCoord; | |||
uniform sampler2D tileAtlas; | |||
uniform vec2 tileAtlasSize; | |||
uniform sampler2D tiles; | |||
void main() { | |||
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); | |||
// 1/(TILE_SIZE*16) plays the same role here as in the sprite vertex shader. | |||
vec2 offset = v_tileCoord - tilePos; | |||
vec2 pixoffset = (1.0 - offset * 2.0) / (TILE_SIZE * 16.0); | |||
vec2 atlasPos = vec2( | |||
pixoffset.x + tileID + offset.x, | |||
pixoffset.y + floor(tileID / tileAtlasSize.x) + offset.y); | |||
gl_FragColor = texture2D(tileAtlas, atlasPos / tileAtlasSize); | |||
} | |||
)glsl"; | |||
const char *spriteVx = R"glsl( | |||
#define TILE_SIZE 32.0 | |||
@@ -38,43 +78,36 @@ const char *spriteFr = R"glsl( | |||
} | |||
)glsl"; | |||
const char *chunkVx = R"glsl( | |||
const char *rectVx = R"glsl( | |||
uniform mat3 camera; | |||
uniform vec2 pos; | |||
uniform vec2 size; | |||
attribute vec2 vertex; | |||
varying vec2 v_tileCoord; | |||
varying vec2 v_coord; | |||
void main() { | |||
vec3 pos = camera * vec3(pos + vertex, 1); | |||
vec3 pos = camera * vec3(pos + vertex * size, 1); | |||
gl_Position = vec4(pos.xy, 0, 1); | |||
v_tileCoord = vec2(vertex.x, vertex.y); | |||
v_coord = vertex * size; | |||
} | |||
)glsl"; | |||
const char *chunkFr = R"glsl( | |||
const char *rectFr = R"glsl( | |||
precision mediump float; | |||
#define TILE_SIZE 32.0 | |||
#define CHUNK_WIDTH 64 | |||
#define CHUNK_HEIGHT 64 | |||
#define THICKNESS 0.02 | |||
varying vec2 v_tileCoord; | |||
uniform sampler2D tileAtlas; | |||
uniform vec2 tileAtlasSize; | |||
uniform sampler2D tiles; | |||
varying vec2 v_coord; | |||
uniform vec2 size; | |||
void main() { | |||
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); | |||
// 1/(TILE_SIZE*16) plays the same role here as in the sprite vertex shader. | |||
vec2 offset = v_tileCoord - tilePos; | |||
vec2 pixoffset = (1.0 - offset * 2.0) / (TILE_SIZE * 16.0); | |||
vec2 atlasPos = vec2( | |||
pixoffset.x + tileID + offset.x, | |||
pixoffset.y + floor(tileID / tileAtlasSize.x) + offset.y); | |||
gl_FragColor = texture2D(tileAtlas, atlasPos / tileAtlasSize); | |||
// TODO: This probably shouldn't be an if? | |||
if ( | |||
v_coord.x < THICKNESS || v_coord.x > size.x - THICKNESS || | |||
v_coord.y < THICKNESS || v_coord.y > size.y - THICKNESS) { | |||
gl_FragColor = vec4(0.6, 0.6, 0.6, 0.8); | |||
} else { | |||
gl_FragColor = vec4(0, 0, 0, 0); | |||
} | |||
} | |||
)glsl"; | |||
@@ -308,7 +308,7 @@ void World::update(float dt) { | |||
for (auto &plane: planes_) | |||
plane->update(dt); | |||
game_->cam_.pos = player_->pos + Vec2{0.5, 0.5}; | |||
game_->cam_.pos = player_->pos + player_->size / 2; | |||
} | |||
void World::tick(float dt) { |