keid-render-basic-0.1.8.0: src/Render/Unlit/TileMap/Code.hs
module Render.Unlit.TileMap.Code
( vert
, frag
) where
import RIO
import Render.Code (Code, glsl)
import Render.Samplers qualified as Samplers
import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2)
vert :: Code
vert = fromString
[glsl|
#version 450
${set0binding0}
// vertexPos
layout(location = 0) in vec3 vPosition;
// vertexAttrs
layout(location = 1) in vec2 vTexCoord;
// tilemapParams
layout(location = 2) in ivec4 iTextureIds; // combined: tileset, tileset sampler, map, repeat
layout(location = 3) in vec2 iViewOffset;
layout(location = 4) in vec2 iViewportSize;
layout(location = 5) in vec2 iMapTextureSize;
layout(location = 6) in vec2 iTilesetTextureSize;
layout(location = 7) in vec2 iTileSize;
layout(location = 8) in vec2 iTilesetOffset;
layout(location = 9) in vec2 iTilesetBorder;
// transformMat
layout(location = 10) in mat4 iModel;
layout(location = 0) out vec2 fTexCoord;
layout(location = 1) out vec2 fPixCoord;
layout(location = 2) flat out ivec4 fTextureIds;
layout(location = 3) flat out vec2 fTilesetTextureSizeInv;
layout(location = 4) flat out vec2 fTileSize;
layout(location = 5) flat out vec2 fTilesetOffset;
layout(location = 6) flat out vec2 fTilesetBorder;
void main() {
vec4 fPosition = iModel * vec4(vPosition, 1.0);
gl_Position
= scene.projection
* scene.view
* fPosition;
fPixCoord = (vTexCoord * iViewportSize) + iViewOffset;
fTexCoord = fPixCoord / iMapTextureSize / iTileSize;
fTextureIds = iTextureIds;
fTilesetTextureSizeInv = 1.0 / iTilesetTextureSize;
fTileSize = iTileSize;
fTilesetOffset = iTilesetOffset * fTilesetTextureSizeInv;
fTilesetBorder = iTilesetBorder * fTilesetTextureSizeInv;
}
|]
frag :: Code
frag = fromString
[glsl|
#version 450
#extension GL_EXT_nonuniform_qualifier : enable
${set0binding1}
${set0binding2}
layout(location = 0) in vec2 fTexCoord;
layout(location = 1) in vec2 fPixCoord;
// combined: tileset, tileset sampler, map, repeat
layout(location = 2) flat in ivec4 fTextureIds;
layout(location = 3) flat in vec2 fTilesetTextureSizeInv;
layout(location = 4) flat in vec2 fTileSize;
layout(location = 5) flat in vec2 fTilesetOffset;
layout(location = 6) flat in vec2 fTilesetBorder;
layout(location = 0) out vec4 oColor;
int tilesetTextureIx = fTextureIds[0];
int tilesetSamplerIx = fTextureIds[1]; // XXX: can have repeat, but not mips
int mapTextureIx = fTextureIds[2];
int repeatTiles = fTextureIds[3];
// TODO
// const vec4 fTextureGamma = vec4(1.0);
void main() {
if (repeatTiles == 0 && (fTexCoord.x < 0.0 || fTexCoord.y < 0.0 || fTexCoord.x > 1.0 || fTexCoord.y > 1.0)) {
discard;
}
vec4 map = textureLod(
sampler2D(
textures[nonuniformEXT(mapTextureIx)],
samplers[$samplerId]
),
fTexCoord,
0
);
vec2 tilePos = floor(map.xy * 256.0);
vec2 spriteOffset = tilePos * fTileSize;
vec2 spriteCoord = mod(fPixCoord, fTileSize);
uint flags = uint(map.w * 256.0);
// XXX: Anti-diagonal flip first, to allow rotation with H/V flips
if ((flags & 0x20) == 0x20)
spriteCoord = spriteCoord.yx;
if ((flags & 0x40) == 0x40)
spriteCoord.x = fTileSize.x - spriteCoord.x;
if ((flags & 0x80) == 0x80)
spriteCoord.y = fTileSize.y - spriteCoord.y;
vec2 tilesetPadding = fTilesetOffset + tilePos * fTilesetBorder;
vec2 spriteUV =
spriteOffset * fTilesetTextureSizeInv +
spriteCoord * fTilesetTextureSizeInv +
tilesetPadding;
oColor = textureLod(
sampler2D(
textures[nonuniformEXT(tilesetTextureIx)],
samplers[nonuniformEXT(tilesetSamplerIx)]
),
spriteUV,
0
);
}
|]
where
samplerId = Samplers.nearest Samplers.indices