From 2b1e32bf3d74763a3b13c529dee3c6356fe9d9fa Mon Sep 17 00:00:00 2001 From: NY00123 Date: Fri, 1 May 2020 12:28:49 +0300 Subject: [PATCH] SW: Add the currently-unused interpso.* files, enabling interpolation of sector objects as whole groups of points and sprite angles. The following goals are intended to be achieved with this code: - Make it easy to let the user toggle sector object interpolation. - Interpolate the angles of sprites carried by sector objects. - Use the right amount of samples for interpolating a sector object, depending on the players' locations, as done in the checks within DoSector. Unfortunately, modifying DoSector itself to unconditionally call MoveSectorObjects(sop, synctics) technically changes the way sectors move (in the logical sense), and was found out to make a specifically constructed user map unbeatable. - Make it easy to disable interpolation of a whole sector object in case of a need. This is especially important if such an object is controlled by a player in multiplayer, mostly since this isn't compatible with the way player prediction is working. --- source/sw/src/interpso.cpp | 341 +++++++++++++++++++++++++++++++++++++ source/sw/src/interpso.h | 45 +++++ 2 files changed, 386 insertions(+) create mode 100644 source/sw/src/interpso.cpp create mode 100644 source/sw/src/interpso.h diff --git a/source/sw/src/interpso.cpp b/source/sw/src/interpso.cpp new file mode 100644 index 000000000..3ef340adc --- /dev/null +++ b/source/sw/src/interpso.cpp @@ -0,0 +1,341 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1997, 2005 - 3D Realms Entertainment + +This file is part of Shadow Warrior version 1.2 + +Shadow Warrior is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Original Source: 1997 - Frank Maddin and Jim Norwood +Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include "compat.h" +#include "pragmas.h" + +#include "game.h" +#include "interp.h" +#include "interpso.h" + +#define SO_MAXINTERPOLATIONS MAXINTERPOLATIONS + +static struct so_interp +{ + struct interp_data + { + void *curipos; + int32_t oldipos; + int32_t bakipos; + int32_t lastipos; + int32_t lastoldipos; + int32_t lastangdiff; + int32_t spriteofang; + } data[SO_MAXINTERPOLATIONS]; + + int32_t numinterpolations; + int32_t tic, lasttic; +} so_interpdata[MAX_SECTOR_OBJECTS]; + +static void so_setpointinterpolation(so_interp *interp, int32_t *posptr) +{ + int32_t i; + if (interp->numinterpolations >= SO_MAXINTERPOLATIONS) + return; + + for (i = 0; i < interp->numinterpolations; i++) + if (interp->data[i].curipos == posptr) + return; + + so_interp::interp_data *data = &interp->data[interp->numinterpolations++]; + + data->curipos = posptr; + data->oldipos = *posptr; + data->lastipos = *posptr; + data->lastoldipos = *posptr; + data->spriteofang = -1; +} + +static void so_setspriteanginterpolation(so_interp *interp, int16_t *posptr, int32_t spritenum) +{ + int32_t i; + if (interp->numinterpolations >= SO_MAXINTERPOLATIONS) + return; + + for (i = 0; i < interp->numinterpolations; i++) + if (interp->data[i].curipos == posptr) + return; + + so_interp::interp_data *data = &interp->data[interp->numinterpolations++]; + + data->curipos = posptr; + data->oldipos = *posptr; + data->lastipos = *posptr; + data->lastoldipos = *posptr; + data->lastangdiff = 0; + data->spriteofang = spritenum; +} + +// Covers points and angles altogether +static void so_stopdatainterpolation(so_interp *interp, void *posptr) +{ + int32_t i; + + for (i = 0; i < interp->numinterpolations; i++) + if (interp->data[i].curipos == posptr) + break; + + if (i == interp->numinterpolations) + return; + + interp->data[i] = interp->data[--(interp->numinterpolations)]; +} + +void so_addinterpolation(SECTOR_OBJECTp sop) +{ + SECTORp *sectp; + int32_t startwall, endwall; + int32_t i; + + so_interp *interp = &so_interpdata[sop - SectorObject]; + interp->numinterpolations = 0; + + for (sectp = sop->sectp; *sectp; sectp++) + { + startwall = (*sectp)->wallptr; + endwall = startwall + (*sectp)->wallnum - 1; + + for (i = startwall; i <= endwall; i++) + { + int32_t nextwall = wall[i].nextwall; + + so_setpointinterpolation(interp, &wall[i].x); + so_setpointinterpolation(interp, &wall[i].y); + + if (nextwall >= 0) + { + so_setpointinterpolation(interp, &wall[wall[nextwall].point2].x); + so_setpointinterpolation(interp, &wall[wall[nextwall].point2].y); + } + } + + so_setpointinterpolation(interp, &(*sectp)->ceilingz); + so_setpointinterpolation(interp, &(*sectp)->floorz); + } + + // interpolate midpoint, for aiming at a remote controlled SO + so_setpointinterpolation(interp, &sop->xmid); + so_setpointinterpolation(interp, &sop->ymid); + so_setpointinterpolation(interp, &sop->zmid); + + interp->tic = 0; + interp->lasttic = synctics; +} + +void so_setspriteinterpolation(SECTOR_OBJECTp sop, spritetype *sp) +{ + so_interp *interp = &so_interpdata[sop - SectorObject]; + + so_setpointinterpolation(interp, &sp->x); + so_setpointinterpolation(interp, &sp->y); + so_setpointinterpolation(interp, &sp->z); + so_setspriteanginterpolation(interp, &sp->ang, sp - sprite); +} + +void so_stopspriteinterpolation(SECTOR_OBJECTp sop, spritetype *sp) +{ + so_interp *interp = &so_interpdata[sop - SectorObject]; + + so_stopdatainterpolation(interp, &sp->x); + so_stopdatainterpolation(interp, &sp->y); + so_stopdatainterpolation(interp, &sp->z); + so_stopdatainterpolation(interp, &sp->ang); +} + +void so_setinterpolationtics(SECTOR_OBJECTp sop, int16_t locktics) +{ + so_interp *interp = &so_interpdata[sop - SectorObject]; + + interp->tic = 0; + interp->lasttic = locktics; +} + +void so_updateinterpolations(void) // Stick at beginning of domovethings +{ + int32_t i; + SECTOR_OBJECTp sop; + so_interp *interp; + so_interp::interp_data *data; + SWBOOL interpolating = gs.InterpolateSO && !CommEnabled; // If changing from menu + + for (sop = SectorObject, interp = so_interpdata; + sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++, interp++) + { + if (sop->xmid == INT32_MAX /*|| sop->xmid == MAXSO*/) + continue; + if (interp->tic < interp->lasttic) + interp->tic += synctics; + for (i = 0, data = interp->data; i < interp->numinterpolations; i++, data++) + { + if (data->spriteofang >= 0) + { + USERp u = User[data->spriteofang]; + if (u) + u->oangdiff = 0; + if (!interpolating) + data->lastangdiff = 0; + data->oldipos = *(int16_t *)(data->curipos); + } + else + data->oldipos = *(int32_t *)(data->curipos); + + if (!interpolating) + data->lastipos = data->lastoldipos = data->oldipos; + } + } +} + +// must call restore for every do interpolations +// make sure you don't exit +void so_dointerpolations(int32_t smoothratio) // Stick at beginning of drawscreen +{ + int32_t i, delta; + SECTOR_OBJECTp sop; + so_interp *interp; + so_interp::interp_data *data; + + // Set the bakipos values separately, in case a point is shared. + // Also set lastipos if there's been an actual change in a point. + for (sop = SectorObject, interp = so_interpdata; + sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++, interp++) + { + if (sop->xmid == INT32_MAX /*|| sop->xmid == MAXSO*/) + continue; + + for (i = 0; i < interp->numinterpolations; i++) + interp->data[i].bakipos = (interp->data[i].spriteofang >= 0) ? + *(int16_t *)(interp->data[i].curipos) : + *(int32_t *)(interp->data[i].curipos); + + if (interp->tic == 0) // Only if the SO has just moved + { + for (i = 0, data = interp->data; i < interp->numinterpolations; i++, data++) + { + data->lastipos = data->bakipos; + data->lastoldipos = data->oldipos; + if (data->spriteofang >= 0) + { + USERp u = User[data->spriteofang]; + data->lastangdiff = u ? u->oangdiff : 0; + } + } + } + } + + for (sop = SectorObject, interp = so_interpdata; + sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++, interp++) + { + if (sop->xmid == INT32_MAX /*|| sop->xmid == MAXSO*/) + continue; + + for (i = 0, data = interp->data; i < interp->numinterpolations; i++, data++) + { + int32_t ratio = smoothratio * synctics + 65536 * interp->tic; + ratio /= interp->lasttic; + ratio = (interp->tic == interp->lasttic) ? 65536 : ratio; + if (data->spriteofang >= 0) + *(int16_t *)(data->curipos) = NORM_ANGLE(data->lastoldipos + mulscale16(data->lastangdiff, ratio)); + else + { + delta = data->lastipos - data->lastoldipos; + *(int32_t *)(data->curipos) = data->lastoldipos + mulscale16(delta, ratio); + } + } + } +} + +void so_restoreinterpolations(void) // Stick at end of drawscreen +{ + int32_t i; + SECTOR_OBJECTp sop; + so_interp *interp; + so_interp::interp_data *data; + + for (sop = SectorObject, interp = so_interpdata; + sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++, interp++) + { + if (sop->xmid == INT32_MAX /*|| sop->xmid == MAXSO*/) + continue; + + for (i = 0, data = interp->data; i < interp->numinterpolations; i++, data++) + if (data->spriteofang >= 0) + *(int16_t *)(data->curipos) = data->bakipos; + else + *(int32_t *)(data->curipos) = data->bakipos; + } +} + +int SaveSymDataInfo(MFILE_WRITE fil, void *ptr); + +SWBOOL so_writeinterpolations(MFILE_WRITE fil) +{ + int32_t i; + SECTOR_OBJECTp sop; + const so_interp *interp; + SWBOOL saveisshot = FALSE; + + for (sop = SectorObject, interp = so_interpdata; + sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++, interp++) + { + const so_interp::interp_data *data = interp->data; + MWRITE(&interp->numinterpolations,sizeof(interp->numinterpolations),1,fil); + for (i = 0; i < interp->numinterpolations; i++, data++) + { + saveisshot |= SaveSymDataInfo(fil, data->curipos); + MWRITE(&data->oldipos,sizeof(data->oldipos),1,fil); + MWRITE(&data->spriteofang,sizeof(data->spriteofang),1,fil); + } + } + return saveisshot; +} + +int LoadSymDataInfo(MFILE_READ fil, void **ptr); + +SWBOOL so_readinterpolations(MFILE_READ fil) +{ + int32_t i; + SECTOR_OBJECTp sop; + so_interp *interp; + SWBOOL saveisshot = FALSE; + + for (sop = SectorObject, interp = so_interpdata; + sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++, interp++) + { + so_interp::interp_data *data = interp->data; + MREAD(&interp->numinterpolations,sizeof(interp->numinterpolations),1,fil); + for (i = 0; i < interp->numinterpolations; i++, data++) + { + saveisshot |= LoadSymDataInfo(fil, (void **)&data->curipos); + MREAD(&data->oldipos,sizeof(data->oldipos),1,fil); + MREAD(&data->spriteofang,sizeof(data->spriteofang),1,fil); + data->lastipos = data->lastoldipos = data->oldipos; + data->lastangdiff = 0; + } + interp->tic = 0; + interp->lasttic = synctics; + } + return saveisshot; +} diff --git a/source/sw/src/interpso.h b/source/sw/src/interpso.h new file mode 100644 index 000000000..a509782f8 --- /dev/null +++ b/source/sw/src/interpso.h @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1997, 2005 - 3D Realms Entertainment + +This file is part of Shadow Warrior version 1.2 + +Shadow Warrior is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Original Source: 1997 - Frank Maddin and Jim Norwood +Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#ifndef INTERPSO_H +#define INTERPSO_H + +#include "mfile.h" + +extern int32_t so_numinterpolations; + +void so_addinterpolation(SECTOR_OBJECTp sop); +void so_setspriteinterpolation(SECTOR_OBJECTp sop, spritetype *sp); +void so_stopspriteinterpolation(SECTOR_OBJECTp sop, spritetype *sp); +void so_setinterpolationangdiff(SECTOR_OBJECTp sop, int16_t angdiff); +void so_setinterpolationtics(SECTOR_OBJECTp sop, int16_t locktics); +void so_updateinterpolations(void); +void so_dointerpolations(int32_t smoothratio); +void so_restoreinterpolations(void); +SWBOOL so_writeinterpolations(MFILE_WRITE fil); +SWBOOL so_readinterpolations(MFILE_READ fil); + +#endif