477 lines
13 KiB
C++
477 lines
13 KiB
C++
|
/*
|
||
|
|
||
|
Asset manifest operations
|
||
|
-Allen
|
||
|
06.06.2016
|
||
|
|
||
|
*/
|
||
|
|
||
|
// TOP
|
||
|
|
||
|
inline rptr32
|
||
|
to_rptr32(void *pos, void *base){
|
||
|
rptr32 result = (rptr32)((char*)pos - (char*)base);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
inline void*
|
||
|
to_ptr(rptr32 pos, void *base){
|
||
|
void *result = ((char*)base + pos);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
inline Asset_Node*
|
||
|
to_node_ptr(rptr32 pos, void *base){
|
||
|
Asset_Node *result = (Asset_Node *)((char*)base + pos);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
inline Asset_Node*
|
||
|
get_node(i32 image_id, Asset_Manifest *manifest){
|
||
|
Asset_Node *node = to_node_ptr(manifest->asset_nodes, manifest);
|
||
|
node += image_id - 1;
|
||
|
return(node);
|
||
|
}
|
||
|
|
||
|
inline i32
|
||
|
get_image_id(rptr32 pos, Asset_Manifest *manifest){
|
||
|
i32 dist = (pos - manifest->asset_nodes);
|
||
|
Assert(dist % sizeof(Asset_Node) == 0);
|
||
|
dist = 1 + (dist/sizeof(Asset_Node));
|
||
|
return(dist);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
init_sentinel(Asset_Node *node, void *base){
|
||
|
rptr32 self = to_rptr32(node, base);
|
||
|
node->next_sibling = self;
|
||
|
node->prev_sibling = self;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
insert_node(Asset_Node *node, Asset_Node *pos, void *base){
|
||
|
rptr32 node_self = to_rptr32(node, base);
|
||
|
rptr32 pos_self = to_rptr32(pos, base);
|
||
|
rptr32 next_self = pos->next_sibling;
|
||
|
Asset_Node *next = to_node_ptr(next_self, base);
|
||
|
|
||
|
node->prev_sibling = pos_self;
|
||
|
node->next_sibling = next_self;
|
||
|
|
||
|
pos->next_sibling = node_self;
|
||
|
next->prev_sibling = node_self;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
remove_node(Asset_Node *node, void *base){
|
||
|
rptr32 next_self = node->next_sibling;
|
||
|
rptr32 prev_self = node->prev_sibling;
|
||
|
Asset_Node *next = to_node_ptr(next_self, base);
|
||
|
Asset_Node *prev = to_node_ptr(prev_self, base);
|
||
|
|
||
|
next->prev_sibling = prev_self;
|
||
|
prev->next_sibling = next_self;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
sibling_insert_before(Asset_Node *node, Asset_Node *pos, void *base){
|
||
|
rptr32 node_self = to_rptr32(node, base);
|
||
|
rptr32 pos_self = to_rptr32(pos, base);
|
||
|
rptr32 prev_self = pos->prev_sibling;
|
||
|
Asset_Node *prev = to_node_ptr(prev_self, base);
|
||
|
|
||
|
node->parent = pos->parent;
|
||
|
|
||
|
node->next_sibling = pos_self;
|
||
|
node->prev_sibling = prev_self;
|
||
|
|
||
|
pos->prev_sibling = node_self;
|
||
|
prev->next_sibling = node_self;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
sibling_insert_after(Asset_Node *node, Asset_Node *pos, void *base){
|
||
|
rptr32 node_self = to_rptr32(node, base);
|
||
|
rptr32 pos_self = to_rptr32(pos, base);
|
||
|
rptr32 next_self = pos->next_sibling;
|
||
|
Asset_Node *next = to_node_ptr(next_self, base);
|
||
|
|
||
|
node->parent = pos->parent;
|
||
|
|
||
|
node->prev_sibling = pos_self;
|
||
|
node->next_sibling = next_self;
|
||
|
|
||
|
pos->next_sibling = node_self;
|
||
|
next->prev_sibling = node_self;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
tree_remove(Asset_Node *node, void *base){
|
||
|
rptr32 parent_self = node->parent;
|
||
|
rptr32 node_self = to_rptr32(node, base);
|
||
|
rptr32 next_self = node->next_sibling;
|
||
|
rptr32 prev_self = node->prev_sibling;
|
||
|
Asset_Node *parent = to_node_ptr(parent_self, base);
|
||
|
Asset_Node *next = to_node_ptr(next_self, base);
|
||
|
Asset_Node *prev = to_node_ptr(prev_self, base);
|
||
|
|
||
|
next->prev_sibling = prev_self;
|
||
|
prev->next_sibling = next_self;
|
||
|
|
||
|
if (parent->first_child == node_self){
|
||
|
if (next_self != node_self){
|
||
|
parent->first_child = next_self;
|
||
|
}
|
||
|
else{
|
||
|
parent->first_child = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
insert_under(Asset_Node *node, Asset_Node *parent, void *base, b32 insert_as_first){
|
||
|
if (parent->first_child == 0){
|
||
|
rptr32 node_self = to_rptr32(node, base);
|
||
|
rptr32 parent_self = to_rptr32(parent, base);
|
||
|
|
||
|
parent->first_child = node_self;
|
||
|
node->next_sibling = node_self;
|
||
|
node->prev_sibling = node_self;
|
||
|
node->parent = parent_self;
|
||
|
}
|
||
|
else{
|
||
|
Asset_Node *first = to_node_ptr(parent->first_child, base);
|
||
|
sibling_insert_before(node, first, base);
|
||
|
|
||
|
if (insert_as_first){
|
||
|
rptr32 node_self = to_rptr32(node, base);
|
||
|
parent->first_child = node_self;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
add_free_nodes(Asset_Manifest *manifest, Wrapped_Partition *part){
|
||
|
i32 node_count = (manifest->part.max - manifest->part.pos) / sizeof(Asset_Node);
|
||
|
|
||
|
if (node_count > 0){
|
||
|
Asset_Node *nodes = push_array(part, Asset_Node, node_count);
|
||
|
|
||
|
i32 j = manifest->asset_node_count + 1;
|
||
|
|
||
|
if (manifest->asset_nodes == 0){
|
||
|
manifest->asset_nodes = to_rptr32(nodes, manifest);
|
||
|
}
|
||
|
manifest->asset_node_count += node_count;
|
||
|
manifest->asset_free_count += node_count;
|
||
|
|
||
|
Asset_Node *node = nodes;
|
||
|
for (i32 i = 0; i < node_count; ++i, ++j, ++node){
|
||
|
insert_node(node, &manifest->free_sentinel, manifest);
|
||
|
node->image_id = j;
|
||
|
node->name[0] = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
initialize_empty_manifest(void *manifest_memory, i32 size){
|
||
|
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
|
||
|
manifest->version = ASSET_MANIFEST_VERSION;
|
||
|
|
||
|
manifest->part = make_relative_partition(size);
|
||
|
|
||
|
Wrapped_Partition part_ = make_wrapped_partition(&manifest->part, manifest_memory);
|
||
|
Wrapped_Partition *part = &part_;
|
||
|
|
||
|
push_type(part, Asset_Manifest);
|
||
|
|
||
|
init_sentinel(&manifest->free_sentinel, manifest_memory);
|
||
|
|
||
|
manifest->asset_node_count = 0;
|
||
|
manifest->asset_free_count = 0;
|
||
|
|
||
|
add_free_nodes(manifest, part);
|
||
|
}
|
||
|
|
||
|
#define MANIFEST_NAME "CDmanifest"
|
||
|
|
||
|
Asset_Manifest*
|
||
|
manifest_load(System_API *system, Partition *part){
|
||
|
void *result = 0;
|
||
|
|
||
|
Temp_Memory temp = begin_temp(part);
|
||
|
File_Dump dump = system->DBG_dump_begin(MANIFEST_NAME);
|
||
|
|
||
|
if (dump.size > 0){
|
||
|
result = push_block(part, dump.size);
|
||
|
|
||
|
if (result == 0){
|
||
|
#ifdef DEVELOPER
|
||
|
DBG_expand_partition(system, part, dump.size);
|
||
|
result = push_block(part, dump.size);
|
||
|
#else
|
||
|
InvalidCodePath;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (!system->DBG_dump_end(dump, result)){
|
||
|
end_temp(temp);
|
||
|
result = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return((Asset_Manifest*)result);
|
||
|
}
|
||
|
|
||
|
#ifdef DEVELOPER
|
||
|
void
|
||
|
manifest_dump(System_API *system, void *base){
|
||
|
Asset_Manifest *manifest = (Asset_Manifest*)base;
|
||
|
i32 memory_size = manifest->part.max;
|
||
|
system->DBG_dump_out(MANIFEST_NAME, base, memory_size);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void
|
||
|
allocate_node(Asset_Manifest *manifest,
|
||
|
Asset_Node *node,
|
||
|
char *filename, i32 len){
|
||
|
--manifest->asset_free_count;
|
||
|
|
||
|
remove_node(node, manifest);
|
||
|
cd_memcpy(node->name, filename, len+1);
|
||
|
|
||
|
node->first_child = 0;
|
||
|
node->next_sibling = 0;
|
||
|
node->prev_sibling = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
free_node(Asset_Manifest *manifest,
|
||
|
Asset_Node *node){
|
||
|
|
||
|
++manifest->asset_free_count;
|
||
|
|
||
|
insert_node(node, &manifest->free_sentinel, manifest);
|
||
|
cd_memcpy(node->name, "", 0);
|
||
|
}
|
||
|
|
||
|
rptr32
|
||
|
declare_image(void *manifest_memory, char *filename, i32 image_id, i32 expect_empty){
|
||
|
rptr32 result = 0;
|
||
|
i32 len = 0;
|
||
|
|
||
|
len = cd_strlen(filename);
|
||
|
|
||
|
if (len != 0 && len < ASSET_MAX_NAME){
|
||
|
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
|
||
|
Asset_Node *nodes = (Asset_Node*)
|
||
|
to_ptr(manifest->asset_nodes, manifest_memory);
|
||
|
Asset_Node *node = nodes + (image_id - 1);
|
||
|
|
||
|
if (node->name[0] == 0 && expect_empty){
|
||
|
allocate_node(manifest, node, filename, len);
|
||
|
result = to_rptr32(node, manifest_memory);
|
||
|
}
|
||
|
else if (node->name[0] != 0 && !expect_empty){
|
||
|
cd_memcpy(node->name, filename, len+1);
|
||
|
result = to_rptr32(node, manifest_memory);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
rptr32
|
||
|
bind_image(void *manifest_memory, Manifest_Setup *setup, char *filename, i32 image_id){
|
||
|
rptr32 result = declare_image(manifest_memory, filename, image_id, true);
|
||
|
|
||
|
if (setup->count > 0){
|
||
|
Asset_Node *node = to_node_ptr(result, manifest_memory);
|
||
|
Asset_Node *parent = to_node_ptr(setup->parents[setup->count-1], manifest_memory);
|
||
|
|
||
|
insert_under(node, parent, manifest_memory, false);
|
||
|
node->type = AssetType_Image;
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
rptr32
|
||
|
replace_image(void *manifest_memory, char *filename, i32 image_id){
|
||
|
return(declare_image(manifest_memory, filename, image_id, false));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
begin_folder(void *manifest_memory, Manifest_Setup *setup, char *name, i32 image_id){
|
||
|
Assert(setup->count < ArrayCount(setup->parents));
|
||
|
|
||
|
rptr32 node_self = bind_image(manifest_memory, setup, name, image_id);
|
||
|
setup->parents[setup->count++] = node_self;
|
||
|
|
||
|
Asset_Node *node = to_node_ptr(node_self, manifest_memory);
|
||
|
node->type = AssetType_GenericFolder;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
end_folder(void *manifest_memory, Manifest_Setup *setup){
|
||
|
Assert(setup->count > 0);
|
||
|
--setup->count;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
new_image(void *manifest_memory, char *filename){
|
||
|
i32 result = 0;
|
||
|
|
||
|
i32 len = cd_strlen(filename);
|
||
|
|
||
|
if (len != 0 && len < ASSET_MAX_NAME){
|
||
|
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
|
||
|
Asset_Node *node =
|
||
|
to_node_ptr(manifest->free_sentinel.next_sibling, manifest_memory);
|
||
|
if (node != &manifest->free_sentinel){
|
||
|
Assert(node->name[0] == 0);
|
||
|
allocate_node(manifest, node, filename, len);
|
||
|
result = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
delete_image(void *manifest_memory, i32 image_id){
|
||
|
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
|
||
|
Asset_Node *nodes = to_node_ptr(manifest->asset_nodes, manifest_memory);
|
||
|
Asset_Node *node = nodes + (image_id - 1);
|
||
|
|
||
|
if (node->name[0] != 0){
|
||
|
free_node(manifest, node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
move_manifest_to_bigger_block(void *manifest_memory, void *new_memory, i32 size){
|
||
|
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
|
||
|
|
||
|
Assert(manifest->part.max < size);
|
||
|
|
||
|
if (new_memory != manifest_memory){
|
||
|
cd_memcpy(new_memory, manifest_memory, manifest->part.max);
|
||
|
}
|
||
|
manifest = (Asset_Manifest*)new_memory;
|
||
|
manifest->part.max = size;
|
||
|
|
||
|
Wrapped_Partition part = make_wrapped_partition(&manifest->part, manifest_memory);
|
||
|
add_free_nodes(manifest, &part);
|
||
|
}
|
||
|
|
||
|
#ifdef DEVELOPER
|
||
|
Asset_Node*
|
||
|
get_available_node(System_API *system, Partition *manifest_part, Asset_Manifest **manifest_memory_ptr){
|
||
|
Asset_Manifest *manifest = (Asset_Manifest*)manifest_part->base;
|
||
|
|
||
|
rptr32 node_self = manifest->free_sentinel.next_sibling;
|
||
|
Asset_Node *result = to_node_ptr(node_self, manifest);
|
||
|
|
||
|
if (result == &manifest->free_sentinel){
|
||
|
i32 pos = manifest_part->rel_part.pos;
|
||
|
Asset_Manifest *new_manifest = (Asset_Manifest*)push_block(manifest_part, pos);
|
||
|
if (new_manifest == 0){
|
||
|
DBG_expand_partition(system, manifest_part, pos);
|
||
|
new_manifest = (Asset_Manifest*)push_block(manifest_part, pos);
|
||
|
Assert(new_manifest);
|
||
|
manifest = (Asset_Manifest*)manifest_part->base;
|
||
|
*manifest_memory_ptr = (Asset_Manifest*)manifest_part->base;
|
||
|
}
|
||
|
move_manifest_to_bigger_block(manifest, manifest, manifest_part->rel_part.pos);
|
||
|
|
||
|
node_self = manifest->free_sentinel.next_sibling;
|
||
|
result = to_node_ptr(node_self, manifest);
|
||
|
Assert(result != &manifest->free_sentinel);
|
||
|
}
|
||
|
|
||
|
allocate_node(manifest, result, "New", 3);
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
Asset_Walker_Entry
|
||
|
new_walker_entry(rptr32 first, i32 level){
|
||
|
Asset_Walker_Entry result;
|
||
|
result.first = first;
|
||
|
result.current = first;
|
||
|
result.level = level;
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
Asset_Node*
|
||
|
walk_first_asset_node(void *manifest_memory, Asset_Walker *walker){
|
||
|
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
|
||
|
Asset_Node *nodes = to_node_ptr(manifest->asset_nodes, manifest_memory);
|
||
|
Asset_Node *node = nodes + (ROOT - 1);
|
||
|
|
||
|
walker->current_level = 0;
|
||
|
|
||
|
if (node->first_child){
|
||
|
walker->stack[walker->top++] = new_walker_entry(node->first_child, 1);
|
||
|
}
|
||
|
|
||
|
return(node);
|
||
|
}
|
||
|
|
||
|
Asset_Node*
|
||
|
walk_next_asset_node(void *manifest_memory, Asset_Walker *walker){
|
||
|
Asset_Node *node = 0;
|
||
|
|
||
|
if (walker->top != 0){
|
||
|
walker->current_level = walker->stack[walker->top-1].level;
|
||
|
}
|
||
|
|
||
|
if (walker->top > 0){
|
||
|
Asset_Walker_Entry *top = walker->stack + (walker->top - 1);
|
||
|
|
||
|
node = to_node_ptr(top->current, manifest_memory);
|
||
|
|
||
|
top->current = node->next_sibling;
|
||
|
|
||
|
if (top->current == top->first){
|
||
|
--walker->top;
|
||
|
}
|
||
|
|
||
|
if (node->first_child){
|
||
|
walker->stack[walker->top++] =
|
||
|
new_walker_entry(node->first_child, top->level + 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(node);
|
||
|
}
|
||
|
|
||
|
Asset_Node*
|
||
|
walk_skip_children_asset_node(void *manifest_memory, Asset_Walker *walker){
|
||
|
Asset_Node *node = 0;
|
||
|
|
||
|
if (walker->top > 0){
|
||
|
Asset_Walker_Entry *top = walker->stack + (walker->top - 1);
|
||
|
|
||
|
while (top->level > walker->current_level){
|
||
|
--walker->top;
|
||
|
if (walker->top > 0){
|
||
|
top = walker->stack + (walker->top - 1);
|
||
|
}
|
||
|
else{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
node = walk_next_asset_node(manifest_memory, walker);
|
||
|
}
|
||
|
|
||
|
return(node);
|
||
|
}
|
||
|
|
||
|
// BOTTOM
|