Compare commits
No commits in common. "dev" and "main" have entirely different histories.
@ -8,7 +8,6 @@ add_library(sprstk
|
||||
src/sprstk.cpp
|
||||
|
||||
src/gl.c
|
||||
src/stb_image.c
|
||||
)
|
||||
|
||||
target_include_directories(sprstk PUBLIC include PRIVATE src)
|
||||
|
@ -7,4 +7,3 @@ function(add_example name)
|
||||
endfunction()
|
||||
|
||||
add_example(basic)
|
||||
add_example(terrain)
|
||||
|
@ -1,128 +1,126 @@
|
||||
#include <sprstk/sprstk.h>
|
||||
|
||||
#include <simplexnoise1234.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Tile
|
||||
constexpr int SIZE = 256;
|
||||
|
||||
double octaves(SimplexNoise1234& simplex, double x, double y, int layers, double persistence, double frequency)
|
||||
{
|
||||
struct Type
|
||||
double ampl = 1;
|
||||
double maxval = 0;
|
||||
double val = 0;
|
||||
|
||||
for (int i = 0; i < layers; i++)
|
||||
{
|
||||
virtual unsigned int layers() const = 0;
|
||||
val += simplex.noise(x * frequency, y * frequency) * ampl;
|
||||
|
||||
bool operator==(const Type& other) const { return this == &other; }
|
||||
};
|
||||
maxval += ampl;
|
||||
|
||||
Tile();
|
||||
const Type& type;
|
||||
|
||||
unsigned int layers() const { return type.layers(); }
|
||||
bool operator==(const Tile& other) { return type == other.type; }
|
||||
};
|
||||
|
||||
namespace Tiles
|
||||
{
|
||||
|
||||
struct FloorTileType : public Tile::Type
|
||||
{
|
||||
virtual unsigned int layers() const override
|
||||
{
|
||||
return 1;
|
||||
ampl *= persistence;
|
||||
frequency *= 2;
|
||||
}
|
||||
} Floor;
|
||||
|
||||
struct WallTileType : public Tile::Type
|
||||
{
|
||||
virtual unsigned int layers() const override
|
||||
{
|
||||
return 31;
|
||||
}
|
||||
} Wall;
|
||||
|
||||
return val / maxval;
|
||||
}
|
||||
|
||||
Tile::Tile() :
|
||||
type(Tiles::Wall)
|
||||
{}
|
||||
uint8_t data[SIZE * SIZE];
|
||||
|
||||
struct AppState
|
||||
double ease(double n)
|
||||
{
|
||||
static constexpr int MAP_SIZE = 256;
|
||||
|
||||
Tile tiles[MAP_SIZE * MAP_SIZE];
|
||||
struct
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} player;
|
||||
|
||||
Tile& tile_at(int x, int y)
|
||||
{
|
||||
static Tile dummy;
|
||||
|
||||
x += MAP_SIZE / 2;
|
||||
y += MAP_SIZE / 2;
|
||||
|
||||
if (x < 0 || x >= MAP_SIZE || y < 0 || y >= MAP_SIZE) { return dummy; }
|
||||
|
||||
return tiles[x + y * MAP_SIZE];
|
||||
}
|
||||
};
|
||||
|
||||
void init(sprstk* instance, AppState* userdata)
|
||||
{
|
||||
sprstk_set_scale(instance, 8.0f);
|
||||
|
||||
sprstk_palette palette;
|
||||
for (int i = 0; i < 32; i++) { int val = i * 2 + 0x10; val <<= 24; palette.colors[i] = val | 0xFFFFFF; }
|
||||
sprstk_set_palette(instance, 0, &palette);
|
||||
|
||||
for (int i = 0; i < 32; i++) { palette.colors[i] = 0xFF00FF00; }
|
||||
sprstk_set_palette(instance, 1, &palette);
|
||||
|
||||
sprstk_load_sprites(instance, "resources/atlas.png", 8);
|
||||
return pow(n, 1.5);
|
||||
}
|
||||
|
||||
void update(sprstk* instance, float dt, AppState* userdata)
|
||||
uint32_t color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||
{
|
||||
sprstk_clear(instance);
|
||||
return (r << 24) | (g << 16) | (b << 8) | a;
|
||||
}
|
||||
|
||||
constexpr int SIZE = 4;
|
||||
int pick_pal(uint8_t height)
|
||||
{
|
||||
if (height > 20) { return 0; }
|
||||
if (height > 8) { return 1; }
|
||||
return 2;
|
||||
}
|
||||
|
||||
for (int i = -SIZE; i <= SIZE; i++)
|
||||
void init(sprstk* instance, void* userdata)
|
||||
{
|
||||
sprstk_palette pal = {};
|
||||
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
for (int j = -SIZE; j <= SIZE; j++)
|
||||
uint8_t val = 0x33 / (12 - i / 2.0f) + 0x33;
|
||||
pal.colors[i] = color(val, val, val, 0x60);
|
||||
}
|
||||
|
||||
for (int i = 24; i < 32; i++)
|
||||
{
|
||||
uint8_t val = 0x55 / (16 - i / 2.0f) + 0xAA;
|
||||
pal.colors[i] = color(val, val, val, 0x60);
|
||||
}
|
||||
|
||||
sprstk_set_palette(instance, 0, &pal);
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
pal.colors[i] = color(0x70 / (5.0f - i / 4.0f), 0x35 / (5.0f - i / 4.0f), 0, 0x60);
|
||||
}
|
||||
|
||||
for (int i = 16; i < 32; i++)
|
||||
{
|
||||
pal.colors[i] = color(0x05 / (8.5f - i / 2.5f) + 0x15, 0x40 / (8.5f - i / 2.5f) + 0x0, 0, 0x60);
|
||||
}
|
||||
|
||||
sprstk_set_palette(instance, 1, &pal);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
pal.colors[i] = color(0x20 / (8 - i) + 0x10, 0x40 / (8 - i) + 0x20, 0xB0 / (8 - i) + 0x40, 0x60);
|
||||
}
|
||||
|
||||
sprstk_set_palette(instance, 2, &pal);
|
||||
|
||||
sprstk_set_scale(instance, 0.4f);
|
||||
|
||||
SimplexNoise1234 simplex;
|
||||
for (int i = 0; i < SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < SIZE; j++)
|
||||
{
|
||||
if (i == 0 && j == 0) { continue; }
|
||||
|
||||
Tile& tile = userdata->tile_at(userdata->player.x + i, userdata->player.y + j);
|
||||
sprstk_put(instance, {
|
||||
.position = { i, j },
|
||||
.layers = tile.layers(),
|
||||
.layer_order_offset = 0,
|
||||
.palette_index = 0,
|
||||
.layer_modifiers = { i / 32.0f, j / 32.0f, 1 / 64.0f },
|
||||
.sprite = { 0, 0 },
|
||||
});
|
||||
double value = octaves(simplex, i, j, 6, 0.4, 1.0 / 128.0);
|
||||
data[i + j * SIZE] = 28 * ease((value + 1) / 2) + 3;
|
||||
}
|
||||
}
|
||||
|
||||
sprstk_tile_info info = {};
|
||||
info.position = { 0, 0 };
|
||||
info.sprite = { 1, 0 };
|
||||
info.palette_index = 1;
|
||||
sprstk_put(instance, info);
|
||||
for (int i = 0; i < SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < SIZE; j++)
|
||||
{
|
||||
sprstk_put(instance, i - SIZE / 2, j - SIZE / 2, data[i + SIZE * j], pick_pal(data[i + SIZE * j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update(sprstk* instance, float dt, float* userdata)
|
||||
{
|
||||
*userdata += dt / 2;
|
||||
sprstk_set_angle(instance, *userdata);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
AppState userdata;
|
||||
float data = 0;
|
||||
sprstk* instance = sprstk_new({.init = init, .update = (sprstk_update_fn)update}, &data);
|
||||
|
||||
sprstk* instance = sprstk_new({ .init = (sprstk_init_fn)init, .update = (sprstk_update_fn)update }, &userdata);
|
||||
sprstk_run(instance);
|
||||
|
||||
sprstk_del(instance);
|
||||
sprstk_stop(instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,224 +0,0 @@
|
||||
#include <sprstk/sprstk.h>
|
||||
|
||||
#include <simplexnoise1234.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr int SIZE = 512;
|
||||
|
||||
double octaves(SimplexNoise1234& simplex, double x, double y, int layers, double persistence, double frequency)
|
||||
{
|
||||
double ampl = 1;
|
||||
double maxval = 0;
|
||||
double val = 0;
|
||||
|
||||
for (int i = 0; i < layers; i++)
|
||||
{
|
||||
val += simplex.noise(x * frequency, y * frequency) * ampl;
|
||||
|
||||
maxval += ampl;
|
||||
|
||||
ampl *= persistence;
|
||||
frequency *= 2;
|
||||
}
|
||||
|
||||
return val / maxval;
|
||||
}
|
||||
|
||||
uint8_t data[SIZE * SIZE];
|
||||
|
||||
double split_point = 0.5;
|
||||
|
||||
double ease_f(double n)
|
||||
{
|
||||
return pow(n, 0.7);
|
||||
}
|
||||
|
||||
double ease_g(double n)
|
||||
{
|
||||
return pow(n, 2);
|
||||
}
|
||||
|
||||
double prime(double (*fn)(double), double n)
|
||||
{
|
||||
constexpr double DELTA = 0.001;
|
||||
|
||||
return (fn(n + DELTA) - fn(n)) / DELTA;
|
||||
}
|
||||
|
||||
double ease(double n)
|
||||
{
|
||||
const double fprime = prime(ease_f, n);
|
||||
const double gprime = prime(ease_g, n);
|
||||
|
||||
const double scale = (fprime / gprime) * (ease_g(1) - ease_g(split_point)) + ease_f(split_point);
|
||||
|
||||
if (n < split_point) { return ease_f(n) / scale; }
|
||||
return (fprime / gprime * (ease_g(n) - ease_g(split_point)) + ease_f(split_point)) / scale;
|
||||
}
|
||||
|
||||
uint32_t color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||
{
|
||||
return (r << 0) | (g << 8) | (b << 16) | (a << 24);
|
||||
}
|
||||
|
||||
uint32_t color(double r, double g, double b, double a)
|
||||
{
|
||||
if (r < 0) { r = 0; }
|
||||
if (r > 1) { r = 1; }
|
||||
if (g < 0) { g = 0; }
|
||||
if (g > 1) { g = 1; }
|
||||
if (b < 0) { b = 0; }
|
||||
if (b > 1) { b = 1; }
|
||||
if (a < 0) { a = 0; }
|
||||
if (a > 1) { a = 1; }
|
||||
|
||||
uint8_t r8 = r * 255.0;
|
||||
uint8_t g8 = g * 255.0;
|
||||
uint8_t b8 = b * 255.0;
|
||||
uint8_t a8 = a * 255.0;
|
||||
|
||||
return color(r8, g8, b8, a8);
|
||||
}
|
||||
|
||||
constexpr double ALPHA = 0.7;
|
||||
|
||||
const sprstk_palette* water_palette()
|
||||
{
|
||||
static sprstk_palette pal;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
pal.colors[i] = color(i / 32.0, i / 16.0, i / 8.0, ALPHA);
|
||||
}
|
||||
|
||||
return &pal;
|
||||
}
|
||||
|
||||
const sprstk_palette* sand_palette()
|
||||
{
|
||||
static sprstk_palette pal;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
pal.colors[i] = color(i / 20.0 + 0.3, i / 20.0 + 0.2, i / 20.0 + 0.1, ALPHA);
|
||||
}
|
||||
|
||||
return &pal;
|
||||
}
|
||||
|
||||
const sprstk_palette* land_palette()
|
||||
{
|
||||
static sprstk_palette pal;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if (i <= 19)
|
||||
{
|
||||
pal.colors[i] = color(i / 24.0 + 0.1, i / 36.0 + 0.05, i / 48.0, ALPHA);
|
||||
}
|
||||
else
|
||||
{
|
||||
pal.colors[i] = color(i / 40.0 - 0.1, i / 40.0 + 0.1, 0.1, ALPHA);
|
||||
}
|
||||
}
|
||||
|
||||
return &pal;
|
||||
}
|
||||
|
||||
const sprstk_palette* stone_palette()
|
||||
{
|
||||
static sprstk_palette pal;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
const double offset = (i < 28 ? -0.2 : 0.2);
|
||||
pal.colors[i] = color(i / 35.2 + offset, i / 32.0 + offset, i / 29.0 + offset, ALPHA);
|
||||
}
|
||||
|
||||
return &pal;
|
||||
}
|
||||
|
||||
const sprstk_palette* shadow_palette()
|
||||
{
|
||||
static sprstk_palette pal;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
pal.colors[i] = color(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
return &pal;
|
||||
}
|
||||
|
||||
int pick_pal(uint8_t height)
|
||||
{
|
||||
if (height < 8) { return 0; } // water
|
||||
if (height < 13) { return 1; } // sand
|
||||
if (height < 24) { return 2; } // land
|
||||
return 3;
|
||||
}
|
||||
|
||||
void init(sprstk* instance, void* userdata)
|
||||
{
|
||||
sprstk_set_palette(instance, 0, water_palette());
|
||||
sprstk_set_palette(instance, 1, sand_palette());
|
||||
sprstk_set_palette(instance, 2, land_palette());
|
||||
sprstk_set_palette(instance, 3, stone_palette());
|
||||
sprstk_set_palette(instance, 4, shadow_palette());
|
||||
|
||||
sprstk_set_scale(instance, 0.5);
|
||||
|
||||
SimplexNoise1234 simplex;
|
||||
for (int i = 0; i < SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < SIZE; j++)
|
||||
{
|
||||
double value = octaves(simplex, i, j, 6, 0.4, 1.0 / 128.0);
|
||||
data[i + j * SIZE] = 30 * ease((value + 1) / 2) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
sprstk_clear(instance);
|
||||
for (int i = 0; i < SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < SIZE; j++)
|
||||
{
|
||||
sprstk_tile_info info = {};
|
||||
info.position = { i - SIZE / 2, j - SIZE / 2 };
|
||||
info.layers = data[i + SIZE * j];
|
||||
info.layer_modifiers = { 0, 15 };
|
||||
info.palette_index = pick_pal(data[i + SIZE * j]);
|
||||
info.layer_order_offset = 1;
|
||||
sprstk_put(instance, info);
|
||||
|
||||
info.palette_index = 4;
|
||||
info.layer_modifiers = { 0.5, 15.5 };
|
||||
info.layer_order_offset = 0;
|
||||
sprstk_put(instance, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update(sprstk* instance, float dt, float* userdata)
|
||||
{
|
||||
*userdata += dt / 2;
|
||||
sprstk_set_angle(instance, *userdata);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
float data = 0;
|
||||
sprstk* instance = sprstk_new({.init = init, .update = (sprstk_update_fn)update}, &data);
|
||||
|
||||
sprstk_run(instance);
|
||||
|
||||
sprstk_del(instance);
|
||||
|
||||
return 0;
|
||||
}
|
@ -24,25 +24,6 @@ typedef struct {
|
||||
uint32_t colors[32];
|
||||
} sprstk_palette;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
int x;
|
||||
int y;
|
||||
} position;
|
||||
unsigned int layers;
|
||||
unsigned int layer_order_offset;
|
||||
unsigned int palette_index;
|
||||
struct {
|
||||
float dx;
|
||||
float dy;
|
||||
float scale;
|
||||
} layer_modifiers;
|
||||
struct {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
} sprite;
|
||||
} sprstk_tile_info;
|
||||
|
||||
sprstk* sprstk_new(sprstk_callbacks callbacks, void* userdata);
|
||||
void sprstk_del(sprstk* instance);
|
||||
|
||||
@ -51,15 +32,14 @@ void sprstk_stop(sprstk* instance);
|
||||
|
||||
void sprstk_clear(sprstk* instance);
|
||||
|
||||
void sprstk_put(sprstk* instance, sprstk_tile_info info);
|
||||
void sprstk_put(sprstk* instance, int x, int y, unsigned int layers, unsigned int palette_lookup);
|
||||
void sprstk_putz(sprstk* instance, int x, int y, unsigned int layers, unsigned int palette_lookup, unsigned int z_offset);
|
||||
|
||||
void sprstk_set_palette(sprstk* instance, unsigned int index, const sprstk_palette* palette);
|
||||
|
||||
void sprstk_set_scale(sprstk* instance, float scale);
|
||||
void sprstk_set_angle(sprstk* instance, float angle);
|
||||
|
||||
void sprstk_load_sprites(sprstk* instance, const char* filename, unsigned int tile_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 152 B |
242
src/sprstk.cpp
242
src/sprstk.cpp
@ -3,14 +3,11 @@
|
||||
#include <glad/gl.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#define STBI_ONLY_PNG
|
||||
#include <stb_image.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define OIT_LAYERS 64
|
||||
#define OIT_LAYERS 32
|
||||
#define _STRINGIFY(x) #x
|
||||
#define STRINGIFY(x) _STRINGIFY(x)
|
||||
|
||||
@ -25,41 +22,16 @@ layout (triangles, max_vertices = 128, max_primitives = 64) out;
|
||||
layout (location = 0) out PerVertexData
|
||||
{
|
||||
flat uint layer;
|
||||
flat vec4 color;
|
||||
vec2 texcoord;
|
||||
flat uint color;
|
||||
} v_out[];
|
||||
|
||||
layout (location = 1) uniform vec3 screen_size_and_pixel_scale;
|
||||
layout (location = 2) uniform float scale;
|
||||
layout (location = 3) uniform mat2 rotation_matrix;
|
||||
layout (location = 4) uniform float tile_size;
|
||||
|
||||
/*
|
||||
'packed_data[0]'
|
||||
|
||||
0 -- 7 8 -- 15 16 -- 23 24 -- 32
|
||||
[xxxxxxxx][xyyyyyyy][yylllllo][pppppppp]
|
||||
|
||||
x | x position
|
||||
y | y position
|
||||
l | layer count
|
||||
o | layer order offset
|
||||
p | palette index
|
||||
|
||||
'packed_data[1]'
|
||||
|
||||
0 -- 7 8 -- 15 16 -- 23 24 -- 32
|
||||
[aaaaaaaa][bbbbbbbb][ssssssss][iiiijjjj]
|
||||
|
||||
a | x offset per layer - 1.4.3 floating-point, exponent bias 8
|
||||
b | y offset per layer - 1.4.3 floating-point, exponent bias 8
|
||||
s | scale per layer
|
||||
i | x texture position
|
||||
j | y texture position
|
||||
*/
|
||||
struct TileInfo
|
||||
{
|
||||
uint packed_data[2];
|
||||
uint position;
|
||||
};
|
||||
|
||||
layout (std430, binding = 0) restrict readonly buffer TileInfos
|
||||
@ -82,61 +54,38 @@ const uint indices[6] = { 0, 1, 2, 2, 1, 3 };
|
||||
void main()
|
||||
{
|
||||
TileInfo t_info = tile_infos[gl_WorkGroupID.x];
|
||||
uint position_x = bitfieldExtract(t_info.packed_data[0], 0, 9);
|
||||
uint position_y = bitfieldExtract(t_info.packed_data[0], 9, 9);
|
||||
vec2 stack_position = vec2(position_x, position_y) - vec2(256, 256);
|
||||
uint position_x = bitfieldExtract(t_info.position, 0, 10);
|
||||
uint position_y = bitfieldExtract(t_info.position, 10, 10);
|
||||
vec2 stack_position = vec2(position_x, position_y) - vec2(512, 512);
|
||||
|
||||
uint layer_count = bitfieldExtract(t_info.packed_data[0], 18, 5);
|
||||
uint layer_count = bitfieldExtract(t_info.position, 20, 5);
|
||||
|
||||
uint tile_texture_x = bitfieldExtract(t_info.packed_data[1], 24, 4);
|
||||
uint tile_texture_y = bitfieldExtract(t_info.packed_data[1], 24, 4);
|
||||
vec2 tile_texture_offset = vec2(tile_texture_x, tile_texture_y);
|
||||
float minsize = min(screen_size_and_pixel_scale.x, screen_size_and_pixel_scale.y);
|
||||
|
||||
vec2 positions[4] = { vec2(-0.5, -0.5), vec2(0.5, -0.5), vec2(-0.5, 0.5), vec2(0.5, 0.5) };
|
||||
vec2 texcoords[4] = { vec2(0, 0), vec2(1, 0), vec2(0, 1), vec2(1, 1) };
|
||||
for (uint i = 0; i < 4; i++)
|
||||
{
|
||||
positions[i] += stack_position;
|
||||
positions[i] *= screen_size_and_pixel_scale.zz;
|
||||
|
||||
texcoords[i] += tile_texture_offset;
|
||||
texcoords[i] *= tile_size;
|
||||
}
|
||||
|
||||
uint layer_order_offset = bitfieldExtract(t_info.packed_data[0], 23, 1);
|
||||
uint z_offset = bitfieldExtract(t_info.position, 25, 2);
|
||||
|
||||
uint palette_lookup = bitfieldExtract(t_info.packed_data[0], 24, 8);
|
||||
uint palette_lookup = bitfieldExtract(t_info.position, 27, 5);
|
||||
ColorInfo c_info = color_infos[palette_lookup];
|
||||
uint c = c_info.color[gl_LocalInvocationID.x];
|
||||
|
||||
float x_offset_per_layer_mantissa = float(bitfieldExtract(t_info.packed_data[1], 0, 3)) / 7 + 1;
|
||||
float x_offset_per_layer_exponent = float(bitfieldExtract(t_info.packed_data[1], 3, 4)) - 8;
|
||||
if (x_offset_per_layer_exponent == 7) { x_offset_per_layer_mantissa = 0; }
|
||||
float x_offset_per_layer_sign = float(bitfieldExtract(t_info.packed_data[1], 7, 1));
|
||||
float y_offset_per_layer_mantissa = float(bitfieldExtract(t_info.packed_data[1], 8, 3)) / 7 + 1;
|
||||
float y_offset_per_layer_exponent = float(bitfieldExtract(t_info.packed_data[1], 11, 4)) - 8;
|
||||
if (y_offset_per_layer_exponent == 7) { y_offset_per_layer_mantissa = 0; }
|
||||
float y_offset_per_layer_sign = float(bitfieldExtract(t_info.packed_data[1], 15, 1));
|
||||
|
||||
float x_offset_per_layer = (-2 * x_offset_per_layer_sign + 1) * pow(2, x_offset_per_layer_exponent) * x_offset_per_layer_mantissa;
|
||||
float y_offset_per_layer = (-2 * y_offset_per_layer_sign + 1) * pow(2, y_offset_per_layer_exponent) * y_offset_per_layer_mantissa;
|
||||
vec2 offset_per_layer = vec2(x_offset_per_layer, y_offset_per_layer);
|
||||
|
||||
float scale_per_layer = bitfieldExtract(t_info.packed_data[1], 16, 8) / 255.0f;
|
||||
float layer_scale = 1 + scale_per_layer * gl_LocalInvocationID.x;
|
||||
|
||||
for (uint i = 4 * gl_LocalInvocationID.x; i < 4 * gl_LocalInvocationID.x + 4; i++)
|
||||
{
|
||||
vec4 position = vec4(rotation_matrix * positions[i % 4], float(2 * gl_LocalInvocationID.x + layer_order_offset) / 128, 1);
|
||||
vec4 position = vec4(rotation_matrix * positions[i % 4], float(4 * gl_LocalInvocationID.x + z_offset) / 128, 1);
|
||||
position.xy /= screen_size_and_pixel_scale.xy;
|
||||
position.xy *= scale;
|
||||
position.xy += offset_per_layer * vec2(gl_LocalInvocationID.x * scale / screen_size_and_pixel_scale.xy);
|
||||
position.xy *= layer_scale;
|
||||
|
||||
position.y += 20 * gl_LocalInvocationID.x * scale / screen_size_and_pixel_scale.y;
|
||||
gl_MeshVerticesNV[i].gl_Position = position;
|
||||
v_out[i].layer = 2 * gl_LocalInvocationID.x + layer_order_offset;
|
||||
v_out[i].color = unpackUnorm4x8(c);
|
||||
v_out[i].texcoord = texcoords[i % 4];
|
||||
|
||||
v_out[i].layer = 4 * gl_LocalInvocationID.x + z_offset;
|
||||
|
||||
v_out[i].color = c;
|
||||
}
|
||||
|
||||
for (uint i = 6 * gl_LocalInvocationID.x; i < 6 * gl_LocalInvocationID.x + 6; i++)
|
||||
@ -156,23 +105,20 @@ layout (location = 0) out vec4 FragColor;
|
||||
layout (binding = 0, rg32ui) uniform restrict writeonly uimage3D AZBuffer;
|
||||
layout (binding = 1, r32ui) uniform restrict uimage2D AZNextBuffer;
|
||||
|
||||
layout (binding = 0) uniform sampler2D TextureAtlas;
|
||||
|
||||
in PerVertexData
|
||||
{
|
||||
flat uint layer;
|
||||
flat vec4 color;
|
||||
vec2 texcoord;
|
||||
flat uint color;
|
||||
} fragIn;
|
||||
|
||||
void main()
|
||||
{
|
||||
const vec4 texture_color = texture(TextureAtlas, fragIn.texcoord / vec2(textureSize(TextureAtlas, 0)));
|
||||
const uint color = packUnorm4x8(fragIn.color * texture_color);
|
||||
const uint position = imageAtomicAdd(AZNextBuffer, ivec2(gl_FragCoord.xy), 1);
|
||||
|
||||
imageAtomicMax(AZNextBuffer, ivec2(gl_FragCoord.xy), fragIn.layer + 1);
|
||||
|
||||
imageStore(AZBuffer, ivec3(gl_FragCoord.xy, fragIn.layer), uvec4(fragIn.layer, color, 0, 0));
|
||||
if (position < )" STRINGIFY(OIT_LAYERS) R"()
|
||||
{
|
||||
imageStore(AZBuffer, ivec3(gl_FragCoord.xy, position), uvec4(fragIn.layer, fragIn.color, 0, 0));
|
||||
}
|
||||
|
||||
FragColor = vec4(0);
|
||||
}
|
||||
@ -199,13 +145,33 @@ layout (binding = 1, r32ui) uniform restrict readonly uimage2D AZNextBuffer;
|
||||
|
||||
void main()
|
||||
{
|
||||
uvec2 data[ )" STRINGIFY(OIT_LAYERS) R"(];
|
||||
|
||||
const uint layer_count = imageLoad(AZNextBuffer, ivec2(gl_FragCoord.xy)).x;
|
||||
|
||||
for (uint i = 0; i < layer_count; i++)
|
||||
{
|
||||
data[i] = imageLoad(AZBuffer, ivec3(gl_FragCoord.xy, i)).xy;
|
||||
}
|
||||
|
||||
for (int i = 0; i < layer_count; i++)
|
||||
{
|
||||
for (int j = i; j > 0 && data[j - 1].x > data[j].x; j--)
|
||||
{
|
||||
const uvec2 temp = data[j];
|
||||
data[j] = data[j - 1];
|
||||
data[j - 1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 color = vec3(0);
|
||||
for (int i = 0; i < layer_count; i++)
|
||||
{
|
||||
uvec4 data = imageLoad(AZBuffer, ivec3(gl_FragCoord.xy, i));
|
||||
vec4 temp_color = unpackUnorm4x8(data.y);
|
||||
uint a = bitfieldExtract(data[i].y, 0, 8);
|
||||
uint b = bitfieldExtract(data[i].y, 8, 8);
|
||||
uint g = bitfieldExtract(data[i].y, 16, 8);
|
||||
uint r = bitfieldExtract(data[i].y, 24, 8);
|
||||
vec4 temp_color = vec4(r, g, b, a) / vec4(255);
|
||||
|
||||
color = vec3(temp_color.rgb * temp_color.a + color.rgb * (1 - temp_color.a));
|
||||
}
|
||||
@ -216,7 +182,7 @@ void main()
|
||||
|
||||
struct TileInfo
|
||||
{
|
||||
uint32_t packed_data[2];
|
||||
uint32_t position;
|
||||
};
|
||||
|
||||
class application_error : public std::runtime_error
|
||||
@ -291,14 +257,15 @@ public:
|
||||
glProgramUniform3f(gl.az_pass_program, 1, width, height, 8);
|
||||
|
||||
update_buffers();
|
||||
|
||||
glBindTextureUnit(0, gl.atlas);
|
||||
}
|
||||
|
||||
callbacks.update(this, dt, userdata);
|
||||
|
||||
constexpr uint8_t color = 0;
|
||||
glClearTexImage(gl.az_buffer, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, &color);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
constexpr uint32_t color = 0;
|
||||
glClearTexImage(gl.az_buffer, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, &color);
|
||||
|
||||
constexpr uint8_t z = 0;
|
||||
glClearTexImage(gl.az_next_buffer, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, &z);
|
||||
@ -335,68 +302,30 @@ public:
|
||||
gl.tile_count = 0;
|
||||
}
|
||||
|
||||
void put(sprstk_tile_info info)
|
||||
void put(int x, int y, unsigned int layers, unsigned int palette_lookup, unsigned int z_offset = 0)
|
||||
{
|
||||
if (gl.tile_count >= (1 << 20)) { return; }
|
||||
x += 512;
|
||||
x &= 0b1111111111;
|
||||
|
||||
int x = info.position.x;
|
||||
x += 256;
|
||||
x &= 0b111111111;
|
||||
y += 512;
|
||||
y &= 0b1111111111;
|
||||
y <<= 10;
|
||||
|
||||
int y = info.position.y;
|
||||
y += 256;
|
||||
y &= 0b111111111;
|
||||
y <<= 9;
|
||||
|
||||
unsigned int layers = info.layers;
|
||||
layers &= 0b11111;
|
||||
layers <<= 18;
|
||||
layers <<= 20;
|
||||
|
||||
int layer_order_offset = info.layer_order_offset;
|
||||
layer_order_offset &= 0b1;
|
||||
layer_order_offset <<= 23;
|
||||
z_offset &= 0b11;
|
||||
z_offset <<= 25;
|
||||
|
||||
int palette_index = info.palette_index;
|
||||
palette_index &= 0b11111111;
|
||||
palette_index <<= 24;
|
||||
palette_lookup &= 0b11111;
|
||||
palette_lookup <<= 27;
|
||||
|
||||
int layer_dx = 0;
|
||||
float layer_dx_exponent = floorf(logf(fabsf(info.layer_modifiers.dx)) / logf(2));
|
||||
if (fabsf(info.layer_modifiers.dx) < 0.0000001f) { layer_dx_exponent = 7; }
|
||||
float layer_dx_mantissa = info.layer_modifiers.dx / powf(2, layer_dx_exponent);
|
||||
layer_dx |= (int((layer_dx_mantissa - 1) * 7 - 2 * (info.layer_modifiers.dx < 0)) & 0b111);
|
||||
layer_dx |= (int(layer_dx_exponent + 8) & 0b1111) << 3;
|
||||
layer_dx |= (info.layer_modifiers.dx < 0 ? 1 : 0) << 7;
|
||||
|
||||
int layer_dy = 0;
|
||||
float layer_dy_exponent = floorf(logf(fabsf(info.layer_modifiers.dy)) / logf(2));
|
||||
if (fabsf(info.layer_modifiers.dy) < 0.0000001f) { layer_dy_exponent = 7; }
|
||||
float layer_dy_mantissa = info.layer_modifiers.dy / powf(2, layer_dy_exponent);
|
||||
layer_dy |= (int((layer_dy_mantissa - 1) * 7 - 2 * (info.layer_modifiers.dy < 0)) & 0b111) << 8;
|
||||
layer_dy |= (int(layer_dy_exponent + 8) & 0b1111) << 11;
|
||||
layer_dy |= (info.layer_modifiers.dy < 0 ? 1 : 0) << 15;
|
||||
|
||||
int layer_scale = info.layer_modifiers.scale * 255.0f;
|
||||
layer_scale &= 0b11111111;
|
||||
layer_scale <<= 16;
|
||||
|
||||
int atlas_x = info.sprite.x;
|
||||
atlas_x &= 0b1111;
|
||||
atlas_x <<= 24;
|
||||
|
||||
int atlas_y = info.sprite.y;
|
||||
atlas_y &= 0b1111;
|
||||
atlas_y <<= 28;
|
||||
|
||||
gl.tile_buffer_map[gl.tile_count++] = {
|
||||
uint32_t(x | y | layers | layer_order_offset | palette_index),
|
||||
uint32_t(layer_dx | layer_dy | layer_scale | atlas_x | atlas_y)
|
||||
};
|
||||
gl.tile_buffer_map[gl.tile_count++] = { x | y | layers | z_offset | palette_lookup };
|
||||
}
|
||||
|
||||
void set_palette(unsigned int index, const sprstk_palette* palette)
|
||||
{
|
||||
if (index >= (1 << 8)) { return; }
|
||||
if (index > (1 << 5)) { return; }
|
||||
|
||||
gl.color_info_map[index] = *palette;
|
||||
}
|
||||
@ -415,17 +344,6 @@ public:
|
||||
glProgramUniformMatrix2fv(gl.az_pass_program, 3, 1, false, arr);
|
||||
}
|
||||
|
||||
void load_sprites(const char* filename, unsigned int tile_size)
|
||||
{
|
||||
int w, h, n;
|
||||
unsigned char* img = stbi_load(filename, &w, &h, &n, 4);
|
||||
glBindTexture(GL_TEXTURE_2D, gl.atlas);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
stbi_image_free(img);
|
||||
|
||||
glProgramUniform1f(gl.az_pass_program, 4, tile_size);
|
||||
}
|
||||
|
||||
private:
|
||||
sprstk_callbacks callbacks;
|
||||
void* userdata;
|
||||
@ -452,7 +370,6 @@ private:
|
||||
sprstk_palette* color_info_map;
|
||||
unsigned int az_buffer;
|
||||
unsigned int az_next_buffer;
|
||||
unsigned int atlas;
|
||||
} gl;
|
||||
|
||||
void init_sdl()
|
||||
@ -469,7 +386,7 @@ private:
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
|
||||
|
||||
sdl.window = SDL_CreateWindow("sprstk", 1280, 960, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||
sdl.window = SDL_CreateWindow("sprstk", 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||
if (!sdl.window)
|
||||
{
|
||||
throw application_error("Failed to create window");
|
||||
@ -590,31 +507,22 @@ private:
|
||||
|
||||
glGenBuffers(1, &gl.tile_buffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, gl.tile_buffer);
|
||||
glNamedBufferStorage(gl.tile_buffer, sizeof(TileInfo) * (1 << 20), nullptr, GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
glNamedBufferStorage(gl.tile_buffer, sizeof(TileInfo) * (1 << 26), nullptr, GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
|
||||
gl.tile_count = 0;
|
||||
gl.tile_buffer_map = (TileInfo*)glMapNamedBufferRange(gl.tile_buffer, 0, sizeof(TileInfo) * (1 << 20), GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT);
|
||||
gl.tile_buffer_map = (TileInfo*)glMapNamedBufferRange(gl.tile_buffer, 0, sizeof(TileInfo) * (1 << 26), GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT);
|
||||
|
||||
glGenBuffers(1, &gl.color_buffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, gl.color_buffer);
|
||||
glNamedBufferStorage(gl.color_buffer, sizeof(sprstk_palette) * (1 << 8), nullptr, GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
glNamedBufferStorage(gl.color_buffer, sizeof(sprstk_palette) * (1 << 5), nullptr, GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
|
||||
gl.color_info_map = (sprstk_palette*)glMapNamedBufferRange(gl.color_buffer, 0, sizeof(sprstk_palette) * (1 << 8), GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT);
|
||||
gl.color_info_map = (sprstk_palette*)glMapNamedBufferRange(gl.color_buffer, 0, sizeof(sprstk_palette) * (1 << 5), GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT);
|
||||
|
||||
const float arr[4] = {1, 0, 0, 1};
|
||||
glProgramUniformMatrix2fv(gl.az_pass_program, 3, 1, false, arr);
|
||||
glProgramUniform1f(gl.az_pass_program, 2, 1);
|
||||
|
||||
update_buffers();
|
||||
|
||||
glGenTextures(1, &gl.atlas);
|
||||
glBindTexture(GL_TEXTURE_2D, gl.atlas);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
const uint8_t white_pixels[4] = { 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, white_pixels);
|
||||
|
||||
glBindTextureUnit(0, gl.atlas);
|
||||
}
|
||||
|
||||
void destroy_gl()
|
||||
@ -705,9 +613,14 @@ void sprstk_clear(sprstk* instance)
|
||||
instance->clear();
|
||||
}
|
||||
|
||||
void sprstk_put(sprstk* instance, sprstk_tile_info info)
|
||||
void sprstk_put(sprstk* instance, int x, int y, unsigned int layers, unsigned int palette_lookup)
|
||||
{
|
||||
instance->put(info);
|
||||
instance->put(x, y, layers, palette_lookup);
|
||||
}
|
||||
|
||||
void sprstk_putz(sprstk* instance, int x, int y, unsigned int layers, unsigned int palette_lookup, unsigned int z_offset)
|
||||
{
|
||||
instance->put(x, y, layers, palette_lookup, z_offset);
|
||||
}
|
||||
|
||||
void sprstk_set_palette(sprstk* instance, unsigned int index, const sprstk_palette* palette)
|
||||
@ -725,9 +638,4 @@ void sprstk_set_angle(sprstk* instance, float angle)
|
||||
instance->set_angle(angle);
|
||||
}
|
||||
|
||||
void sprstk_load_sprites(sprstk *instance, const char *filename, unsigned int tile_size)
|
||||
{
|
||||
instance->load_sprites(filename, tile_size);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
#define STBI_ONLY_PNG
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
7988
src/stb_image.h
7988
src/stb_image.h
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user