0 registered members (),
1,094
guests, and 1
spider. |
Key:
Admin,
Global Mod,
Mod
|
|
|
Preloading assets in the background
#371304
05/19/11 19:17
05/19/11 19:17
|
Joined: Mar 2006
Posts: 3,538 WA, Australia
JibbSmart
OP
Expert
|
OP
Expert
Joined: Mar 2006
Posts: 3,538
WA, Australia
|
G'day! I have two requests. It'd be really cool to be able to preload models, sounds, levels, bmaps, and even arbitrary files in the background, over many frames (like how the http_ functions let the game continue while it waits for data). This could lead to huge levels that are loaded dynamically and all sorts of cool stuff. I imagine it could be used something like this (based on the http example code):
var id = load_asset("massivelyComplexEnt.mdl");
while (!load_ready(id)) wait(1);
if (load_ready(id) == 1) { // load successful?
levelReady = 1; // global var to notify everyone the next room is ready
ent_create("massivelyComplexEnt.mdl", nullvector, roomSetupAction);
} else {
error("BIG MISTAKE!");
}
Unless, of course, is there already a way to safely do this with our own threading? An additional function to check if an asset has already been loaded or is in the process of being loaded would also be fantastic, but that kind of thing we can manage ourselves. Something like: load_status(var id) Returns information about an asset's place in memory:
2 asset has already been loaded 1 asset is being loaded 0 asset has not been loaded My second request is an option to not load the level anew when using session_connect or session_open (or any other session_ functions that require it). I guess this has to do with synchronising entities between sessions, but I'm sure I'm not the only one who sets dplay_entrate to -1 and synchronises everything manually with the send_data_ functions. It'd be nice to set a variable or something for these situations so levels don't need to be loaded again, and then use the session_ functions as we please without having to re-initialise levels. If you've played Burnout Paradise, a very cool features was that you could connect to a game and drop out of it without interrupting your driving, since it was all one big world, and all it had to do on the client side was synchronise a few players, and then remove them when you disconnect. Thanks for reading Jibb
Formerly known as JulzMighty. I made KarBOOM!
|
|
|
Re: Preloading assets in the background
[Re: Quad]
#371310
05/19/11 19:46
05/19/11 19:46
|
Joined: Oct 2007
Posts: 5,210 İstanbul, Turkey
Quad
Senior Expert
|
Senior Expert
Joined: Oct 2007
Posts: 5,210
İstanbul, Turkey
|
load_status return value 3 asset was already loaded, use force_reload to force reloading.
3333333333
|
|
|
Re: Preloading assets in the background
[Re: Quad]
#371314
05/19/11 19:49
05/19/11 19:49
|
Joined: Mar 2006
Posts: 3,538 WA, Australia
JibbSmart
OP
Expert
|
OP
Expert
Joined: Mar 2006
Posts: 3,538
WA, Australia
|
Yes ^^ That would be very useful for level editors, for example.
Jibb
Formerly known as JulzMighty. I made KarBOOM!
|
|
|
Re: Preloading assets in the background
[Re: MasterQ32]
#371339
05/20/11 07:30
05/20/11 07:30
|
Joined: Jul 2001
Posts: 6,904
HeelX
Senior Expert
|
Senior Expert
Joined: Jul 2001
Posts: 6,904
|
Streaming content is one of those big things I can think of which are missing in Gamestudio. This counts for all kinds of stuff: Bitmaps, Models, Levels, Sounds, etc. One further suggestion: If one would stream a content and creates it with the common functions like ent_create, the streaming will be continued until it is ready and then it will automatically created by the called function. This way, one could start streaming e.g. the next level, if the player is in the reach of the level exit. So, lets say it is big and loaded by ~70% when the level_load call is done. Then, the level_load call would wait, until the remaining ~30% of the level is loaded and then it will be "activated". Sounds reasonable, isn't it?
|
|
|
Re: Preloading assets in the background
[Re: Zapan@work]
#371359
05/20/11 12:05
05/20/11 12:05
|
Joined: Apr 2007
Posts: 3,751 Canada
WretchedSid
Expert
|
Expert
Joined: Apr 2007
Posts: 3,751
Canada
|
Ahh, no one needs a dll and taking money for something this trivial brings bad karma (imo) Here you go, a working version. It calls add_buffer() on the mainthread, so no need to fear anything. Just save it into a file and include it. Done.
#include <windows.h>
#include <stdio.h>
typedef struct entA_state
{
char loaded; // 0 = not begun loading, 1 = loading, 2 = loaded, 3 = Added, 200 = Fuckup
void *buffer;
long size;
char *file;
char *filepath;
struct entA_state *next;
} entA_state;
HANDLE entA_mutex;
entA_state *entA_firstState;
DWORD entA_worker(void *unused);
int entA_init()
{
entA_firstState = NULL;
entA_mutex = CreateMutex(NULL, FALSE, NULL);
if(entA_mutex == NULL)
{
return 0;
}
DWORD threadID;
// TODO: Error checking
CreateThread(NULL, 0, entA_worker, NULL, 0, &threadID);
SetThreadPriority(threadID, THREAD_PRIORITY_LOWEST);
return 1;
}
DWORD entA_loadObject(entA_state *state)
{
FILE *file = fopen(state->filepath, "rb");
if(!file)
{
// BAD BAD BAD
WaitForSingleObject(entA_mutex, INFINITE);
state->loaded = 200;
ReleaseMutex(entA_mutex);
return 1;
}
// Get the size of the file
fseek(file, 0, SEEK_END);
state->size = ftell(file);
rewind(file);
// TODO: Error checking
state->buffer = (void *)malloc(state->size);
fread(state->buffer, 1, state->size, file);
fclose(file);
WaitForSingleObject(entA_mutex, INFINITE);
state->loaded = 2; // We are done, hooray!
ReleaseMutex(entA_mutex);
return 1;
}
DWORD entA_worker(void *unused)
{
while(1)
{
WaitForSingleObject(entA_mutex, INFINITE);
entA_state *state = entA_firstState;
while(state)
{
if(state->loaded == 0)
{
state->loaded = 1;
CreateThread(NULL, 0, entA_loadObject, state, 0, NULL);
}
state = state->next;
}
ReleaseMutex(entA_mutex);
}
return 1;
}
entA_state *entA_stateForFile(char *file, char *filepath)
{
entA_state *state = entA_firstState;
while(state)
{
if(strcmp(file, state->file) == 0)
{
return state;
}
state = state->next;
}
state = (entA_state *)malloc(sizeof(entA_state));
if(state)
{
state->file = (char *)malloc((strlen(file) + 1) * sizeof(char));
state->filepath = (char *)malloc((strlen(filepath) + 1) * sizeof(char));
strcpy(state->file, file);
strcpy(state->filepath, filepath);
state->loaded = 0;
state->buffer = NULL;
state->next = NULL;
state->next = entA_firstState;
entA_firstState = state;
}
return state;
}
ENTITY *entA_create(STRING *file, VECTOR *pos, EVENT entAction)
{
STRING *filepath;
ENTITY *ent = NULL;
entA_state *state;
int initiatedLoading = 0;
filepath = str_create(work_dir);
str_cat(filepath, "\\");
str_cat(filepath, file);
WaitForSingleObject(entA_mutex, INFINITE);
state = entA_stateForFile(_chr(file), _chr(filepath));
if(state->loaded == 3)
{
// The file is already cached, so we can safely create the entity right away
ReleaseMutex(entA_mutex);
ptr_remove(filepath);
return ent_create(file, pos, entAction);
}
else if(state->loaded == 0)
{
// We have kicked of the loading, so its our responsibility to add the buffer later on
initiatedLoading = 1;
}
ReleaseMutex(entA_mutex);
int ready = 0;
while(ready == 0)
{
wait(1);
WaitForSingleObject(entA_mutex, INFINITE);
switch(state->loaded)
{
case 2:
{
if(initiatedLoading == 1)
{
add_buffer(state->file, state->buffer, state->size);
state->loaded = 3;
ready = 1;
}
}
break;
case 3:
{
ready = 1;
}
break;
case 200:
{
printf("Could not load file \"%s\"", state->file);
ReleaseMutex(entA_mutex);
ptr_remove(filepath);
return NULL;
}
break;
default:
break;
}
ReleaseMutex(entA_mutex);
}
ent = ent_create(file, pos, entAction);
ptr_remove(filepath);
return ent;
}
There are some error checkings left and I there is no way to purge the files (well they can be purged, but not recreated). Its trivial to add these things, so I let you do this. Here is a small test scrip which uses the models from the shadertest folder:
#include <acknex.h>
#include "async.c"
ENTITY *stone, *marine;
action rotate()
{
while(1)
{
my.pan += 12 * time_step;
my.tilt += 9 * time_step;
wait(1);
}
}
void main()
{
level_load(NULL);
wait(1);
entA_init(); // DON'T forget!
stone = entA_create("stones.mdl", vector(1024, 0, 0), NULL);
marine = entA_create("marine.mdl", vector(1024, 0, 0), rotate);
int i;
for(i=0; i<10; i++)
entA_create("box.mdl", vector(1024, -290 + (i * 120), -35), NULL);
}
Last edited by JustSid; 05/20/11 12:19.
Shitlord by trade and passion. Graphics programmer at Laminar Research. I write blog posts at feresignum.com
|
|
|
|