/** * @brief This function is called to blit the next frame of an anim instance to the screen. * This is normally called by the anim_render_all() function. * * @param instance Pointer to animation instance * @param frametime Time elapsed since last call, in seconds */ int anim_show_next_frame(anim_instance *instance, float frametime) { int bitmap_id, bitmap_flags=0, new_frame_num, frame_diff=0, i, n_frames=0,frame_save; float percent_through, time; vertex image_vertex; int aabitmap = 0; int bpp = 16; Assert( instance != NULL ); instance->time_elapsed += frametime; // Advance to the next frame, if we determine enough time has elapsed. if(instance->direction == ANIM_DIRECT_FORWARD) n_frames = instance->stop_at - instance->start_at + 1; else if(instance->direction == ANIM_DIRECT_REVERSE) n_frames = instance->start_at - instance->stop_at + 1; time = n_frames / i2fl(instance->parent->fps); percent_through = instance->time_elapsed / time; if(instance->direction == ANIM_DIRECT_FORWARD) new_frame_num = instance->start_at - 1 + fl2i(percent_through * n_frames + 0.5f); else new_frame_num = instance->start_at - 1 - fl2i(percent_through * n_frames + 0.5f); frame_save = instance->frame_num; // If framerate independent, use the new_frame_num... unless instance->skip_frames is // FALSE, then only advance a maximum of one frame (this is needed since some big animations // should just play slower rather than taking the hit of decompressing multiple frames and // creating an even greater slowdown if (instance->framerate_independent) { if(instance->direction == ANIM_DIRECT_FORWARD){ if ( new_frame_num > instance->last_frame_num) { if ( instance->skip_frames ) instance->frame_num = new_frame_num; else instance->frame_num++; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if( new_frame_num < instance->last_frame_num) { if ( instance->skip_frames ) instance->frame_num = new_frame_num; else instance->frame_num--; } } } else { if(instance->direction == ANIM_DIRECT_FORWARD){ if ( new_frame_num > instance->last_frame_num) { instance->frame_num++; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if ( new_frame_num < instance->last_frame_num) { instance->frame_num--; } } } if(instance->direction == ANIM_DIRECT_FORWARD){ if ( instance->frame_num < instance->start_at ) { instance->frame_num = instance->start_at; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if ( instance->frame_num > instance->start_at ) { instance->frame_num = instance->start_at; } } if ( instance->stop_now == TRUE ) { return -1; } // If past the last frame, clamp to the last frame and then set the stop_now flag in the // anim instance. The next iteration, the animation will stop. if(instance->direction == ANIM_DIRECT_FORWARD){ if (instance->frame_num >= instance->stop_at ) { if (instance->looped) { // looped animations instance->frame_num = instance->stop_at; instance->time_elapsed = 0.0f; } else if(instance->ping_pong) { // pingponged animations instance->frame_num = instance->stop_at; anim_reverse_direction(instance); } else { // one-shot animations instance->frame_num = instance->stop_at; instance->last_frame_num = instance->frame_num; instance->stop_now = TRUE; } } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if (instance->frame_num <= instance->stop_at ) { if (instance->looped) { // looped animations instance->frame_num = instance->stop_at; instance->time_elapsed = 0.0f; } else if(instance->ping_pong) { // pingponged animations instance->frame_num = instance->stop_at; anim_reverse_direction(instance); } else { // one-shot animations instance->frame_num = instance->stop_at+1; instance->last_frame_num = instance->frame_num; instance->stop_now = TRUE; } } } if(instance->direction == ANIM_DIRECT_FORWARD){ if( instance->last_frame_num >= instance->start_at ) { frame_diff = instance->frame_num - instance->last_frame_num; } else { frame_diff = 1; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if( instance->last_frame_num <= instance->start_at ) { frame_diff = instance->last_frame_num - instance->frame_num; } else { frame_diff = 1; } } Assert(frame_diff >= 0); Assert( instance->frame_num >= 0 && instance->frame_num < instance->parent->total_frames ); // if the anim is paused, ignore all the above changes and still display this frame if(instance->paused || Anim_paused){ instance->frame_num = frame_save; instance->time_elapsed -= frametime; frame_diff = 0; } if (instance->parent->flags & ANF_XPARENT){ bitmap_flags = 0; } bpp = 16; if(instance->aa_color != NULL){ bitmap_flags |= BMP_AABITMAP; aabitmap = 1; bpp = 8; } if ( frame_diff > 0 ) { instance->last_frame_num = instance->frame_num; t1 = timer_get_fixed_seconds(); for ( i = 0; i < frame_diff; i++ ) { anim_check_for_palette_change(instance); // if we're playing backwards, every frame must be a keyframe and we set the data ptr here if(instance->direction == ANIM_DIRECT_REVERSE){ if ( anim_instance_is_streamed(instance) ) { instance->file_offset = instance->parent->file_offset + instance->parent->keys[instance->frame_num-1].offset; } else { instance->data = instance->parent->data + instance->parent->keys[instance->frame_num-1].offset; } } ubyte *temp = NULL; int temp_file_offset = -1; // if we're using bitmap polys BM_SELECT_TEX_FORMAT(); if ( anim_instance_is_streamed(instance) ) { if ( instance->xlate_pal ){ temp_file_offset = unpack_frame_from_file(instance, instance->frame, instance->parent->width*instance->parent->height, instance->parent->palette_translation, aabitmap, bpp); } else { temp_file_offset = unpack_frame_from_file(instance, instance->frame, instance->parent->width*instance->parent->height, NULL, aabitmap, bpp); } } else { if ( instance->xlate_pal ){ temp = unpack_frame(instance, instance->data, instance->frame, instance->parent->width*instance->parent->height, instance->parent->palette_translation, aabitmap, bpp); } else { temp = unpack_frame(instance, instance->data, instance->frame, instance->parent->width*instance->parent->height, NULL, aabitmap, bpp); } } // always go back to screen format BM_SELECT_SCREEN_FORMAT(); // see if we had an error during decode (corrupted anim stream) if ( (temp == NULL) && (temp_file_offset < 0) ) { mprintf(("ANI: Fatal ERROR at frame %i!! Aborting playback of \"%s\"...\n", instance->frame_num, instance->parent->name)); // return -1 to end all playing of this anim instanc return -1; } if(instance->direction == ANIM_DIRECT_FORWARD){ if ( anim_instance_is_streamed(instance) ) { instance->file_offset = temp_file_offset; } else { instance->data = temp; } } } t2 = timer_get_fixed_seconds(); } else { t2=t1=0; } // this only happens when the anim is being looped, we need to reset the last_frame_num if ( (instance->time_elapsed == 0) && (instance->looped) ) { instance->last_frame_num = -1; instance->frame_num = -1; instance->data = instance->parent->data; instance->file_offset = instance->parent->file_offset; instance->loop_count++; } t1 = timer_get_fixed_seconds(); if ( frame_diff == 0 && instance->last_bitmap != -1 ) { bitmap_id = instance->last_bitmap; } else { if ( instance->last_bitmap != -1 ){ bm_release(instance->last_bitmap); } bitmap_id = bm_create(bpp, instance->parent->width, instance->parent->height, instance->frame, bitmap_flags); } if ( bitmap_id == -1 ) { // anim has finsished playing, free the instance frame data anim_release_render_instance(instance); return -1; // NOTE: there is no need to free the instance, since it was pre-allocated as // part of the anim_free_list } else { gr_set_bitmap(bitmap_id); // determine x,y to display the bitmap at if ( instance->world_pos == NULL ) { int old_max_w_unscaled = gr_screen.max_w_unscaled; int old_max_h_unscaled = gr_screen.max_h_unscaled; int old_max_w_unscaled_zoomed = gr_screen.max_w_unscaled_zoomed; int old_max_h_unscaled_zoomed = gr_screen.max_h_unscaled_zoomed; gr_set_screen_scale(instance->base_w, instance->base_h); gr_set_clip(0, 0, instance->base_w, instance->base_h, GR_RESIZE_MENU); if ( instance->aa_color == NULL ) { gr_bitmap(instance->x, instance->y, GR_RESIZE_MENU_NO_OFFSET); } else { gr_set_color_fast( (color*)instance->aa_color ); gr_aabitmap(instance->x, instance->y, GR_RESIZE_MENU_NO_OFFSET); } gr_set_screen_scale(old_max_w_unscaled, old_max_h_unscaled, old_max_w_unscaled_zoomed, old_max_h_unscaled_zoomed); gr_reset_clip(); } else { g3_rotate_vertex(&image_vertex,instance->world_pos); Assert(instance->radius != 0.0f); //g3_draw_bitmap(&image_vertex, 0, instance->radius*1.5f, TMAP_FLAG_TEXTURED | TMAP_HTL_2D); material mat_params; material_set_unlit(&mat_params, bitmap_id, 1.0f, false, false); g3_render_rect_screen_aligned_2d(&mat_params, &image_vertex, 0, instance->radius*1.5f); } instance->last_bitmap = bitmap_id; } t2 = timer_get_fixed_seconds(); return 0; }
int gr_stub_bm_lock(char *filename, int handle, int bitmapnum, ubyte bpp, ubyte flags) { ubyte c_type = BM_TYPE_NONE; ubyte true_bpp; bitmap_entry *be = &bm_bitmaps[bitmapnum]; bitmap *bmp = &be->bm; true_bpp = 8; // don't do a bpp check here since it could be different in OGL - taylor if ( (bmp->data == 0) ) { Assert(be->ref_count == 1); if ( be->type != BM_TYPE_USER ) { if ( bmp->data == 0 ) { nprintf (("BmpMan","Loading %s for the first time.\n", be->filename)); } } if ( !Bm_paging ) { if ( be->type != BM_TYPE_USER ) { nprintf(( "Paging", "Loading %s (%dx%dx%d)\n", be->filename, bmp->w, bmp->h, true_bpp )); } } // select proper format if(flags & BMP_AABITMAP){ BM_SELECT_ALPHA_TEX_FORMAT(); } else if(flags & BMP_TEX_ANY){ BM_SELECT_TEX_FORMAT(); } else { BM_SELECT_SCREEN_FORMAT(); } // make sure we use the real graphic type for EFFs if ( be->type == BM_TYPE_EFF ) { c_type = be->info.ani.eff.type; } else { c_type = be->type; } switch ( c_type ) { case BM_TYPE_PCX: bm_lock_pcx( handle, bitmapnum, be, bmp, true_bpp, flags ); break; case BM_TYPE_ANI: bm_lock_ani( handle, bitmapnum, be, bmp, true_bpp, flags ); break; case BM_TYPE_TGA: bm_lock_tga( handle, bitmapnum, be, bmp, true_bpp, flags ); break; case BM_TYPE_JPG: bm_lock_jpg( handle, bitmapnum, be, bmp, bmp->true_bpp, flags ); break; case BM_TYPE_DDS: case BM_TYPE_DXT1: case BM_TYPE_DXT3: case BM_TYPE_DXT5: case BM_TYPE_CUBEMAP_DDS: case BM_TYPE_CUBEMAP_DXT1: case BM_TYPE_CUBEMAP_DXT3: case BM_TYPE_CUBEMAP_DXT5: bm_lock_dds( handle, bitmapnum, be, bmp, true_bpp, flags ); break; case BM_TYPE_USER: bm_lock_user( handle, bitmapnum, be, bmp, true_bpp, flags ); break; default: Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", c_type ); return -1; } // always go back to screen format BM_SELECT_SCREEN_FORMAT(); } // make sure we actually did something if ( !(bmp->data) ) { // crap, bail... return -1; } return 0; }
void generic_render_ani_stream(generic_anim *ga) { int i; int bpp = ANI_BPP_CHECK; if(ga->use_hud_color) bpp = 8; #ifdef TIMER int start_time = timer_get_fixed_seconds(); #endif if(ga->current_frame == ga->previous_frame) return; #ifdef TIMER mprintf(("=========================\n")); mprintf(("frame: %d\n", ga->current_frame)); #endif anim_check_for_palette_change(ga->ani.instance); // if we're using bitmap polys BM_SELECT_TEX_FORMAT(); if(ga->direction & GENERIC_ANIM_DIRECTION_BACKWARDS) { //grab the keyframe - every frame is a keyframe for ANI if(ga->ani.animation->flags & ANF_STREAMED) { ga->ani.instance->file_offset = ga->ani.animation->file_offset + ga->ani.animation->keys[ga->current_frame].offset; } else { ga->ani.instance->data = ga->ani.animation->data + ga->ani.animation->keys[ga->current_frame].offset; } if(ga->ani.animation->flags & ANF_STREAMED) { ga->ani.instance->file_offset = unpack_frame_from_file(ga->ani.instance, ga->buffer, ga->width * ga->height, (ga->ani.instance->xlate_pal) ? ga->ani.animation->palette_translation : NULL, (bpp==8)?1:0, bpp); } else { ga->ani.instance->data = unpack_frame(ga->ani.instance, ga->ani.instance->data, ga->buffer, ga->width * ga->height, (ga->ani.instance->xlate_pal) ? ga->ani.animation->palette_translation : NULL, (bpp==8)?1:0, bpp); } } else { //looping back if((ga->current_frame == 0) || (ga->current_frame < ga->previous_frame)) { //go back to keyframe if there is one if(ga->keyframe && (ga->current_frame > 0)) { if(ga->ani.animation->flags & ANF_STREAMED) { ga->ani.instance->file_offset = ga->ani.animation->file_offset + ga->keyoffset; } else { ga->ani.instance->data = ga->ani.animation->data + ga->keyoffset; } ga->previous_frame = ga->keyframe - 1; } //go back to the start else { ga->ani.instance->file_offset = ga->ani.animation->file_offset; ga->ani.instance->data = ga->ani.animation->data; ga->previous_frame = -1; } } #ifdef TIMER mprintf(("proc: %d\n", timer_get_fixed_seconds() - start_time)); mprintf(("previous frame: %d\n", ga->previous_frame)); #endif for(i = ga->previous_frame + 1; i <= ga->current_frame; i++) { if(ga->ani.animation->flags & ANF_STREAMED) { ga->ani.instance->file_offset = unpack_frame_from_file(ga->ani.instance, ga->buffer, ga->width * ga->height, (ga->ani.instance->xlate_pal) ? ga->ani.animation->palette_translation : NULL, (bpp==8)?1:0, bpp); } else { ga->ani.instance->data = unpack_frame(ga->ani.instance, ga->ani.instance->data, ga->buffer, ga->width * ga->height, (ga->ani.instance->xlate_pal) ? ga->ani.animation->palette_translation : NULL, (bpp==8)?1:0, bpp); } } } // always go back to screen format BM_SELECT_SCREEN_FORMAT(); //we need to use this because performance is worse if we flush the gfx card buffer gr_update_texture(ga->bitmap_id, bpp, ga->buffer, ga->width, ga->height); //in case we want to check that the frame is actually changing //mprintf(("frame crc = %08X\n", cf_add_chksum_long(0, ga->buffer, ga->width * ga->height * (bpp >> 3)))); ga->ani.instance->last_bitmap = ga->bitmap_id; #ifdef TIMER mprintf(("end: %d\n", timer_get_fixed_seconds() - start_time)); mprintf(("=========================\n")); #endif }