+4
compile_flags.txt
+4
compile_flags.txt
+1
include/keraforge.h
+1
include/keraforge.h
+41
include/keraforge/_header.h
+41
include/keraforge/_header.h
···
7
7
#include <stdbool.h>
8
8
9
9
10
+
#ifndef __FUNCTION_NAME__
11
+
# ifdef WIN32
12
+
# define __FUNCTION_NAME__ __FUNCTION__
13
+
# else
14
+
# define __FUNCTION_NAME__ __func__
15
+
# endif
16
+
#endif
17
+
18
+
19
+
#ifdef KF_SANITY_CHECKS
20
+
# include <stdio.h> /* fprintf, stderr */
21
+
# include <stdlib.h> /* exit */
22
+
# define KF_SANITY_CHECK(EXPR, ...) \
23
+
do \
24
+
{ \
25
+
if (!(EXPR)) \
26
+
{ \
27
+
fprintf(stderr, "\x1b[1;31msanity check failed: \x1b[0;34m%s:%d\x1b[0m in \x1b[34m%s: \x1b[0m", __FILE__, __LINE__, __FUNCTION_NAME__); \
28
+
fprintf(stderr, __VA_ARGS__); \
29
+
fprintf(stderr, "\n"); \
30
+
kf_printbacktrace(stderr); \
31
+
exit(1); \
32
+
} \
33
+
} \
34
+
while (0)
35
+
# define KF_UNREACHABLE(...) \
36
+
do \
37
+
{ \
38
+
fprintf(stderr, "\x1b[1;31munreachable: \x1b[0;34m%s:%d\x1b[0m in \x1b[34m%s: \x1b[0m", __FILE__, __LINE__, __FUNCTION_NAME__); \
39
+
fprintf(stderr, __VA_ARGS__); \
40
+
fprintf(stderr, "\n"); \
41
+
kf_printbacktrace(stderr); \
42
+
exit(1); \
43
+
} \
44
+
while (0)
45
+
#else
46
+
# define KF_SANITY_CHECK(EXPR, ...) do { ; } while (0)
47
+
# define KF_UNREACHABLE(...) do { ; } while (0)
48
+
#endif
49
+
50
+
10
51
typedef int8_t i8;
11
52
typedef int16_t i16;
12
53
typedef int32_t i32;
+11
include/keraforge/error.h
+11
include/keraforge/error.h
+2
include/keraforge/sprites.h
+2
include/keraforge/sprites.h
···
18
18
19
19
/* Load a sprite sheet with the given sprite width/height. */
20
20
struct kf_spritesheet kf_loadspritesheet(char *filename, int spritewidth, int spriteheight);
21
+
/* Draw a single sprite from the sheet with a provided width and height. */
22
+
void kf_drawsprite_wh(struct kf_spritesheet *sheet, f32 x, f32 y, f32 w, f32 h, int spritex, int spritey);
21
23
/* Draw a single sprite from the sheet at the given coordinates. */
22
24
void kf_drawsprite(struct kf_spritesheet *sheet, f32 x, f32 y, int spritex, int spritey);
23
25
+39
-3
include/keraforge/world.h
+39
-3
include/keraforge/world.h
···
4
4
5
5
#include <keraforge/_header.h>
6
6
#include <keraforge/math.h>
7
+
#include <keraforge/sprites.h>
7
8
#include <raylib.h>
8
9
10
+
11
+
#define KF_TILE_SIZE_PX 16
9
12
10
13
#define KF_TILEID_MAX UINT16_MAX
11
14
typedef u16 kf_tileid_t;
12
-
#define KF_TILE_SIZE_PX 16
15
+
/* Used to store connectivity variant. */
16
+
typedef u16 kf_tiledatum_t;
13
17
14
18
15
19
struct kf_actor; /* Forward declaration */
16
20
17
21
22
+
#define KF_TILEMASK_NORTH (0x0001)
23
+
#define KF_TILEMASK_WEST (0x0010)
24
+
#define KF_TILEMASK_EAST (0x0100)
25
+
#define KF_TILEMASK_SOUTH (0x1000)
26
+
27
+
28
+
/* Represents a singular tile in the world. */
29
+
struct kf_tile
30
+
{
31
+
kf_tileid_t id;
32
+
kf_tiledatum_t data;
33
+
};
34
+
18
35
/* Represents a world (or a subworld, often called "rooms"). */
19
36
struct kf_world
20
37
{
···
30
47
/* Height of the map. */
31
48
u32 height;
32
49
/* Array of tiles in the map. Use kf_gettile to get a tile using an X/Y position. */
33
-
kf_tileid_t map[];
50
+
struct kf_tile map[];
34
51
};
35
52
36
53
/* Struct-of-arrays for tiles. See: kf_tiles */
···
51
68
/* Struct-of-arrays for tiles. */
52
69
extern struct _kf_tiles kf_tiles;
53
70
71
+
/* Options for creating tiles using addtile and addtiles. */
72
+
struct kf_tile_opts
73
+
{
74
+
char *key;
75
+
Color mapcol;
76
+
struct kf_spritesheet *sheet;
77
+
struct kf_vec2(u32) sprite;
78
+
bool collide;
79
+
};
80
+
81
+
kf_tileid_t kf_addtile(struct kf_tile_opts opts);
82
+
#define KF_ADDTILE(...) (kf_addtile((struct kf_tile_opts){ __VA_ARGS__ }))
83
+
54
84
/* Create a world using the given width and height.
55
85
Fills the map with the given `fill` tile. */
56
86
struct kf_world *kf_world_new(u32 width, u32 height, kf_tileid_t fill);
···
58
88
/* Get the size of the world in bytes. */
59
89
size_t kf_world_getsize(struct kf_world *world);
60
90
91
+
/* Get the sprite offset for a given tile datum. */
92
+
struct kf_vec2(u32) kf_getspritefortilebitmask(kf_tiledatum_t t);
93
+
94
+
/* Update a tile and optionally its neighbours. */
95
+
void kf_world_updatetile(struct kf_world *world, u32 x, u32 y, bool update_neighbours);
96
+
61
97
/* Get a pointer to the tile ID at a given position. */
62
-
kf_tileid_t *kf_world_gettile(struct kf_world *world, u32 x, u32 y);
98
+
struct kf_tile *kf_world_gettile(struct kf_world *world, u32 x, u32 y);
63
99
64
100
/* Draw visible collision rectangles. */
65
101
void kf_world_drawcolliders(struct kf_world *world, struct kf_actor *player, Camera2D camera);
+5
-2
scripts/_config.sh
+5
-2
scripts/_config.sh
···
7
7
export CC="ccache $CC"
8
8
fi
9
9
10
-
export CFLAGS="-Wall -Wextra -Werror -std=c99 -Iinclude/ -c"
11
-
export LFLAGS="-lraylib -lm -lGL -lpthread -ldl -lrt -lX11"
10
+
export KF_DEBUG_CFLAGS="-g -DKF_SANITY_CHECKS"
11
+
export KF_DEBUG_LFLAGS="-g -rdynamic"
12
+
13
+
export CFLAGS="-Wall -Wextra -Werror -std=c99 -Iinclude/ -c -DKF_GNU $KF_DEBUG_CFLAGS"
14
+
export LFLAGS="-lraylib -lm -lGL -lpthread -ldl -lrt -lX11 $KF_DEBUG_LFLAGS"
+1
-1
scripts/run.sh
+1
-1
scripts/run.sh
+2
-2
src/actor.c
+2
-2
src/actor.c
···
56
56
KF_TILE_SIZE_PX - 1,
57
57
}; /* tile rect */
58
58
u32 x;
59
-
kf_tileid_t *tile = kf_world_gettile(world, sx, sy);
59
+
struct kf_tile *tile = kf_world_gettile(world, sx, sy);
60
60
61
61
for (u32 y = sy ; y <= ey ; y++)
62
62
{
63
63
for (x = sx ; x <= ex ; x++)
64
64
{
65
-
if (kf_tiles.collide[*tile] && CheckCollisionRecs(r, tr))
65
+
if (kf_tiles.collide[tile->id] && CheckCollisionRecs(r, tr))
66
66
return 0;
67
67
tile++; /* shift tile pointer to the right */
68
68
tr.x += KF_TILE_SIZE_PX;
+31
src/error.c
+31
src/error.c
···
1
+
#include <keraforge.h>
2
+
3
+
#if KF_GNU
4
+
#include <execinfo.h>
5
+
#endif
6
+
7
+
8
+
void kf_printbacktrace(FILE *file)
9
+
{
10
+
#if KF_GNU
11
+
static const int maxtracelen = 128;
12
+
void *trace[maxtracelen];
13
+
14
+
int size = backtrace(trace, maxtracelen);
15
+
char **strings = backtrace_symbols(trace, size);
16
+
if (strings)
17
+
{
18
+
fprintf(file, "backtrace: (%d frames)\n", size);
19
+
for (int i = 0 ; i < size ; i++)
20
+
fprintf(file, " %d: %s\n", size-i, strings[i]);
21
+
}
22
+
else
23
+
{
24
+
fprintf(file, "failed to obtain backtrace\n");
25
+
}
26
+
27
+
free(strings);
28
+
#else
29
+
fprintf(file, "kf_printbacktrace requires GNU extensions (execinfo.h)\n");
30
+
#endif
31
+
}
+36
-19
src/main.c
+36
-19
src/main.c
···
1
-
#include "keraforge/input.h"
2
1
#include <keraforge.h>
3
2
#include <raylib.h>
4
3
#include <raymath.h>
···
74
73
/* gamepad axis movement */
75
74
f32 gpx = kf_getgamepadaxis(inputbind_move_left);
76
75
f32 gpy = kf_getgamepadaxis(inputbind_move_up);
77
-
// f32 gpx = GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X);
78
-
// f32 gpy = GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y);
79
76
if (gpx > kf_deadzone || gpx < -kf_deadzone || gpy > kf_deadzone || gpy < -kf_deadzone)
80
77
{
81
78
v.y = gpy;
···
141
138
(void)argc;
142
139
(void)argv;
143
140
144
-
SetTraceLogLevel(LOG_WARNING);
141
+
// SetTraceLogLevel(LOG_WARNING);
145
142
InitWindow(800, 600, "Keraforge");
146
143
SetTargetFPS(60);
147
144
SetExitKey(KEY_NULL);
148
145
149
146
loadbinds();
150
147
151
-
kf_tiles.key[0] = "grass";
152
-
kf_tiles.mapcol[0] = GREEN;
153
-
kf_tiles.key[1] = "dirt";
154
-
kf_tiles.mapcol[1] = BROWN;
155
-
kf_tiles.key[2] = "stone";
156
-
kf_tiles.mapcol[2] = GRAY;
157
-
kf_tiles.collide[2] = true;
158
-
kf_tiles.count = 3;
148
+
struct kf_spritesheet terrain = kf_loadspritesheet("data/res/img/tile/terrain.png", 16, 16);
149
+
KF_ADDTILE(
150
+
.key = "grass",
151
+
.mapcol = GREEN,
152
+
.sheet = &terrain,
153
+
.sprite = {0, 0},
154
+
);
155
+
KF_ADDTILE(
156
+
.key = "sand",
157
+
.mapcol = YELLOW,
158
+
.sheet = &terrain,
159
+
.sprite = {4, 0},
160
+
);
161
+
KF_ADDTILE(
162
+
.key = "stone",
163
+
.mapcol = GRAY,
164
+
.sheet = &terrain,
165
+
.sprite = {0, 4},
166
+
.collide = true,
167
+
);
168
+
KF_ADDTILE(
169
+
.key = "debug",
170
+
.mapcol = BLUE,
171
+
.sheet = &terrain,
172
+
.sprite = {4, 4},
173
+
);
174
+
printf("loaded %d tiles\n", kf_tiles.count);
159
175
160
176
struct kf_uiconfig *uiconfig = kf_ui_getconfig();
161
177
uiconfig->select = inputbind_select;
···
170
186
if (!kf_exists("data/map.bin"))
171
187
{
172
188
printf("-> creating world\n");
173
-
world = kf_world_new(128, 128, 0);
174
-
for (size_t i = 0 ; i < world->width*world->height ; i += (size_t)((float)(rand())/RAND_MAX*10))
175
-
world->map[i] = (rand()/(float)RAND_MAX*3);
189
+
world = kf_world_new(128, 128, 1);
176
190
printf("-> saving world\n");
177
191
size_t len = kf_world_getsize(world);
178
192
printf("-> writing of %lu bytes\n", len);
···
236
250
cam.zoom -= 0.25f;
237
251
238
252
BeginDrawing();
239
-
ClearBackground(WHITE);
253
+
ClearBackground(BLACK);
240
254
241
255
BeginMode2D(cam);
242
256
kf_world_draw(world, cam);
243
257
// kf_world_drawcolliders(world, player, cam);
244
258
if (select.x < world->width && select.y < world->height)
245
259
{
260
+
struct kf_tile *t = kf_world_gettile(world, select.x, select.y);
246
261
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
247
262
{
248
-
kf_tileid_t *t = kf_world_gettile(world, select.x, select.y);
249
-
*t = (kf_tileid_t)selected_tile;
263
+
t->id = (kf_tileid_t)selected_tile;
264
+
kf_world_updatetile(world, select.x, select.y, true);
250
265
}
251
266
DrawRectangleLines(select.x * KF_TILE_SIZE_PX, select.y * KF_TILE_SIZE_PX, KF_TILE_SIZE_PX, KF_TILE_SIZE_PX, WHITE);
267
+
struct kf_vec2(u32) s = kf_getspritefortilebitmask(t->data);
268
+
DrawText(TextFormat("%d [0x%04x] (%d,%d) {%d,%d}", t->id, t->data, select.x, select.y, s.x, s.y), select.x * KF_TILE_SIZE_PX, select.y * KF_TILE_SIZE_PX - 10, 10, BLACK);
252
269
}
253
270
player->draw(world, player);
254
271
EndMode2D();
···
264
281
case menu_none:
265
282
break;
266
283
case menu_palette:
267
-
if (kf_ui_choice("Select tile", &kf_tiles.key[0], kf_tiles.count, &selected_tile))
284
+
if (kf_ui_choice("Select tile", &kf_tiles.key[0], kf_tiles.count + 1, &selected_tile))
268
285
setmenu(menu_none);
269
286
break;
270
287
case menu_escape:
+11
-7
src/sprites.c
+11
-7
src/sprites.c
···
14
14
}
15
15
16
16
inline
17
-
void kf_drawsprite(struct kf_spritesheet *sheet, f32 x, f32 y, int spritex, int spritey)
17
+
void kf_drawsprite_wh(struct kf_spritesheet *sheet, f32 x, f32 y, f32 w, f32 h, int spritex, int spritey)
18
18
{
19
+
KF_SANITY_CHECK(sheet != NULL, "spritesheet is null");
20
+
19
21
DrawTexturePro(
20
22
sheet->texture,
21
23
(Rectangle){
···
23
25
spritey * sheet->spriteheight,
24
26
sheet->spritewidth,
25
27
sheet->spriteheight },
26
-
(Rectangle){
27
-
x,
28
-
y,
29
-
sheet->spritewidth,
30
-
sheet->spriteheight },
31
-
(Vector2){0, 0},
28
+
(Rectangle){ x, y, w, h },
29
+
(Vector2){ 0, 0 },
32
30
0,
33
31
WHITE
34
32
);
35
33
}
34
+
35
+
inline
36
+
void kf_drawsprite(struct kf_spritesheet *sheet, f32 x, f32 y, int spritex, int spritey)
37
+
{
38
+
kf_drawsprite_wh(sheet, x, y, sheet->spritewidth, sheet->spriteheight, spritex, spritey);
39
+
}
+111
-15
src/world.c
+111
-15
src/world.c
···
1
+
#include "keraforge/world.h"
1
2
#include <keraforge.h>
2
3
#include <raylib.h>
4
+
#include <stdio.h>
3
5
#include <stdlib.h>
4
6
#include <string.h>
5
7
#include <math.h>
···
8
10
struct _kf_tiles kf_tiles = {0};
9
11
10
12
13
+
static inline
14
+
void _kf_updatetilebitmask(struct kf_world *world, u32 x, u32 y);
15
+
16
+
17
+
kf_tileid_t kf_addtile(struct kf_tile_opts opts)
18
+
{
19
+
KF_SANITY_CHECK(opts.key != NULL, "tile added without key");
20
+
KF_SANITY_CHECK(opts.sheet != NULL, "tile added without sheet");
21
+
22
+
kf_tileid_t id = ++kf_tiles.count;
23
+
24
+
kf_tiles.key[id] = opts.key;
25
+
kf_tiles.mapcol[id] = opts.mapcol;
26
+
kf_tiles.sheet[id] = opts.sheet;
27
+
kf_tiles.sprite[id] = opts.sprite;
28
+
kf_tiles.collide[id] = opts.collide;
29
+
30
+
return id;
31
+
}
32
+
11
33
struct kf_world *kf_world_new(u32 width, u32 height, kf_tileid_t fill)
12
34
{
13
-
const size_t len = sizeof(kf_tileid_t) * width * height;
14
-
struct kf_world *world = malloc(sizeof(struct kf_world) + len);
35
+
const size_t len = sizeof(struct kf_world) + sizeof(struct kf_tile)*width*height;
36
+
struct kf_world *world = malloc(len);
37
+
printf("creating world: %lu bytes: %p\n", len, world);
15
38
world->revision = 0;
16
39
world->width = width;
17
40
world->height = height;
18
-
memset(world->map, fill, len);
41
+
memset(world->map, 0, sizeof(struct kf_tile)*width*height);
42
+
for (size_t i = 0 ; i < width*height ; i++)
43
+
world->map[i].id = fill;
44
+
45
+
u32 x;
46
+
for (u32 y = 0 ; y < height ; y++)
47
+
{
48
+
for (x = 0 ; x < width ; x++)
49
+
{
50
+
_kf_updatetilebitmask(world, x, y);
51
+
}
52
+
}
53
+
19
54
return world;
20
55
}
21
56
22
57
size_t kf_world_getsize(struct kf_world *world)
23
58
{
24
-
return sizeof(struct kf_world) + sizeof(kf_tileid_t)*world->width*world->height;
59
+
return sizeof(struct kf_world) + sizeof(struct kf_tile)*world->width*world->height;
60
+
}
61
+
62
+
static inline
63
+
void _kf_updatetilebitmask(struct kf_world *world, u32 x, u32 y)
64
+
{
65
+
struct kf_tile *t = kf_world_gettile(world, x, y);
66
+
kf_tileid_t
67
+
n = y-1 >= world->height ? 0 : kf_world_gettile(world, x, y-1)->id,
68
+
w = x-1 >= world->width ? 0 : kf_world_gettile(world, x-1, y)->id,
69
+
e = x+1 >= world->width ? 0 : kf_world_gettile(world, x+1, y)->id,
70
+
s = y+1 >= world->height ? 0 : kf_world_gettile(world, x, y+1)->id;
71
+
t->data = 0x0000;
72
+
if (t->id == n) t->data |= KF_TILEMASK_NORTH;
73
+
if (t->id == w) t->data |= KF_TILEMASK_WEST;
74
+
if (t->id == e) t->data |= KF_TILEMASK_EAST;
75
+
if (t->id == s) t->data |= KF_TILEMASK_SOUTH;
25
76
}
26
77
27
-
kf_tileid_t *kf_world_gettile(struct kf_world *world, u32 x, u32 y)
78
+
void kf_world_updatetile(struct kf_world *world, u32 x, u32 y, bool update_neighbours)
79
+
{
80
+
_kf_updatetilebitmask(world, x, y);
81
+
if (update_neighbours)
82
+
{
83
+
if (y-1 < world->height) kf_world_updatetile(world, x, y-1, false);
84
+
if (x-1 < world->width) kf_world_updatetile(world, x-1, y, false);
85
+
if (x+1 < world->width) kf_world_updatetile(world, x+1, y, false);
86
+
if (y+1 < world->height) kf_world_updatetile(world, x, y+1, false);
87
+
}
88
+
}
89
+
90
+
inline
91
+
struct kf_vec2(u32) kf_getspritefortilebitmask(kf_tiledatum_t t)
92
+
{
93
+
switch (t)
94
+
{
95
+
case 0x0000: return (struct kf_vec2(u32)){0, 3}; /* 0x0000: */
96
+
case 0x0001: return (struct kf_vec2(u32)){0, 2}; /* 0x0001: N */
97
+
case 0x0010: return (struct kf_vec2(u32)){3, 3}; /* 0x0010: W */
98
+
case 0x0011: return (struct kf_vec2(u32)){3, 2}; /* 0x0011: NW */
99
+
case 0x0100: return (struct kf_vec2(u32)){1, 3}; /* 0x0100: E */
100
+
case 0x0101: return (struct kf_vec2(u32)){1, 2}; /* 0x0101: EN */
101
+
case 0x0110: return (struct kf_vec2(u32)){2, 3}; /* 0x0110: EW */
102
+
case 0x0111: return (struct kf_vec2(u32)){2, 2}; /* 0x0111: EWN */
103
+
case 0x1000: return (struct kf_vec2(u32)){0, 0}; /* 0x1000: S */
104
+
case 0x1001: return (struct kf_vec2(u32)){0, 1}; /* 0x1001: SN */
105
+
case 0x1010: return (struct kf_vec2(u32)){3, 0}; /* 0x1010: SW */
106
+
case 0x1011: return (struct kf_vec2(u32)){3, 1}; /* 0x1011: SWN */
107
+
case 0x1100: return (struct kf_vec2(u32)){1, 0}; /* 0x1100: SE */
108
+
case 0x1101: return (struct kf_vec2(u32)){1, 1}; /* 0x1101: SEN */
109
+
case 0x1110: return (struct kf_vec2(u32)){2, 0}; /* 0x1110: SEW */
110
+
case 0x1111: return (struct kf_vec2(u32)){2, 1}; /* 0x1111: NESW */
111
+
}
112
+
KF_UNREACHABLE("invalid bitmask: 0x%x", t);
113
+
return (struct kf_vec2(u32)){-1, -1};
114
+
}
115
+
116
+
struct kf_tile *kf_world_gettile(struct kf_world *world, u32 x, u32 y)
28
117
{
29
118
return &world->map[y*world->width + x];
30
119
}
···
47
136
const u32 ex = fmin(world->width, ceilf(end.x / KF_TILE_SIZE_PX));
48
137
const u32 ey = fmin(world->height, ceilf(end.y / KF_TILE_SIZE_PX));
49
138
const size_t down = world->width - ex + sx - 1; /* number of indexes to add to reach the next tile down */
50
-
kf_tileid_t *tile = kf_world_gettile(world, sx, sy);
139
+
struct kf_tile *tile = kf_world_gettile(world, sx, sy);
51
140
52
141
/* check if any tiles will collide with the actor's rect */
53
142
const f32 trx = sx * KF_TILE_SIZE_PX;
···
63
152
{
64
153
for (x = sx ; x <= ex ; x++)
65
154
{
66
-
if (kf_tiles.collide[*tile])
155
+
if (kf_tiles.collide[tile->id])
67
156
DrawRectangleLinesEx(tr, 1, CheckCollisionRecs(r, tr) ? RED : BLACK);
68
157
69
158
tile++; /* shift tile pointer to the right */
···
84
173
const u32 ex = fmin(world->width, ceilf(end.x / KF_TILE_SIZE_PX));
85
174
const u32 ey = fmin(world->height, ceilf(end.y / KF_TILE_SIZE_PX));
86
175
const size_t down = world->width - ex + sx; /* number of indexes to add to reach the next tile down */
87
-
kf_tileid_t *tile = kf_world_gettile(world, sx, sy);
176
+
struct kf_tile *tile = kf_world_gettile(world, sx, sy);
88
177
u32 x;
89
178
for (u32 y = sy ; y < ey ; y++)
90
179
{
91
180
for (x = sx ; x < ex ; x++)
92
181
{
93
-
DrawRectangle(
94
-
(int)x * KF_TILE_SIZE_PX,
95
-
(int)y * KF_TILE_SIZE_PX,
96
-
KF_TILE_SIZE_PX,
97
-
KF_TILE_SIZE_PX,
98
-
kf_tiles.mapcol[*tile]
99
-
);
182
+
KF_SANITY_CHECK(tile->id <= kf_tiles.count, "erroneous tile on map at %u,%u: %u (count=%u)", x, y, tile->id, kf_tiles.count);
183
+
if (tile->id)
184
+
{
185
+
struct kf_vec2(u32) s = kf_getspritefortilebitmask(tile->data);
186
+
kf_drawsprite_wh(
187
+
kf_tiles.sheet[tile->id],
188
+
x*KF_TILE_SIZE_PX,
189
+
y*KF_TILE_SIZE_PX,
190
+
KF_TILE_SIZE_PX,
191
+
KF_TILE_SIZE_PX,
192
+
kf_tiles.sprite[tile->id].x + s.x,
193
+
kf_tiles.sprite[tile->id].y + s.y
194
+
);
195
+
}
100
196
tile++; /* shift tile pointer to the right */
101
197
}
102
198
tile += down; /* shift tile pointer down */