summaryrefslogtreecommitdiff
path: root/asset.cpp
blob: fc8abde74207ca38bc5b3d7e3a47e409fd3033c7 (plain) (blame)
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
#include "asset.hpp"

extern "C" {
#include "memory.h"
#include "pack.h"
#include "plat.h"
#include "str.h"
}

#define max_asset_types 32
#define asset_scratch_size (1024 * 1024)

struct RLoader {
	char magic[4];
	Asset_Loader* loader;
};

struct Manager {
	RLoader loaders[max_asset_types];

	Manager() {
		int i;
		for (i = 0; i < max_asset_types; i++) {
			loaders[i].loader = 0;
		}
	}

	RLoader* find_loader(const char* magic) {
		uint32_t hash = fnv1a64((uint8_t*)magic, 4);
		int bucket = (int)(hash % max_asset_types);
		int i;
		for (i = 0; i < max_asset_types; i++) {
			RLoader& e = loaders[bucket];
			if (!e.loader || (
				e.magic[0] == magic[0] &&
				e.magic[1] == magic[1] &&
				e.magic[2] == magic[2] &&
				e.magic[3] == magic[3]
			)) return &e;
			bucket = (bucket + 1) % max_asset_types;
		}
		return 0;
	}

	Asset_Loader& get_loader(const char* magic) {
		RLoader* r = find_loader(magic);
		assert(r != 0 && r->loader != 0);
		return *r->loader;
	}

	void set_loader(const char* magic, Asset_Loader* l) {
		RLoader* r = find_loader(magic);
		assert(r != 0 && r->loader == 0);
		r->magic[0] = magic[0];
		r->magic[1] = magic[1];
		r->magic[2] = magic[2];
		r->magic[3] = magic[3];
		r->loader = l;
	}
} manager;

void register_asset_loader(
	const char* magic,
	Asset_Loader* loader
) {
	manager.set_loader(magic, loader);
}

void Asset_Arena::init(Arena* arena, const char* pack_name) {
	p = pack_open(pack_name, arena);
	assert(p != 0);
	a = arena;
	s = (Arena*)arena_alloc(a, sizeof *s);
	init_arena(
		s,
		arena_alloc(a, asset_scratch_size),
		asset_scratch_size
	);
	assets = 0;
}

void Asset_Arena::destroy() {
	Asset* a;
	for (a = assets; a; a = a->next) {
		a->loader->unload(a);
	}
	pack_close(p);
}

void Asset_Arena::claim(Asset* a) {
	if (assets) {
		a->next = assets;
		assets = a;
	} else assets = a;
}

Asset* Asset_Arena::load(const char* name) {
	char magic[4];
	Pack_File* f = pack_open_file(p, name);
	if (!f) return 0;
	pack_read(f, magic, 4);
	pack_seek(f, 0, seek_rel_start);
	Asset_Loader& loader = manager.get_loader(magic);
	clear_arena(s);
	Asset* asset = loader.load(a, s, f);
	if (asset) {
		asset->loader = &loader;
		claim(asset);
	}
	pack_close_file(f);
	return asset;
}