forked from NotAShelf/rogged
various: add admin build; various layout improvements
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ieaa99fa0a32b42b1e97aada611d809b96a6a6964
This commit is contained in:
parent
d8b49054d5
commit
514a9560a2
9 changed files with 856 additions and 201 deletions
178
src/render.c
178
src/render.c
|
|
@ -103,6 +103,57 @@ static Color color_lerp(Color a, Color b, float t) {
|
|||
(unsigned char)(a.b + (int)((b.b - a.b) * t)), (unsigned char)(a.a + (int)((b.a - a.a) * t))};
|
||||
}
|
||||
|
||||
static float light_factor_from_brightness(int brightness) {
|
||||
float base_light = brightness > 0 ? AMBIENT_LIGHT_FACTOR : REMEMBERED_LIGHT_FACTOR;
|
||||
return base_light + (1.0f - base_light) * powf((float)brightness / 255.0f, LIGHT_EXPONENT);
|
||||
}
|
||||
|
||||
static int sample_light(const Map *map, int tx, int ty, int sx, int sy) {
|
||||
int base_x = tx * SUB_TILE_RES + sx;
|
||||
int base_y = ty * SUB_TILE_RES + sy;
|
||||
int sum = 0;
|
||||
int count = 0;
|
||||
for (int dy = -1; dy <= 1; dy++) {
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
int x = base_x + dx;
|
||||
int y = base_y + dy;
|
||||
if (x < 0 || y < 0 || x >= MAP_WIDTH * SUB_TILE_RES || y >= MAP_HEIGHT * SUB_TILE_RES)
|
||||
continue;
|
||||
sum += map->light_map[y][x];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count > 0 ? sum / count : 0;
|
||||
}
|
||||
|
||||
static Color tint_for_light(const Map *map, int tx, int ty, int sx, int sy, int is_opaque, float dim) {
|
||||
float factor = light_factor_from_brightness(sample_light(map, tx, ty, sx, sy)) * dim;
|
||||
if (is_opaque)
|
||||
factor = AMBIENT_LIGHT_FACTOR + 0.92f * factor;
|
||||
int value = (int)(255.0f * factor);
|
||||
if (value > 255)
|
||||
value = 255;
|
||||
return (Color){(unsigned char)value, (unsigned char)value, (unsigned char)value, 255};
|
||||
}
|
||||
|
||||
static void draw_lit_texture_tile(const Map *map, const Tileset *tileset, Rectangle src, Rectangle dst, int tx, int ty,
|
||||
int is_opaque, float dim) {
|
||||
const int parts = 4;
|
||||
float src_w = src.width / (float)parts;
|
||||
float src_h = src.height / (float)parts;
|
||||
float dst_w = dst.width / (float)parts;
|
||||
float dst_h = dst.height / (float)parts;
|
||||
for (int py = 0; py < parts; py++) {
|
||||
for (int px = 0; px < parts; px++) {
|
||||
int sx = (px * SUB_TILE_RES) / parts + SUB_TILE_RES / (parts * 2);
|
||||
int sy = (py * SUB_TILE_RES) / parts + SUB_TILE_RES / (parts * 2);
|
||||
Rectangle s = {src.x + src_w * px, src.y + src_h * py, src_w, src_h};
|
||||
Rectangle d = {dst.x + dst_w * px, dst.y + dst_h * py, dst_w + 0.5f, dst_h + 0.5f};
|
||||
DrawTexturePro(tileset->atlas, s, d, (Vector2){0, 0}, 0.0f, tint_for_light(map, tx, ty, sx, sy, is_opaque, dim));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void render_map(const Map *map, const Tileset *tileset) {
|
||||
for (int y = 0; y < MAP_HEIGHT; y++) {
|
||||
for (int x = 0; x < MAP_WIDTH; x++) {
|
||||
|
|
@ -115,8 +166,7 @@ void render_map(const Map *map, const Tileset *tileset) {
|
|||
continue;
|
||||
}
|
||||
|
||||
float base_light = brightness > 0 ? AMBIENT_LIGHT_FACTOR : REMEMBERED_LIGHT_FACTOR;
|
||||
float light_factor = base_light + (1.0f - base_light) * powf((float)brightness / 255.0f, LIGHT_EXPONENT);
|
||||
float light_factor = light_factor_from_brightness(brightness);
|
||||
if (is_deep_corridor(map, x, y))
|
||||
light_factor *= 0.82f;
|
||||
|
||||
|
|
@ -140,10 +190,18 @@ void render_map(const Map *map, const Tileset *tileset) {
|
|||
case TILE_DOOR_RUINED:
|
||||
tile_id = TILE_DOOR_OPEN_SPRITE;
|
||||
break;
|
||||
case TILE_RUBBLE:
|
||||
case TILE_SHALLOW_WATER:
|
||||
tile_id = TILE_FLOOR_0 + ((x * 7 + y * 13) % 4);
|
||||
break;
|
||||
case TILE_STATUE:
|
||||
tile_id = TILE_WALL_0 + ((x * 7 + y * 13) % 2);
|
||||
break;
|
||||
}
|
||||
|
||||
int is_door = (map->tiles[y][x] == TILE_DOOR_CLOSED || map->tiles[y][x] == TILE_DOOR_OPEN);
|
||||
int tile_drawn = 0;
|
||||
int decor_base_drawn = 0;
|
||||
|
||||
// Draw floor underneath doors using tileset if available, so the
|
||||
// floor matches adjacent tiles
|
||||
|
|
@ -151,29 +209,31 @@ void render_map(const Map *map, const Tileset *tileset) {
|
|||
int floor_id = TILE_FLOOR_0 + ((x * 7 + y * 13) % 4);
|
||||
Rectangle floor_src = tileset_get_region(tileset, floor_id);
|
||||
if (floor_src.width > 0) {
|
||||
int fv = (int)(255.0f * light_factor);
|
||||
if (fv > 255)
|
||||
fv = 255;
|
||||
Color ftint = (Color){(unsigned char)fv, (unsigned char)fv, (unsigned char)fv, 255};
|
||||
DrawTexturePro(tileset->atlas, floor_src, dst, (Vector2){0, 0}, 0.0f, ftint);
|
||||
draw_lit_texture_tile(map, tileset, floor_src, dst, x, y, 0, 1.0f);
|
||||
tile_drawn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (tile_id >= 0 && tileset != NULL && tileset->finalized && !is_door) {
|
||||
int is_decor =
|
||||
map->tiles[y][x] == TILE_RUBBLE || map->tiles[y][x] == TILE_SHALLOW_WATER || map->tiles[y][x] == TILE_STATUE;
|
||||
if (tile_id >= 0 && tileset != NULL && tileset->finalized && !is_door && !is_decor) {
|
||||
Rectangle src = tileset_get_region(tileset, tile_id);
|
||||
if (src.width > 0) {
|
||||
int is_opaque = (map->tiles[y][x] == TILE_WALL);
|
||||
float wall_dim = is_opaque ? (AMBIENT_LIGHT_FACTOR + 0.92f * light_factor) : light_factor;
|
||||
int tv = (int)(255.0f * wall_dim);
|
||||
if (tv > 255)
|
||||
tv = 255;
|
||||
Color tint = (Color){(unsigned char)tv, (unsigned char)tv, (unsigned char)tv, 255};
|
||||
DrawTexturePro(tileset->atlas, src, dst, (Vector2){0, 0}, 0.0f, tint);
|
||||
int is_opaque = (map->tiles[y][x] == TILE_WALL || map->tiles[y][x] == TILE_STATUE);
|
||||
draw_lit_texture_tile(map, tileset, src, dst, x, y, is_opaque, is_deep_corridor(map, x, y) ? 0.82f : 1.0f);
|
||||
tile_drawn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_decor && tileset != NULL && tileset->finalized) {
|
||||
int base_id = TILE_FLOOR_0 + ((x * 7 + y * 13) % 4);
|
||||
Rectangle src = tileset_get_region(tileset, base_id);
|
||||
if (src.width > 0) {
|
||||
draw_lit_texture_tile(map, tileset, src, dst, x, y, 0, 1.0f);
|
||||
decor_base_drawn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tile_drawn || is_door) {
|
||||
Color wall_color = color_lerp((Color){42, 42, 52, 255}, DARKGRAY, light_factor);
|
||||
Color floor_color = color_lerp((Color){32, 32, 42, 255}, BLACK, light_factor);
|
||||
|
|
@ -187,23 +247,6 @@ void render_map(const Map *map, const Tileset *tileset) {
|
|||
break;
|
||||
case TILE_FLOOR:
|
||||
DrawRectangleRec(dst, floor_color);
|
||||
// Torch flicker: warm tint on floor tiles adjacent to stairs
|
||||
{
|
||||
int is_adjacent_to_stairs = 0;
|
||||
for (int dy = -1; dy <= 1 && !is_adjacent_to_stairs; dy++) {
|
||||
for (int dx = -1; dx <= 1 && !is_adjacent_to_stairs; dx++) {
|
||||
int nx = x + dx;
|
||||
int ny = y + dy;
|
||||
if (in_bounds(nx, ny, MAP_WIDTH, MAP_HEIGHT) && map->tiles[ny][nx] == TILE_STAIRS) {
|
||||
is_adjacent_to_stairs = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_adjacent_to_stairs && light_factor > 0.05f) {
|
||||
int flicker = (int)(sinf(GetTime() * 5.0f) * 15.0f);
|
||||
DrawRectangleRec(dst, (Color){40 + flicker, 25, 10, 60});
|
||||
}
|
||||
}
|
||||
// Grid lines
|
||||
if (DRAW_GRID_LINES && light_factor > 0.05f) {
|
||||
DrawRectangleLines((int)dst.x, (int)dst.y, (int)dst.width, (int)dst.height, (Color){20, 20, 20, 80});
|
||||
|
|
@ -304,6 +347,72 @@ void render_map(const Map *map, const Tileset *tileset) {
|
|||
(Color){120, 90, 60, 255});
|
||||
}
|
||||
break;
|
||||
case TILE_RUBBLE:
|
||||
if (!decor_base_drawn)
|
||||
DrawRectangleRec(dst, floor_color);
|
||||
if (light_factor > 0.05f) {
|
||||
Color stone = color_lerp((Color){54, 50, 46, 255}, (Color){126, 118, 102, 255}, light_factor);
|
||||
Color light = color_lerp((Color){72, 68, 60, 255}, (Color){166, 156, 132, 255}, light_factor);
|
||||
Color dark = color_lerp((Color){22, 20, 19, 255}, (Color){67, 60, 52, 255}, light_factor);
|
||||
int ox = x * TILE_SIZE;
|
||||
int oy = y * TILE_SIZE;
|
||||
DrawRectangle(ox + 3, oy + 12, 10, 2, (Color){0, 0, 0, 55});
|
||||
DrawRectangle(ox + 5, oy + 7, 5, 5, dark);
|
||||
DrawRectangle(ox + 6, oy + 6, 5, 5, stone);
|
||||
DrawLine(ox + 6, oy + 6, ox + 10, oy + 6, light);
|
||||
DrawRectangle(ox + 2, oy + 10, 5, 3, dark);
|
||||
DrawRectangle(ox + 3, oy + 9, 5, 3, stone);
|
||||
DrawPixel(ox + 4, oy + 9, light);
|
||||
DrawRectangle(ox + 10, oy + 10, 4, 3, dark);
|
||||
DrawRectangle(ox + 10, oy + 9, 4, 3, stone);
|
||||
DrawPixel(ox + 12, oy + 9, light);
|
||||
DrawPixel(ox + 5, oy + 13, stone);
|
||||
DrawPixel(ox + 12, oy + 13, stone);
|
||||
}
|
||||
break;
|
||||
case TILE_SHALLOW_WATER:
|
||||
if (!decor_base_drawn)
|
||||
DrawRectangleRec(dst, floor_color);
|
||||
if (light_factor > 0.05f) {
|
||||
Color water = color_lerp((Color){12, 30, 39, 165}, (Color){36, 94, 116, 175}, light_factor);
|
||||
Color edge = color_lerp((Color){7, 18, 24, 170}, (Color){23, 62, 76, 180}, light_factor);
|
||||
Color glint = color_lerp((Color){48, 91, 105, 130}, (Color){128, 184, 196, 155}, light_factor);
|
||||
int shimmer = (int)(sinf(GetTime() * 2.0f + (float)(x + y)) * 10.0f);
|
||||
int ox = x * TILE_SIZE;
|
||||
int oy = y * TILE_SIZE;
|
||||
DrawRectangle(ox + 3, oy + 5, 10, 7, water);
|
||||
DrawRectangle(ox + 4, oy + 4, 8, 1, water);
|
||||
DrawRectangle(ox + 4, oy + 12, 8, 1, edge);
|
||||
DrawPixel(ox + 2, oy + 7, edge);
|
||||
DrawPixel(ox + 13, oy + 9, edge);
|
||||
glint.a = (unsigned char)(glint.a + shimmer);
|
||||
DrawLine(ox + 5, oy + 7, ox + 10, oy + 7, glint);
|
||||
DrawLine(ox + 7, oy + 10, ox + 12, oy + 10, glint);
|
||||
}
|
||||
break;
|
||||
case TILE_STATUE:
|
||||
if (!decor_base_drawn)
|
||||
DrawRectangleRec(dst, floor_color);
|
||||
if (light_factor > 0.05f) {
|
||||
Color stone = color_lerp((Color){52, 52, 56, 255}, (Color){142, 138, 128, 255}, light_factor);
|
||||
Color shade = color_lerp((Color){22, 22, 26, 255}, (Color){68, 66, 64, 255}, light_factor);
|
||||
Color light = color_lerp((Color){78, 78, 82, 255}, (Color){176, 170, 150, 255}, light_factor);
|
||||
int ox = x * TILE_SIZE;
|
||||
int oy = y * TILE_SIZE;
|
||||
DrawRectangle(ox + 3, oy + 12, 10, 2, (Color){0, 0, 0, 70});
|
||||
DrawRectangle(ox + 4, oy + 11, 8, 3, shade);
|
||||
DrawRectangle(ox + 5, oy + 10, 6, 2, stone);
|
||||
DrawRectangle(ox + 5, oy + 5, 6, 6, shade);
|
||||
DrawRectangle(ox + 6, oy + 4, 5, 6, stone);
|
||||
DrawRectangle(ox + 5, oy + 7, 1, 3, shade);
|
||||
DrawRectangle(ox + 11, oy + 7, 1, 3, shade);
|
||||
DrawRectangle(ox + 6, oy + 2, 4, 3, stone);
|
||||
DrawRectangle(ox + 7, oy + 1, 2, 1, light);
|
||||
DrawPixel(ox + 7, oy + 6, light);
|
||||
DrawPixel(ox + 9, oy + 6, shade);
|
||||
DrawLine(ox + 6, oy + 10, ox + 10, oy + 10, light);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -320,12 +429,9 @@ void render_player(const Player *p, const Tileset *tileset, int frame_counter) {
|
|||
Rectangle dst = {(float)(p->position.x * TILE_SIZE), (float)(p->position.y * TILE_SIZE), (float)TILE_SIZE,
|
||||
(float)TILE_SIZE};
|
||||
|
||||
// Soft radial glow under the player
|
||||
int cx = p->position.x * TILE_SIZE + TILE_SIZE / 2;
|
||||
int cy = p->position.y * TILE_SIZE + TILE_SIZE / 2;
|
||||
DrawCircle(cx, cy, 14.0f, (Color){255, 220, 100, 20});
|
||||
DrawCircle(cx, cy, 10.0f, (Color){255, 230, 150, 35});
|
||||
DrawCircle(cx, cy, 6.0f, (Color){255, 240, 180, 55});
|
||||
DrawEllipse(cx, cy + 5, 6.0f, 3.0f, (Color){0, 0, 0, 60});
|
||||
|
||||
if (tileset != NULL && tileset->finalized) {
|
||||
int tile_id = p->sprite_tile_id;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue