New Interpolation method for demos and a small hack to fix this Interpolation if duplicate object signatures appear (mostly)

This commit is contained in:
zicodxx 2010-01-07 00:01:36 +00:00
parent 2505f63f2b
commit 7653e8ee12
3 changed files with 84 additions and 251 deletions

View file

@ -1,5 +1,9 @@
D2X-Rebirth Changelog
20100107
--------
main/gamecntl.c, main/newdemo.c: New Interpolation method for demos and a small hack to fix this Interpolation if duplicate object signatures appear (mostly)
20091227
--------
main/newmenu.c: Make listboxes into windows

View file

@ -633,6 +633,7 @@ void HandleDemoKey(int key)
break;
case KEY_DEBUGGED + KEY_I:
Newdemo_do_interpolate = !Newdemo_do_interpolate;
HUD_init_message("Demo playback interpolation %s", Newdemo_do_interpolate?"ON":"OFF");
break;
case KEY_DEBUGGED + KEY_K: {
int how_many, c;

View file

@ -1,4 +1,3 @@
/* $Id: newdemo.c,v 1.1.1.1 2006/03/17 19:57:03 zicodxx Exp $ */
/*
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
@ -92,7 +91,6 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "editor/editor.h"
#endif
void DoJasonInterpolate (fix recorded_time);
extern int init_hoard_data();
extern void init_seismic_disturbances(void);
@ -159,8 +157,6 @@ ubyte DemoDoRight=0,DemoDoLeft=0;
#define NORMAL_PLAYBACK 0
#define SKIP_PLAYBACK 1
#define INTERPOLATE_PLAYBACK 2
#define INTERPOL_FACTOR (F1_0 + (F1_0/5))
#define DEMO_VERSION 15 // last D1 version was 13
#define DEMO_GAME_TYPE 3 // 1 was shareware, 2 registered
@ -181,7 +177,7 @@ int Newdemo_num_written;
int Newdemo_old_cockpit;
sbyte Newdemo_no_space;
sbyte Newdemo_at_eof;
sbyte Newdemo_do_interpolate = 1; // ZICO - I HATE not-interpolated playbacks...
sbyte Newdemo_do_interpolate = 1;
sbyte Newdemo_warning_given = 0;
sbyte Newdemo_cntrlcen_destroyed = 0;
static sbyte nd_bad_read;
@ -191,8 +187,6 @@ fix nd_playback_total;
fix nd_recorded_total;
fix nd_recorded_time;
sbyte playback_style;
sbyte First_time_playback=1;
fix JasonPlaybackTotal=0;
int Newdemo_show_percentage=1;
static int swap_endian = 0;
@ -1527,7 +1521,6 @@ int newdemo_read_demo_start(enum purpose_type purpose)
}
Boss_cloak_start_time=Boss_cloak_end_time=GameTime;
JasonPlaybackTotal=0;
#ifndef NETWORK
if (Newdemo_game_mode & GM_MULTI) {
nm_messagebox( NULL, 1, "Ok", "can't playback net game\nwith this version of code\n" );
@ -3002,161 +2995,90 @@ void newdemo_back_frames(int frames)
}
/*
* routine to interpolate the viewer position. the current position is
* stored in the Viewer object. Save this position, and read the next
* frame to get all objects read in. Calculate the delta playback and
* the delta recording frame times between the two frames, then intepolate
* the viewers position accordingly. nd_recorded_time is the time that it
* took the recording to render the frame that we are currently looking
* at.
*/
void interpolate_frame(fix d_play, fix d_recorded)
void DoZicoInterpolate (fix recorded_time)
{
int i, j, num_cur_objs;
fix factor;
object *cur_objs;
static fix delay_time=0;
int i = 0, j = 0;
object SavObj[MAX_OBJECTS];
int SavObjNum;
factor = fixdiv(d_play, d_recorded);
if (factor > F1_0)
factor = F1_0;
memset(&SavObj, 0, sizeof(object)*MAX_OBJECTS);
num_cur_objs = Highest_object_index;
cur_objs = (object *)d_malloc(sizeof(object) * (num_cur_objs + 1));
if (cur_objs == NULL) {
Int3();
if (NewdemoFrameCount < 2)
return;
}
for (i = 0; i <= num_cur_objs; i++)
memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
// Read in the next Frame and store the objects from it.
Newdemo_vcr_state = ND_STATE_PAUSED;
if (newdemo_read_frame_information(0) == -1) {
d_free(cur_objs);
if (newdemo_read_frame_information(0) == -1)
{
newdemo_stop_playback();
return;
}
Newdemo_vcr_state = ND_STATE_PLAYBACK;
for (i=0; i<=Highest_object_index; i++)
memcpy(&SavObj[i], &Objects[i], sizeof(object));
SavObjNum=Highest_object_index;
newdemo_back_frames(1);
for (i = 0; i <= num_cur_objs; i++) {
for (j = 0; j <= Highest_object_index; j++) {
if (cur_objs[i].signature == Objects[j].signature) {
sbyte render_type = cur_objs[i].render_type;
fix delta_x, delta_y, delta_z;
// Extract the angles from the object orientation matrix.
// Some of this code taken from ai_turn_towards_vector
// Don't do the interpolation on certain render types which don't use an orientation matrix
if (!((render_type == RT_LASER) || (render_type == RT_FIREBALL) || (render_type == RT_POWERUP))) {
vms_vector fvec1, fvec2, rvec1, rvec2;
fix mag1;
fvec1 = cur_objs[i].orient.fvec;
vm_vec_scale(&fvec1, F1_0-factor);
fvec2 = Objects[j].orient.fvec;
vm_vec_scale(&fvec2, factor);
vm_vec_add2(&fvec1, &fvec2);
mag1 = vm_vec_normalize_quick(&fvec1);
if (mag1 > F1_0/256) {
rvec1 = cur_objs[i].orient.rvec;
vm_vec_scale(&rvec1, F1_0-factor);
rvec2 = Objects[j].orient.rvec;
vm_vec_scale(&rvec2, factor);
vm_vec_add2(&rvec1, &rvec2);
vm_vec_normalize_quick(&rvec1); // Note: Doesn't matter if this is null, if null, vm_vector_2_matrix will just use fvec1
vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
}
//--old new way -- vms_vector fvec1, fvec2, rvec1, rvec2;
//--old new way --
//--old new way -- fvec1 = cur_objs[i].orient.fvec;
//--old new way -- vm_vec_scale(&fvec1, F1_0-factor);
//--old new way -- fvec2 = Objects[j].orient.fvec;
//--old new way -- vm_vec_scale(&fvec2, factor);
//--old new way -- vm_vec_add2(&fvec1, &fvec2);
//--old new way -- vm_vec_normalize_quick(&fvec1);
//--old new way --
//--old new way -- rvec1 = cur_objs[i].orient.rvec;
//--old new way -- vm_vec_scale(&rvec1, F1_0-factor);
//--old new way -- rvec2 = Objects[j].orient.rvec;
//--old new way -- vm_vec_scale(&rvec2, factor);
//--old new way -- vm_vec_add2(&rvec1, &rvec2);
//--old new way -- vm_vec_normalize_quick(&rvec1);
//--old new way --
//--old new way -- vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
// -- old fashioned way -- vm_extract_angles_matrix(&cur_angles, &(cur_objs[i].orient));
// -- old fashioned way -- vm_extract_angles_matrix(&dest_angles, &(Objects[j].orient));
// -- old fashioned way --
// -- old fashioned way -- delta_p = (dest_angles.p - cur_angles.p);
// -- old fashioned way -- delta_h = (dest_angles.h - cur_angles.h);
// -- old fashioned way -- delta_b = (dest_angles.b - cur_angles.b);
// -- old fashioned way --
// -- old fashioned way -- if (delta_p != 0) {
// -- old fashioned way -- if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0;
// -- old fashioned way -- if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0;
// -- old fashioned way -- delta_p = fixmul(delta_p, factor);
// -- old fashioned way -- cur_angles.p += delta_p;
// -- old fashioned way -- }
// -- old fashioned way -- if (delta_h != 0) {
// -- old fashioned way -- if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0;
// -- old fashioned way -- if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0;
// -- old fashioned way -- delta_h = fixmul(delta_h, factor);
// -- old fashioned way -- cur_angles.h += delta_h;
// -- old fashioned way -- }
// -- old fashioned way -- if (delta_b != 0) {
// -- old fashioned way -- if (delta_b > F1_0/2) delta_b = dest_angles.b - cur_angles.b - F1_0;
// -- old fashioned way -- if (delta_b < -F1_0/2) delta_b = dest_angles.b - cur_angles.b + F1_0;
// -- old fashioned way -- delta_b = fixmul(delta_b, factor);
// -- old fashioned way -- cur_angles.b += delta_b;
// -- old fashioned way -- }
}
// Interpolate the object position. This is just straight linear
// interpolation.
delta_x = Objects[j].pos.x - cur_objs[i].pos.x;
delta_y = Objects[j].pos.y - cur_objs[i].pos.y;
delta_z = Objects[j].pos.z - cur_objs[i].pos.z;
delta_x = fixmul(delta_x, factor);
delta_y = fixmul(delta_y, factor);
delta_z = fixmul(delta_z, factor);
cur_objs[i].pos.x += delta_x;
cur_objs[i].pos.y += delta_y;
cur_objs[i].pos.z += delta_z;
// -- old fashioned way --// stuff the new angles back into the object structure
// -- old fashioned way -- vm_angles_2_matrix(&(cur_objs[i].orient), &cur_angles);
}
// Do necessary steps to repeat a Demo-Frame if necessary
if (recorded_time > FrameTime)
{
if (delay_time <= 0)
{
delay_time += recorded_time;
}
else if (delay_time > 0)
{
newdemo_back_frames(1);
delay_time -= FrameTime;
}
}
// get back to original position in the demo file. Reread the current
// frame information again to reset all of the object stuff not covered
// with Highest_object_index and the object array (previously rendered
// objects, etc....)
if (!Newdemo_do_interpolate)
return;
newdemo_back_frames(1);
newdemo_back_frames(1);
if (newdemo_read_frame_information(0) == -1)
newdemo_stop_playback();
Newdemo_vcr_state = ND_STATE_PLAYBACK;
// Interpolate objects.
for (i = 0; i <= SavObjNum; i++)
{
for (j = 0; j <= Highest_object_index; j++)
{
if (SavObj[i].signature == Objects[j].signature)
{
vms_vector fvec1, fvec2, rvec1, rvec2;
fix mag1;
for (i = 0; i <= num_cur_objs; i++)
memcpy(&(Objects[i]), &(cur_objs[i]), sizeof(object));
Highest_object_index = num_cur_objs;
d_free(cur_objs);
/*
* HACK: Good 'ol Descent does not check for duplicate signatures when creating objects.
* So in case our two objects have a huge distance, we assume they are different.
* Interpolating would not make much sense in that case nevertheless.
*/
if (vm_vec_dist(&SavObj[i].pos, &Objects[j].pos) > (Objects[j].size*2))
continue;
vm_vec_avg(&Objects[j].pos, &SavObj[i].pos, &Objects[j].pos);
if (!((SavObj[i].render_type == RT_LASER) || (SavObj[i].render_type == RT_FIREBALL) || (SavObj[i].render_type == RT_POWERUP)))
{
fvec1 = SavObj[i].orient.fvec;
fvec2 = Objects[j].orient.fvec;
vm_vec_add2(&fvec1, &fvec2);
mag1 = vm_vec_normalize_quick(&fvec1);
if (mag1 > F1_0/256) {
rvec1 = SavObj[i].orient.rvec;
rvec2 = Objects[j].orient.rvec;
vm_vec_add2(&rvec1, &rvec2);
vm_vec_normalize_quick(&rvec1);
vm_vector_2_matrix(&Objects[j].orient, &fvec1, NULL, &rvec1);
}
}
}
}
}
}
void newdemo_playback_one_frame()
{
int frames_back, i, level;
static fix base_interpol_time = 0;
static fix d_recorded = 0;
for (i = 0; i < MAX_PLAYERS; i++)
if (Players[i].flags & PLAYER_FLAGS_CLOAKED)
@ -3168,9 +3090,6 @@ void newdemo_playback_one_frame()
if (Newdemo_vcr_state == ND_STATE_PAUSED) // render a frame or not
return;
if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
DoJasonInterpolate(nd_recorded_time);
Control_center_destroyed = 0;
Countdown_seconds_left = -1;
PALETTE_FLASH_SET(0,0,0); //clear flash
@ -3238,12 +3157,11 @@ void newdemo_playback_one_frame()
Newdemo_vcr_state = ND_STATE_PAUSED;
}
else {
// First, uptate the total playback time to date. Then we check to see
// if we need to change the playback style to interpolate frames or
// skip frames based on where the playback time is relative to the
// recorded time.
// if we need to change the playback style to skip frames.
// In the end, interpolate between current and next frame and repeat frames
// if FPS are higher than recorded FPS.
if (NewdemoFrameCount <= 0)
nd_playback_total = nd_recorded_total; // baseline total playback time
else
@ -3253,89 +3171,24 @@ void newdemo_playback_one_frame()
{
if (nd_playback_total > nd_recorded_total)
playback_style = SKIP_PLAYBACK;
//if ((nd_playback_total * INTERPOL_FACTOR) < nd_recorded_total) // no matte rhow we look at it: this does not make ANY sense!
if (nd_recorded_total > 0 && nd_recorded_time > 0)
{
playback_style = INTERPOLATE_PLAYBACK;
nd_playback_total = nd_recorded_total + FrameTime; // baseline playback time
base_interpol_time = nd_recorded_total;
d_recorded = nd_recorded_time; // baseline delta recorded
}
}
if ((playback_style == INTERPOLATE_PLAYBACK) && Newdemo_do_interpolate) {
fix d_play = 0;
if (nd_recorded_total - nd_playback_total < FrameTime) {
d_recorded = nd_recorded_total - nd_playback_total;
while (nd_recorded_total - nd_playback_total < FrameTime) {
object *cur_objs;
int i, j, num_objs, level;
num_objs = Highest_object_index;
cur_objs = (object *)d_malloc(sizeof(object) * (num_objs + 1));
if (cur_objs == NULL) {
Warning ("Couldn't get %d bytes for objects in interpolate playback\n", sizeof(object) * num_objs);
break;
}
for (i = 0; i <= num_objs; i++)
memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
level = Current_level_num;
if (newdemo_read_frame_information(0) == -1) {
d_free(cur_objs);
newdemo_stop_playback();
return;
}
if (level != Current_level_num) {
d_free(cur_objs);
if (newdemo_read_frame_information(0) == -1)
newdemo_stop_playback();
break;
}
// for each new object in the frame just read in, determine if there is
// a corresponding object that we have been interpolating. If so, then
// copy that interpolated object to the new Objects array so that the
// interpolated position and orientation can be preserved.
for (i = 0; i <= num_objs; i++) {
for (j = 0; j <= Highest_object_index; j++) {
if (cur_objs[i].signature == Objects[j].signature) {
memcpy(&(Objects[j].orient), &(cur_objs[i].orient), sizeof(vms_matrix));
memcpy(&(Objects[j].pos), &(cur_objs[i].pos), sizeof(vms_vector));
break;
}
}
}
d_free(cur_objs);
d_recorded += nd_recorded_time;
base_interpol_time = nd_playback_total - FrameTime;
}
}
d_play = nd_playback_total - base_interpol_time;
interpolate_frame(d_play, d_recorded);
if (newdemo_read_frame_information(0) == -1) {
newdemo_stop_playback();
return;
}
else {
if (newdemo_read_frame_information(0) == -1) {
newdemo_stop_playback();
return;
}
if (playback_style == SKIP_PLAYBACK) {
while (nd_playback_total > nd_recorded_total) {
if (newdemo_read_frame_information(0) == -1) {
newdemo_stop_playback();
return;
}
if (playback_style == SKIP_PLAYBACK) {
while (nd_playback_total > nd_recorded_total) {
if (newdemo_read_frame_information(0) == -1) {
newdemo_stop_playback();
return;
}
}
}
}
if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
DoZicoInterpolate(nd_recorded_time);
}
void newdemo_start_recording()
@ -3556,8 +3409,6 @@ void newdemo_start_playback(char * filename)
#ifdef NETWORK
change_playernum_to(0);
#endif
First_time_playback=1;
JasonPlaybackTotal=0;
if (filename)
strcat(filename2, filename);
@ -3814,26 +3665,3 @@ void nd_render_extras (ubyte which,object *obj)
}
}
void DoJasonInterpolate (fix recorded_time)
{
fix the_delay;
JasonPlaybackTotal+=FrameTime;
if (!First_time_playback)
{
the_delay=(recorded_time - FrameTime);
if (the_delay < f0_0)
{
while (JasonPlaybackTotal > nd_recorded_total)
if (newdemo_read_frame_information(0) == -1)
{
newdemo_stop_playback();
return;
}
}
}
First_time_playback=0;
}