| @@ -15,8 +15,15 @@ PlayerEntity::PlayerEntity(const Swan::Context &ctx, const PackObject &obj): | |||
| } | |||
| void PlayerEntity::draw(const Swan::Context &ctx, Cygnet::Renderer &rnd) { | |||
| // body_.outline(win); TODO | |||
| anims_[(int)state_].draw(body_.pos - Swan::Vec2(0.2, 0.1), rnd); | |||
| Cygnet::Mat3gf mat; | |||
| // Currently, there is no sprite for running left. | |||
| // Running left is just running right but flipped. | |||
| if (state_ == State::RUNNING_L) { | |||
| mat.translate({-0.5, 0}).scale({-1, 1}).translate({0.5, 0}); | |||
| } | |||
| anims_[(int)state_].draw(rnd, mat.translate(body_.pos)); | |||
| } | |||
| void PlayerEntity::update(const Swan::Context &ctx, float dt) { | |||
| @@ -37,9 +37,7 @@ private: | |||
| PhysicsEntity(SIZE), | |||
| anims_{ | |||
| Swan::Animation(ctx.world.getSprite("core::entity/player-still"), 0.8), | |||
| Swan::Animation( | |||
| ctx.world.getSprite("core::entity/player-running"), | |||
| 1, Cygnet::Mat3gf{}.scale({-1, 1}).translate({1, 0})), | |||
| Swan::Animation(ctx.world.getSprite("core::entity/player-running"), 1), | |||
| Swan::Animation(ctx.world.getSprite("core::entity/player-running"), 1), | |||
| } {} | |||
| @@ -1,6 +1,6 @@ | |||
| #pragma once | |||
| #include <iostream> | |||
| #include <ostream> | |||
| #include <cmath> | |||
| #include <array> | |||
| @@ -42,8 +42,6 @@ public: | |||
| void drawChunk(RenderChunk chunk, SwanCommon::Vec2 pos); | |||
| void drawSprite(RenderSprite sprite, Mat3gf mat, int y = 0); | |||
| void drawSprite(RenderSprite sprite, SwanCommon::Vec2 pos, int y = 0); | |||
| void drawSpriteFlipped(RenderSprite chunk, SwanCommon::Vec2 pos, int y = 0); | |||
| void draw(const RenderCamera &cam); | |||
| @@ -85,13 +83,4 @@ inline void Renderer::drawSprite(RenderSprite sprite, Mat3gf mat, int frame) { | |||
| drawSprites_.push_back({mat, frame, sprite}); | |||
| } | |||
| inline void Renderer::drawSprite(RenderSprite sprite, SwanCommon::Vec2 pos, int frame) { | |||
| drawSprites_.push_back({Mat3gf{}.translate(pos), frame, sprite}); | |||
| } | |||
| inline void Renderer::drawSpriteFlipped(RenderSprite sprite, SwanCommon::Vec2 pos, int frame) { | |||
| // TODO: Translate X by sprite.scale.x? | |||
| drawSprites_.push_back({Mat3gf{}.translate(pos).scale({-1, 1}), frame, sprite}); | |||
| } | |||
| } | |||
| @@ -80,6 +80,7 @@ struct SpriteProg: public GlProgram { | |||
| GLint camera = uniformLoc("camera"); | |||
| GLint transform = uniformLoc("transform"); | |||
| GLint frameSize = uniformLoc("frameSize"); | |||
| GLint frameInfo = uniformLoc("frameInfo"); | |||
| GLint vertex = attribLoc("vertex"); | |||
| GLint tex = uniformLoc("tex"); | |||
| @@ -151,8 +152,8 @@ void Renderer::draw(const RenderCamera &cam) { | |||
| // Make the matrix translate to { -camX, -camY }, fix up the aspect ratio, | |||
| // flip the Y axis so that positive Y direction is down, and scale according to zoom. | |||
| float ratio = (float)cam.size.y / (float)cam.size.x; | |||
| camMat.translate(cam.pos.scale(-ratio, 1) * cam.zoom); | |||
| camMat.scale({ cam.zoom * ratio, -cam.zoom }); | |||
| camMat.translate(-cam.pos); | |||
| camMat.scale({cam.zoom * ratio, -cam.zoom}); | |||
| auto &chunkProg = state_->chunkProg; | |||
| auto &spriteProg = state_->spriteProg; | |||
| @@ -188,9 +189,9 @@ void Renderer::draw(const RenderCamera &cam) { | |||
| glActiveTexture(GL_TEXTURE0); | |||
| for (auto [mat, frame, sprite]: drawSprites_) { | |||
| mat.scale(sprite.scale); | |||
| glUniformMatrix3fv(spriteProg.transform, 1, GL_TRUE, mat.data()); | |||
| glUniform3f(spriteProg.frameInfo, sprite.scale.y, sprite.frameCount, frame); | |||
| glUniform2f(spriteProg.frameSize, sprite.scale.x, sprite.scale.y); | |||
| glUniform2f(spriteProg.frameInfo, sprite.frameCount, frame); | |||
| glBindTexture(GL_TEXTURE_2D, sprite.tex); | |||
| glDrawArrays(GL_TRIANGLES, 0, 6); | |||
| glCheck(); | |||
| @@ -7,7 +7,8 @@ const char *spriteVx = R"glsl( | |||
| uniform mat3 camera; | |||
| uniform mat3 transform; | |||
| uniform vec3 frameInfo; // frame height, frame count, frame index | |||
| uniform vec2 frameSize; | |||
| uniform vec2 frameInfo; // frame count, frame index | |||
| attribute vec2 vertex; | |||
| varying vec2 v_texCoord; | |||
| @@ -16,13 +17,13 @@ const char *spriteVx = R"glsl( | |||
| // It's just an arbitrary small number, but it works as an offset to make sure | |||
| // neighbouring parts of the atlas don't bleed into the frame we actually | |||
| // want to draw due to (nearest neighbour) interpolation. | |||
| float pixoffset = (1.0 - vertex.y * 2.0) / (frameInfo.x * TILE_SIZE * 16.0); | |||
| float pixoffset = (1.0 - vertex.y * 2.0) / (frameSize.y * TILE_SIZE * 16.0); | |||
| v_texCoord = vec2( | |||
| vertex.x, | |||
| (frameInfo.x * frameInfo.z + (frameInfo.x * vertex.y)) / | |||
| (frameInfo.x * frameInfo.y) + pixoffset); | |||
| (frameSize.y * frameInfo.y + (frameSize.y * vertex.y)) / | |||
| (frameSize.y * frameInfo.x) + pixoffset); | |||
| vec3 pos = camera * transform * vec3(vertex, 1); | |||
| vec3 pos = camera * transform * vec3(vertex * frameSize, 1); | |||
| gl_Position = vec4(pos.xy, 0, 1); | |||
| } | |||
| )glsl"; | |||
| @@ -11,18 +11,23 @@ namespace Swan { | |||
| class Animation { | |||
| public: | |||
| Animation(Cygnet::RenderSprite sprite, float interval, Cygnet::Mat3gf mat = {}): | |||
| sprite_(sprite), interval_(interval), timer_(interval), mat_(mat) {} | |||
| sprite_(sprite), interval_(interval), timer_(interval) {} | |||
| void tick(float dt); | |||
| void draw(const Vec2 &pos, Cygnet::Renderer &rnd); | |||
| void reset(); | |||
| void draw(Cygnet::Renderer &rnd, Cygnet::Mat3gf mat); | |||
| private: | |||
| Cygnet::RenderSprite sprite_; | |||
| float interval_; | |||
| float timer_; | |||
| Cygnet::Mat3gf mat_; | |||
| int frame_ = 0; | |||
| }; | |||
| inline void Animation::draw(Cygnet::Renderer &rnd, Cygnet::Mat3gf mat) { | |||
| rnd.drawSprite(sprite_, mat, frame_); | |||
| } | |||
| } | |||
| @@ -15,10 +15,6 @@ void Animation::tick(float dt) { | |||
| } | |||
| } | |||
| void Animation::draw(const Vec2 &pos, Cygnet::Renderer &rnd) { | |||
| rnd.drawSprite(sprite_, Cygnet::Mat3gf(mat_).translate(pos), frame_); | |||
| } | |||
| void Animation::reset() { | |||
| timer_ = interval_; | |||
| frame_ = 0; | |||
| @@ -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}; // - (win.getSize() / 2) + (player_->size / 2); TODO | |||
| game_->cam_.pos = player_->pos + Vec2{0.5, 0.5}; | |||
| } | |||
| void World::tick(float dt) { | |||
| @@ -167,7 +167,7 @@ int main() { | |||
| rnd.drawChunk(chunk, {0, 0}); | |||
| rnd.drawSprite(playerSprite, {x, y}, (int)animAcc % 2); | |||
| rnd.drawSprite(playerSprite, Cygnet::Mat3gf{}.translate({x, y}), (int)animAcc % 2); | |||
| cam.pos = {x + 0.5f, y + 0.5f}; | |||
| win.clear(); | |||