@@ -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(); |