dxx-rebirth/similar/main/morph.cpp
Kp 9d0c6f59a5 Remove always-zero piggy_page_flushed
Descent for DOS supported paging content on demand.  Rebirth has no
support for paging content out, but retained piggy_page_flushed
to track whether anything had been paged out.  Commit 3c20c24 ("Disable
piggy_bitmap_page_out_all") removed the last site that could set
piggy_bitmap_page_out_all to a non-zero value.  All remaining code
either tests it for non-zero or sets it to zero.

Remove the statements that set it to zero.
Remove assertions that the value is zero.
Remove conditional blocks that execute only when it is non-zero.
2016-05-22 17:49:30 +00:00

427 lines
9.7 KiB
C++

/*
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING.txt.
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below.
* See COPYING.txt for license details.
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
*/
/*
*
* Morphing code
*
*/
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "texmap.h"
#include "dxxerror.h"
#include "inferno.h"
#include "morph.h"
#include "polyobj.h"
#include "game.h"
#include "lighting.h"
#include "newdemo.h"
#include "piggy.h"
#include "bm.h"
#include "interp.h"
#include "compiler-range_for.h"
#include "partial_range.h"
using std::max;
array<morph_data, MAX_MORPH_OBJECTS> morph_objects;
//returns ptr to data for this object, or NULL if none
morph_data *find_morph_data(const vobjptr_t obj)
{
if (Newdemo_state == ND_STATE_PLAYBACK) {
morph_objects[0].obj = obj;
return &morph_objects[0];
}
range_for (auto &i, morph_objects)
if (i.obj == obj)
return &i;
return NULL;
}
static void assign_max(fix &a, const fix &b)
{
a = std::max(a, b);
}
static void assign_min(fix &a, const fix &b)
{
a = std::min(a, b);
}
template <fix vms_vector::*p>
static void update_bounds(vms_vector &minv, vms_vector &maxv, const vms_vector *vp)
{
auto &mx = maxv.*p;
assign_max(mx, vp->*p);
auto &mn = minv.*p;
assign_min(mn, vp->*p);
}
//takes pm, fills in min & max
static void find_min_max(polymodel *pm,int submodel_num,vms_vector &minv,vms_vector &maxv)
{
ushort nverts;
ushort *data,type;
data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]];
type = *data++;
Assert(type == 7 || type == 1);
nverts = *data++;
if (type==7)
data+=2; //skip start & pad
auto vp = reinterpret_cast<const vms_vector *>(data);
minv = maxv = *vp++;
nverts--;
while (nverts--) {
update_bounds<&vms_vector::x>(minv, maxv, vp);
update_bounds<&vms_vector::y>(minv, maxv, vp);
update_bounds<&vms_vector::z>(minv, maxv, vp);
vp++;
}
}
#define MORPH_RATE (f1_0*3)
fix morph_rate = MORPH_RATE;
static void init_points(polymodel *pm,const vms_vector *box_size,int submodel_num,morph_data *md)
{
ushort nverts;
ushort *data,type;
int i;
data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]];
type = *data++;
Assert(type == 7 || type == 1);
nverts = *data++;
md->n_morphing_points[submodel_num] = 0;
if (type==7) {
i = *data++; //get start point number
data++; //skip pad
}
else
i = 0; //start at zero
Assert(i+nverts < MAX_VECS);
md->submodel_startpoints[submodel_num] = i;
auto vp = reinterpret_cast<const vms_vector *>(data);
while (nverts--) {
fix k,dist;
if (box_size) {
fix t;
k = 0x7fffffff;
if (vp->x && f2i(box_size->x)<abs(vp->x)/2 && (t = fixdiv(box_size->x,abs(vp->x))) < k) k=t;
if (vp->y && f2i(box_size->y)<abs(vp->y)/2 && (t = fixdiv(box_size->y,abs(vp->y))) < k) k=t;
if (vp->z && f2i(box_size->z)<abs(vp->z)/2 && (t = fixdiv(box_size->z,abs(vp->z))) < k) k=t;
if (k==0x7fffffff) k=0;
}
else
k=0;
vm_vec_copy_scale(md->morph_vecs[i],*vp,k);
dist = vm_vec_normalized_dir_quick(md->morph_deltas[i],*vp,md->morph_vecs[i]);
md->morph_times[i] = fixdiv(dist,morph_rate);
if (md->morph_times[i] != 0)
md->n_morphing_points[submodel_num]++;
vm_vec_scale(md->morph_deltas[i],morph_rate);
vp++; i++;
}
}
static void update_points(polymodel *pm,int submodel_num,morph_data *md)
{
ushort nverts;
ushort *data,type;
int i;
data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]];
type = *data++;
Assert(type == 7 || type == 1);
nverts = *data++;
if (type==7) {
i = *data++; //get start point number
data++; //skip pad
}
else
i = 0; //start at zero
auto vp = reinterpret_cast<const vms_vector *>(data);
while (nverts--) {
if (md->morph_times[i]) //not done yet
{
if ((md->morph_times[i] -= FrameTime) <= 0) {
md->morph_vecs[i] = *vp;
md->morph_times[i] = 0;
md->n_morphing_points[submodel_num]--;
}
else
vm_vec_scale_add2(md->morph_vecs[i],md->morph_deltas[i],FrameTime);
}
vp++; i++;
}
}
//process the morphing object for one frame
void do_morph_frame(const vobjptr_t obj)
{
polymodel *pm;
morph_data *md;
md = find_morph_data(obj);
if (md == NULL) { //maybe loaded half-morphed from disk
obj->flags |= OF_SHOULD_BE_DEAD; //..so kill it
return;
}
pm = &Polygon_models[md->obj->rtype.pobj_info.model_num];
for (uint_fast32_t i = 0; i != pm->n_models; ++i)
if (md->submodel_active[i]==1) {
update_points(pm,i,md);
if (md->n_morphing_points[i] == 0) { //maybe start submodel
md->submodel_active[i] = 2; //not animating, just visible
md->n_submodels_active--; //this one done animating
for (uint_fast32_t t = 0; t != pm->n_models; ++t)
if (pm->submodel_parents[t] == i) { //start this one
init_points(pm,nullptr,t,md);
md->n_submodels_active++;
md->submodel_active[t] = 1;
}
}
}
if (!md->n_submodels_active) { //done morphing!
md->obj->control_type = md->morph_save_control_type;
md->obj->movement_type = md->morph_save_movement_type;
md->obj->render_type = RT_POLYOBJ;
md->obj->mtype.phys_info = md->morph_save_phys_info;
md->obj = NULL;
}
}
static const vms_vector morph_rotvel{0x4000,0x2000,0x1000};
void init_morphs()
{
range_for (auto &i, morph_objects)
i.obj = nullptr;
}
//make the object morph
void morph_start(const vobjptr_t obj)
{
polymodel *pm;
vms_vector pmmin,pmmax;
vms_vector box_size;
int i;
morph_data *md;
for (i=0;i<MAX_MORPH_OBJECTS;i++)
if (morph_objects[i].obj == NULL || morph_objects[i].obj->type==OBJ_NONE || morph_objects[i].obj->signature!=morph_objects[i].Morph_sig)
break;
if (i==MAX_MORPH_OBJECTS) //no free slots
return;
md = &morph_objects[i];
Assert(obj->render_type == RT_POLYOBJ);
md->obj = obj;
md->Morph_sig = obj->signature;
md->morph_save_control_type = obj->control_type;
md->morph_save_movement_type = obj->movement_type;
md->morph_save_phys_info = obj->mtype.phys_info;
Assert(obj->control_type == CT_AI); //morph objects are also AI objects
obj->control_type = CT_MORPH;
obj->render_type = RT_MORPH;
obj->movement_type = MT_PHYSICS; //RT_NONE;
obj->mtype.phys_info.rotvel = morph_rotvel;
pm = &Polygon_models[obj->rtype.pobj_info.model_num];
find_min_max(pm,0,pmmin,pmmax);
box_size.x = max(-pmmin.x,pmmax.x) / 2;
box_size.y = max(-pmmin.y,pmmax.y) / 2;
box_size.z = max(-pmmin.z,pmmax.z) / 2;
//clear all points
md->morph_times = {};
//clear all parts
md->submodel_active = {};
md->submodel_active[0] = 1; //1 means visible & animating
md->n_submodels_active = 1;
//now, project points onto surface of box
init_points(pm,&box_size,0,md);
}
static void draw_model(polygon_model_points &robot_points, polymodel *pm, int submodel_num, const submodel_angles anim_angles, g3s_lrgb light, morph_data *md)
{
int mn;
int facing;
int sort_list[MAX_SUBMODELS],sort_n;
//first, sort the submodels
sort_list[0] = submodel_num;
sort_n = 1;
for (uint_fast32_t i = 0; i != pm->n_models; ++i)
if (md->submodel_active[i] && pm->submodel_parents[i]==submodel_num) {
facing = g3_check_normal_facing(pm->submodel_pnts[i],pm->submodel_norms[i]);
if (!facing)
sort_list[sort_n++] = i;
else { //put at start
int t;
for (t=sort_n;t>0;t--)
sort_list[t] = sort_list[t-1];
sort_list[0] = i;
sort_n++;
}
}
//now draw everything
for (uint_fast32_t i=0;i<sort_n;i++) {
mn = sort_list[i];
if (mn == submodel_num) {
array<bitmap_index, MAX_POLYOBJ_TEXTURES> texture_list_index;
for (unsigned i = 0; i < pm->n_textures; ++i)
{
texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]];
texture_list[i] = &GameBitmaps[ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]].index];
}
// Make sure the textures for this object are paged in...
range_for (auto &j, partial_const_range(texture_list_index, pm->n_textures))
PIGGY_PAGE_IN(j);
// Hmmm... cache got flushed in the middle of paging all these in,
// so we need to reread them all in.
// Make sure that they can all fit in memory.
g3_draw_morphing_model(&pm->model_data[pm->submodel_ptrs[submodel_num]],&texture_list[0],anim_angles,light,&md->morph_vecs[md->submodel_startpoints[submodel_num]], robot_points);
}
else {
const auto &&orient = vm_angles_2_matrix(anim_angles[mn]);
g3_start_instance_matrix(pm->submodel_offsets[mn],&orient);
draw_model(robot_points,pm,mn,anim_angles,light,md);
g3_done_instance();
}
}
}
void draw_morph_object(const vobjptridx_t obj)
{
// int save_light;
polymodel *po;
g3s_lrgb light;
morph_data *md;
md = find_morph_data(obj);
Assert(md != NULL);
Assert(obj->rtype.pobj_info.model_num < N_polygon_models);
po=&Polygon_models[obj->rtype.pobj_info.model_num];
light = compute_object_light(obj,nullptr);
g3_start_instance_matrix(obj->pos,&obj->orient);
polygon_model_points robot_points;
draw_model(robot_points,po,0,obj->rtype.pobj_info.anim_angles,light,md);
g3_done_instance();
if (Newdemo_state == ND_STATE_RECORDING)
newdemo_record_morph_frame(md);
}