1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#define STB_IMAGE_IMPLEMENTATION
#include "lib/stb_image.h"
#include <assert.h>
#include "util/file.h"
#include "util/err.h"
#include "resource.h"
#include "cube.h"
static void image_copy(unsigned int dst_size[2], rgba_data dst, unsigned int src_size[2], const rgba_data src, unsigned int off[2])
{
assert(off[0] + dst_size[0] <= src_size[0]);
assert(off[1] + dst_size[1] <= src_size[1]);
for (unsigned int y = 0; y < dst_size[1]; y++)
memcpy(
(char *)dst + dst_size[0]*y * 4,
(const char *)src + ((off[1] + y)*src_size[0] + off[0]) * 4,
dst_size[0]*4);
}
static texture_id create_texture(struct texture_source *tex, struct source *src, struct draw_backend *draw)
{
FILE *f = file_open(tex->path.str, "rb");
if (!f)
source_error(src, tex->path.loc, "%.*s: failed to open file", PSTR(tex->path.str));
int width, height;
void *img_data = stbi_load_from_file(f, &width, &height, nullptr, 4);
if (!img_data)
source_error(src, tex->path.loc, "%.*s: failed to load image", PSTR(tex->path.str));
unsigned int img_size[2] = { width, height };
texture_id id;
switch (tex->type) {
case TEXTURE_2D:
if (!draw->create_texture(tex->type, img_size, &img_data, &id))
source_error(src, tex->path.loc, "%.*s: failed to create texture", PSTR(tex->path.str));
break;
case TEXTURE_CUBEMAP: {
if (img_size[0] % 4)
source_error(src, tex->path.loc, "%.*s: cubemap image width is not divisible by 4", PSTR(tex->path.str));
if (img_size[1] % 3)
source_error(src, tex->path.loc, "%.*s: cubemap image height is not divisible by 3", PSTR(tex->path.str));
unsigned int face_size[2] = { img_size[0] / 4, img_size[1] / 3 };
static const unsigned int coords[6][2] = {
// right, left, top, bottom, front, back
{ 2, 1 }, { 0, 1 }, { 1, 0 }, { 1, 2 }, { 1, 1 }, { 1, 3 },
};
rgba_data faces[6];
size_t face_len = 4 * face_size[0] * face_size[1];
void *buffer = malloc(6 * face_len);
for (size_t i = 0; i < 6; i++)
image_copy(
face_size,
faces[i] = (char *)buffer + face_len*i,
img_size,
img_data,
(unsigned int [2]) { coords[i][0] * face_size[0], coords[i][1] * face_size[1] });
if (!draw->create_texture(tex->type, face_size, faces, &id))
source_error(src, tex->path.loc, "%.*s: failed to create texture", PSTR(tex->path.str));
free(buffer);
}
}
stbi_image_free(img_data);
return id;
}
static mesh_id create_mesh(struct mesh_source *mesh, struct source *src, struct draw_backend *draw)
{
(void) draw;
source_error(src, mesh->path.loc, "TODO: obj loading");
}
#define LOAD_CACHED(what, cache_field) do { \
what ## _id id, *p_id = nullptr; \
map_find(&cache->cache_field, what->source.path.str, &p_id); \
if (p_id) { \
id = *p_id; \
} else { \
id = create_ ## what(&what->source, src, draw); \
map_insert_end(&cache->cache_field, what->source.path.str, id); \
} \
what->id = id; \
} while (0)
void texture_load(struct texture *texture, struct source *src, struct draw_backend *draw, struct cache *cache)
{
/*
texture_id id, *p_id = nullptr;
map_find(&cache->textures[tex->source.type], tex->source.path, &p_id);
if (p_id) {
id = *p_id;
} else {
id = create_texture(&tex->source, src, draw);
map_insert_end(&cache->textures[tex->source.type], tex->source.path, id);
}
free(tex->source.path.str);
tex->id = id;
*/
LOAD_CACHED(texture, textures[texture->source.type]);
}
void mesh_load(struct mesh *mesh, struct source *src, struct draw_backend *draw, struct cache *cache)
{
switch (mesh->source.type) {
case MESH_CUBE:
if (cache->cube_mesh.present) {
mesh->id = cache->cube_mesh.data;
} else {
if (!draw->create_mesh(sizeof cube_verts / sizeof *cube_verts, cube_verts, &mesh->id))
eprintf("failed to create cube mesh\n");
cache->cube_mesh.present = true;
cache->cube_mesh.data = mesh->id;
}
break;
case MESH_OBJ:
LOAD_CACHED(mesh, meshes);
break;
}
}
void cache_free(struct cache *cache)
{
free(cache->textures[TEXTURE_2D].ptr);
free(cache->textures[TEXTURE_CUBEMAP].ptr);
free(cache->meshes.ptr);
}
|