@@ -9,6 +9,7 @@ struct AtlasState; | |||
class TileAtlas { | |||
public: | |||
TileAtlas(); | |||
TileAtlas(TileAtlas &&); | |||
~TileAtlas(); | |||
void addTile(size_t tileId, const void *data); |
@@ -25,6 +25,7 @@ TileAtlas::TileAtlas(): state_(std::make_unique<AtlasState>()) { | |||
state_->tilesPerLine = std::min(size / SwanCommon::TILE_SIZE, 256); | |||
} | |||
TileAtlas::TileAtlas(TileAtlas &&) = default; | |||
TileAtlas::~TileAtlas() = default; | |||
void TileAtlas::addTile(size_t tileId, const void *data) { |
@@ -3,6 +3,8 @@ | |||
namespace Cygnet::Shaders { | |||
const char *spriteVx = R"glsl( | |||
#define TILE_SIZE 32.0 | |||
uniform mat3 camera; | |||
uniform mat3 transform; | |||
uniform vec3 frameInfo; // frame height, frame count, frame index | |||
@@ -10,10 +12,15 @@ const char *spriteVx = R"glsl( | |||
varying vec2 v_texCoord; | |||
void main() { | |||
// Here, I'm basically treating 1/(TILE_SIZE*16) as half the size of a "pixel". | |||
// 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); | |||
v_texCoord = vec2( | |||
vertex.x, | |||
(frameInfo.x * frameInfo.z + (frameInfo.x * vertex.y)) / | |||
(frameInfo.x * frameInfo.y)); | |||
(frameInfo.x * frameInfo.y) + pixoffset); | |||
vec3 pos = camera * transform * vec3(vertex, 1); | |||
gl_Position = vec4(pos.xy, 0, 1); | |||
@@ -59,9 +66,12 @@ const char *chunkFr = R"glsl( | |||
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( | |||
tileID + v_tileCoord.x - tilePos.x, | |||
floor(tileID / tileAtlasSize.x) + v_tileCoord.y - tilePos.y); | |||
pixoffset.x + tileID + offset.x, | |||
pixoffset.y + floor(tileID / tileAtlasSize.x) + offset.y); | |||
gl_FragColor = texture2D(tileAtlas, atlasPos / tileAtlasSize); | |||
} |
@@ -53,19 +53,19 @@ int main() { | |||
"core.mod/assets/tile/tree-trunk.png", | |||
}) addTile(rbuilder, path); | |||
unsigned char lolTexture[32*32*4*3]; | |||
unsigned char animTexture[32*32*4*3]; | |||
for (size_t i = 0; i < 3; ++i) { | |||
int col = 100 * i + 50;; | |||
for (size_t y = 0; y < 32; ++y) { | |||
for (size_t x = 0; x < 32; ++x) { | |||
lolTexture[i * 32 * 32 * 4 + y * 32 * 4 + x * 4 + 0] = col; | |||
lolTexture[i * 32 * 32 * 4 + y * 32 * 4 + x * 4 + 1] = col; | |||
lolTexture[i * 32 * 32 * 4 + y * 32 * 4 + x * 4 + 2] = col; | |||
lolTexture[i * 32 * 32 * 4 + y * 32 * 4 + x * 4 + 3] = 255; | |||
animTexture[i * 32 * 32 * 4 + y * 32 * 4 + x * 4 + 0] = col; | |||
animTexture[i * 32 * 32 * 4 + y * 32 * 4 + x * 4 + 1] = col; | |||
animTexture[i * 32 * 32 * 4 + y * 32 * 4 + x * 4 + 2] = col; | |||
animTexture[i * 32 * 32 * 4 + y * 32 * 4 + x * 4 + 3] = 255; | |||
} | |||
} | |||
} | |||
rbuilder.addTile(10, lolTexture, 3); | |||
rbuilder.addTile(10, animTexture, 3); | |||
Cygnet::RenderSprite playerSprite = loadSprite( | |||
rbuilder, "core.mod/assets/entity/player-still.png", 64); | |||
@@ -79,6 +79,11 @@ int main() { | |||
tiles[0] = 1; | |||
tiles[1] = 2; | |||
tiles[2] = 3; | |||
for (int y = 0; y < 8; ++y) { | |||
for (int x = 0; x < 8; ++x) { | |||
tiles[y * SwanCommon::CHUNK_WIDTH + x] = 10; | |||
} | |||
} | |||
tiles[10] = 10; | |||
chunk = rnd.createChunk(tiles); | |||
} | |||
@@ -89,7 +94,7 @@ int main() { | |||
.zoom = 1, | |||
}; | |||
float lol = 0; | |||
float animAcc = 0; | |||
bool keys[512] = { 0 }; | |||
@@ -103,7 +108,7 @@ int main() { | |||
double currTime = getTime(); | |||
double dt = currTime - prevTime; | |||
prevTime = currTime; | |||
lol += dt; | |||
animAcc += dt; | |||
fpsAcc += dt; | |||
frames += 1; | |||
@@ -163,8 +168,8 @@ int main() { | |||
rnd.drawChunk(chunk, { 0, 0 }); | |||
rnd.drawSprite(playerSprite, { x, y }, (int)lol % 2); | |||
cam.pos = { x, y }; | |||
rnd.drawSprite(playerSprite, { x, y }, (int)animAcc % 2); | |||
cam.pos = { x + 0.5f, y + 0.5f }; | |||
win.clear(); | |||
rnd.draw(cam); |