// get copy of global state with an additional process // *pp_buf points to memory area of length *p_len to use for new state // *pp_proc is filled with the pointer to the new process // NULL is returned in case of error st_global_state_header * global_state_copy_new_process( st_global_state_header *p_glob, t_pid new_pid, uint8_t lvar_sz, char **pp_buf, unsigned long *p_buf_len, st_process_header **pp_proc ) // extern { size_t sz = nipsvm_state_size( p_glob ) // allocate + sizeof( st_process_header ) + lvar_sz; st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len ); if( p_glob_new == NULL ) return NULL; char *src = (char *)p_glob; char *dest = (char *)p_glob_new; unsigned int len = (char *)global_state_get_channels( p_glob ) - (char *)p_glob; // part to end of last process memcpy( dest, src, len ); p_glob_new->proc_cnt++; dest += len; src += len; sz -= len; *pp_proc = (st_process_header *)dest; // new process (*pp_proc)->pid = h2be_pid( new_pid ); (*pp_proc)->flags = 0; (*pp_proc)->lvar_sz = lvar_sz; (*pp_proc)->pc = h2be_pc( 0 ); dest += sizeof( st_process_header ); sz -= sizeof( st_process_header ); memset( dest, 0, lvar_sz ); dest += lvar_sz; sz -= lvar_sz; memcpy( dest, src, sz ); // rest of state return p_glob_new; }
// get copy of global state with resized local variables // *pp_buf points to memory area of length *p_len to use for new state st_global_state_header * global_state_copy_lvar_sz( st_global_state_header *p_glob, st_process_header *p_proc, uint8_t lvar_sz, char **pp_buf, unsigned long *p_buf_len ) // extern { size_t sz = nipsvm_state_size( p_glob ) - p_proc->lvar_sz + lvar_sz; // allocate st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len ); if( p_glob_new == NULL ) return NULL; char *src = (char *)p_glob; char *dest = (char *)p_glob_new; unsigned int len = (char *)p_proc - (char *)p_glob; // size before process st_process_header *p_proc_new = (st_process_header *)((char*)p_glob_new + len); // pointer to process in new state if( p_proc->flags & PROCESS_FLAGS_ACTIVE ) // size of process header len += sizeof( st_process_active_header ); else len += sizeof( st_process_header ); memcpy( dest, src, len ); // part before process and process header p_proc_new->lvar_sz = lvar_sz; dest += len; src += len; sz -= len; memset( dest, 0, lvar_sz ); // variables memcpy( dest, src, min( lvar_sz, p_proc->lvar_sz ) ); dest += lvar_sz; src += p_proc->lvar_sz; sz -= lvar_sz; memcpy( dest, src, sz ); // rest of state return p_glob_new; }
/* The real main loop of the Eruta engine. Most of the work happens in state.c, * and the main.rb script, though. */ int real_main(void) { Image * border = NULL; Image * sheet = NULL; Tileset * tileset = NULL; Tile * tile = NULL; State * state = NULL; Camera * camera = NULL; Tilepane * tilepane = NULL; Tilemap * map = NULL; Thing * actor = NULL; Tracker * tracker = NULL; Tracker * maptracker = NULL; Sprite * sprite = NULL; SpriteState * spritestate = NULL; AlpsShower shower; int actor_id = -1; int sprite_id = -1; int npc1_id = -1; int npc2_id = -1; React react; ALLEGRO_COLOR myblack = {0.0, 0.0, 0.0, 1.0}; state = state_alloc(); state_set(state); if((!(state)) || (!state_init(state, FALSE))) { perror(state_errmsg(state)); return 1; } alpsshower_init(&shower, state_camera(state), 100, 1.0, bevec(10.0, 10000.0)); /* Initializes the reactor, the game state is it's data. */ react_initempty(&react, state); react.keyboard_key_up = main_react_key_up; react.keyboard_key_down = main_react_key_down; puts_standard_path(ALLEGRO_EXENAME_PATH, "ALLEGRO_EXENAME_PATH:"); camera = state_camera(state); /* Finally initialize ruby and call the ruby startup function. */ rh_load_main(); callrb_on_start(); /* Main game loop, controlled by the State object. */ while(state_busy(state)) { Point spritenow = bevec(100, 120); react_poll(&react, state); alpsshower_update(&shower, state_frametime(state)); state_update(state); state_draw(state); /* alpsshower_draw(&shower, camera); */ state_flip_display(state); } state_done(state); state_free(state); return 0; }
nipsvm_state_t * nipsvm_state_copy (size_t sz, nipsvm_state_t *p_glob, char **pp_buf, unsigned long *p_buf_len) { nipsvm_state_t *p_glob_new = (nipsvm_state_t *)state_alloc (sz, pp_buf, p_buf_len); if( p_glob_new == NULL ) return NULL; memcpy (p_glob_new, p_glob, sz); // simply copy return p_glob_new; }
// generate initial state // *pp_buf points to memory area of length *p_len to use for new state // NULL is returned in case of error st_global_state_header * global_state_initial( char **pp_buf, unsigned long *p_buf_len ) // extern { st_global_state_header *p_glob = (st_global_state_header *)state_alloc( global_state_initial_size, pp_buf, p_buf_len ); if( p_glob == NULL ) return NULL; p_glob->gvar_sz = h2be_16( 0 ); // global header p_glob->proc_cnt = 1; p_glob->excl_pid = h2be_pid( 0 ); p_glob->monitor_pid = h2be_pid( 0 ); p_glob->chan_cnt = 0; st_process_header *p_proc = (st_process_header *)((char *)p_glob + sizeof( st_global_state_header )); // process header p_proc->pid = h2be_pid( 1 ); p_proc->flags = 0; p_proc->lvar_sz = 0; p_proc->pc = h2be_pc( 0 ); return p_glob; }
// get copy of global state with an additional channel // *pp_buf points to memory area of length *p_len to use for new state // the new channel is inserted at the right place according to its channel id // *pp_chan is filled with the pointer to the new process // NULL is returned in case of error st_global_state_header * global_state_copy_new_channel( st_global_state_header *p_glob, t_chid new_chid, uint8_t max_len, uint8_t type_len, uint8_t msg_len, char **pp_buf, unsigned long *p_buf_len, st_channel_header **pp_chan ) // extern { size_t len = nipsvm_state_size( p_glob ); char * ptr = global_state_get_channels( p_glob ); // find place to insert new channel int i; for( i = 0; i < (int)p_glob->chan_cnt; i++ ) { if( be2h_chid( ((st_channel_header *)ptr)->chid ) == new_chid ) // duplicate chid -> error return NULL; if( be2h_chid( ((st_channel_header *)ptr)->chid ) > new_chid ) // place found break; ptr += channel_size( (st_channel_header *)ptr ); } unsigned int len_before = ptr - (char *)p_glob; // get size of part before new channel unsigned int len_chan = sizeof( st_channel_header ) // size of channel + type_len + max( 1, max_len ) * msg_len; unsigned int sz = len + len_chan; st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len ); // allocate new state if( p_glob_new == NULL ) return NULL; char *src = (char *)p_glob; char *dest = (char *)p_glob_new; memcpy( dest, src, len_before ); // first part of old state p_glob_new->chan_cnt++; dest += len_before; src += len_before; sz -= len_before; *pp_chan = (st_channel_header *)dest; // new channel (*pp_chan)->chid = h2be_chid( new_chid ); (*pp_chan)->max_len = max_len; (*pp_chan)->cur_len = 0; (*pp_chan)->msg_len = msg_len; (*pp_chan)->type_len = type_len; dest += sizeof( st_channel_header ); sz -= sizeof( st_channel_header ); len_chan -= sizeof( st_channel_header ); memset( dest, 0, len_chan ); // types and content of new channel dest += len_chan; sz -= len_chan; memcpy( dest, src, sz ); // rest of state return p_glob_new; }
// get copy of global state with resized global variables // *pp_buf points to memory area of length *p_len to use for new state st_global_state_header * global_state_copy_gvar_sz( st_global_state_header *p_glob, uint16_t gvar_sz, char **pp_buf, unsigned long *p_buf_len ) // extern { unsigned int sz = nipsvm_state_size( p_glob ) - be2h_16( p_glob->gvar_sz ) + gvar_sz; // allocate st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len ); if( p_glob_new == NULL ) return NULL; char *src = (char *)p_glob; char *dest = (char *)p_glob_new; memcpy( dest, src, sizeof( st_global_state_header ) ); // header p_glob_new->gvar_sz = h2be_16( gvar_sz ); dest += sizeof( st_global_state_header ); src += sizeof( st_global_state_header ); sz -= sizeof( st_global_state_header ); memset( dest, 0, gvar_sz ); // variables memcpy( dest, src, min( gvar_sz, be2h_16( p_glob->gvar_sz ) ) ); dest += gvar_sz; src += be2h_16( p_glob->gvar_sz ); sz -= gvar_sz; memcpy( dest, src, sz ); // rest of state return p_glob_new; }
// get copy of global state with selected process activated // *pp_buf points to memory area of length *p_len to use for new state // *pp_proc is filled with the pointer to the activated process // NULL is returned in case of error st_global_state_header * global_state_copy_activate( st_global_state_header *p_glob, st_process_header *p_proc, uint8_t stack_max, t_flag_reg flag_reg, char **pp_buf, unsigned long *p_buf_len, st_process_active_header **pp_proc ) // extern { size_t sz = nipsvm_state_size( p_glob ) // allocate - sizeof( st_process_header ) + sizeof( st_process_active_header ) + stack_max * sizeof( t_val ); st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len ); if( p_glob_new == NULL ) return NULL; char *src = (char *)p_glob; char *dest = (char *)p_glob_new; unsigned int len = (char *)p_proc - (char *)p_glob; // part before process memcpy( dest, src, len ); dest += len; src += len; sz -= len; *pp_proc = (st_process_active_header *)dest; // return pointer to activated process memcpy( dest, src, sizeof( st_process_header ) ); // process header memset( ((st_process_active_header *)dest)->registers, 0, sizeof( ((st_process_active_header *)dest)->registers ) ); ((st_process_active_header *)dest)->flag_reg = flag_reg; ((st_process_active_header *)dest)->proc.flags |= PROCESS_FLAGS_ACTIVE; ((st_process_active_header *)dest)->stack_cur = 0; ((st_process_active_header *)dest)->stack_max = stack_max; dest += sizeof( st_process_active_header ); src += sizeof( st_process_header ); sz -= sizeof( st_process_active_header ); memcpy( dest, src, p_proc->lvar_sz ); // local variables dest += p_proc->lvar_sz; src += p_proc->lvar_sz; sz -= p_proc->lvar_sz; len = stack_max * sizeof( t_val ); // stack memset( dest, 0, len ); dest += len; sz -= len; memcpy( dest, src, sz ); // rest of state return p_glob_new; }