} | } | ||||
void PlayerEntity::draw(const Swan::Context &ctx, Cygnet::Renderer &rnd) { | 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) { | void PlayerEntity::update(const Swan::Context &ctx, float dt) { |
PhysicsEntity(SIZE), | PhysicsEntity(SIZE), | ||||
anims_{ | anims_{ | ||||
Swan::Animation(ctx.world.getSprite("core::entity/player-still"), 0.8), | 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), | Swan::Animation(ctx.world.getSprite("core::entity/player-running"), 1), | ||||
} {} | } {} | ||||
#pragma once | #pragma once | ||||
#include <iostream> | |||||
#include <ostream> | |||||
#include <cmath> | #include <cmath> | ||||
#include <array> | #include <array> | ||||
void drawChunk(RenderChunk chunk, SwanCommon::Vec2 pos); | void drawChunk(RenderChunk chunk, SwanCommon::Vec2 pos); | ||||
void drawSprite(RenderSprite sprite, Mat3gf mat, int y = 0); | 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); | void draw(const RenderCamera &cam); | ||||
drawSprites_.push_back({mat, frame, sprite}); | 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}); | |||||
} | |||||
} | } |
GLint camera = uniformLoc("camera"); | GLint camera = uniformLoc("camera"); | ||||
GLint transform = uniformLoc("transform"); | GLint transform = uniformLoc("transform"); | ||||
GLint frameSize = uniformLoc("frameSize"); | |||||
GLint frameInfo = uniformLoc("frameInfo"); | GLint frameInfo = uniformLoc("frameInfo"); | ||||
GLint vertex = attribLoc("vertex"); | GLint vertex = attribLoc("vertex"); | ||||
GLint tex = uniformLoc("tex"); | GLint tex = uniformLoc("tex"); | ||||
// Make the matrix translate to { -camX, -camY }, fix up the aspect ratio, | // 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. | // 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; | 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 &chunkProg = state_->chunkProg; | ||||
auto &spriteProg = state_->spriteProg; | auto &spriteProg = state_->spriteProg; | ||||
glActiveTexture(GL_TEXTURE0); | glActiveTexture(GL_TEXTURE0); | ||||
for (auto [mat, frame, sprite]: drawSprites_) { | for (auto [mat, frame, sprite]: drawSprites_) { | ||||
mat.scale(sprite.scale); | |||||
glUniformMatrix3fv(spriteProg.transform, 1, GL_TRUE, mat.data()); | 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); | glBindTexture(GL_TEXTURE_2D, sprite.tex); | ||||
glDrawArrays(GL_TRIANGLES, 0, 6); | glDrawArrays(GL_TRIANGLES, 0, 6); | ||||
glCheck(); | glCheck(); |
uniform mat3 camera; | uniform mat3 camera; | ||||
uniform mat3 transform; | 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; | attribute vec2 vertex; | ||||
varying vec2 v_texCoord; | varying vec2 v_texCoord; | ||||
// It's just an arbitrary small number, but it works as an offset to make sure | // 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 | // neighbouring parts of the atlas don't bleed into the frame we actually | ||||
// want to draw due to (nearest neighbour) interpolation. | // 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( | v_texCoord = vec2( | ||||
vertex.x, | 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); | gl_Position = vec4(pos.xy, 0, 1); | ||||
} | } | ||||
)glsl"; | )glsl"; |
class Animation { | class Animation { | ||||
public: | public: | ||||
Animation(Cygnet::RenderSprite sprite, float interval, Cygnet::Mat3gf mat = {}): | 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 tick(float dt); | ||||
void draw(const Vec2 &pos, Cygnet::Renderer &rnd); | |||||
void reset(); | void reset(); | ||||
void draw(Cygnet::Renderer &rnd, Cygnet::Mat3gf mat); | |||||
private: | private: | ||||
Cygnet::RenderSprite sprite_; | Cygnet::RenderSprite sprite_; | ||||
float interval_; | float interval_; | ||||
float timer_; | float timer_; | ||||
Cygnet::Mat3gf mat_; | |||||
int frame_ = 0; | int frame_ = 0; | ||||
}; | }; | ||||
inline void Animation::draw(Cygnet::Renderer &rnd, Cygnet::Mat3gf mat) { | |||||
rnd.drawSprite(sprite_, mat, frame_); | |||||
} | } | ||||
} | |||||
} | } | ||||
} | } | ||||
void Animation::draw(const Vec2 &pos, Cygnet::Renderer &rnd) { | |||||
rnd.drawSprite(sprite_, Cygnet::Mat3gf(mat_).translate(pos), frame_); | |||||
} | |||||
void Animation::reset() { | void Animation::reset() { | ||||
timer_ = interval_; | timer_ = interval_; | ||||
frame_ = 0; | frame_ = 0; |
for (auto &plane: planes_) | for (auto &plane: planes_) | ||||
plane->update(dt); | 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) { | void World::tick(float dt) { |
rnd.drawChunk(chunk, {0, 0}); | 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}; | cam.pos = {x + 0.5f, y + 0.5f}; | ||||
win.clear(); | win.clear(); |