674a9213f8
GCC std::array uses std::size_t for its size_type. On Linux/amd64, `std::size_t` is `unsigned long`. On Win32, `std::size_t` is `unsigned int`. This provokes format string warnings because an unsigned int is passed where the format string declares an unsigned long. On Win32, `unsigned int` and `unsigned long` are the same size, so `unsigned long` could have been used to avoid this problem by maintaining consistency with Linux, but it was not. This may have been an attempt to achieve bug compatibility with Microsoft's types. Add a workaround by defining a macro DXX_PRI_size_type in the style of inttypes.h PRI* macros. Use an SConf test to determine the correct value by inspecting which compilation runs succeed. Currently, Linux needs "l", Win32 needs "", and Win64 needs "I64".
754 lines
22 KiB
C++
754 lines
22 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-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* Bitmap and palette loading functions.
|
|
*
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "pstypes.h"
|
|
#include "inferno.h"
|
|
#include "gr.h"
|
|
#include "bm.h"
|
|
#include "u_mem.h"
|
|
#include "dxxerror.h"
|
|
#include "object.h"
|
|
#include "vclip.h"
|
|
#include "effects.h"
|
|
#include "polyobj.h"
|
|
#include "wall.h"
|
|
#include "textures.h"
|
|
#include "game.h"
|
|
#include "multi.h"
|
|
#include "iff.h"
|
|
#include "powerup.h"
|
|
#include "sounds.h"
|
|
#include "piggy.h"
|
|
#include "aistruct.h"
|
|
#include "robot.h"
|
|
#include "weapon.h"
|
|
#include "gauges.h"
|
|
#include "player.h"
|
|
#include "endlevel.h"
|
|
#include "cntrlcen.h"
|
|
#include "makesig.h"
|
|
#include "interp.h"
|
|
#include "console.h"
|
|
#include "rle.h"
|
|
#include "physfsx.h"
|
|
#include "internal.h"
|
|
#include "strutil.h"
|
|
|
|
#ifdef EDITOR
|
|
#include "editor/texpage.h"
|
|
#endif
|
|
|
|
#include "compiler-range_for.h"
|
|
#include "compiler-make_unique.h"
|
|
#include "partial_range.h"
|
|
|
|
array<ubyte, MAX_SOUNDS> Sounds, AltSounds;
|
|
|
|
unsigned NumTextures;
|
|
|
|
#ifdef EDITOR
|
|
int Num_object_subtypes = 1;
|
|
#endif
|
|
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
int Num_total_object_types;
|
|
|
|
sbyte ObjType[MAX_OBJTYPE];
|
|
sbyte ObjId[MAX_OBJTYPE];
|
|
fix ObjStrength[MAX_OBJTYPE];
|
|
#elif defined(DXX_BUILD_DESCENT_II)
|
|
//the polygon model number to use for the marker
|
|
int Marker_model_num = -1;
|
|
unsigned N_ObjBitmaps;
|
|
static void bm_free_extra_objbitmaps();
|
|
#endif
|
|
|
|
namespace dsx {
|
|
Textures_array Textures; // All textures.
|
|
//for each model, a model number for dying & dead variants, or -1 if none
|
|
array<int, MAX_POLYGON_MODELS> Dying_modelnums, Dead_modelnums;
|
|
TmapInfo_array TmapInfo;
|
|
}
|
|
|
|
//right now there's only one player ship, but we can have another by
|
|
//adding an array and setting the pointer to the active ship.
|
|
player_ship only_player_ship;
|
|
|
|
//----------------- Miscellaneous bitmap pointers ---------------
|
|
unsigned Num_cockpits;
|
|
array<bitmap_index, N_COCKPIT_BITMAPS> cockpit_bitmap;
|
|
|
|
//---------------- Variables for wall textures ------------------
|
|
unsigned Num_tmaps;
|
|
|
|
//---------------- Variables for object textures ----------------
|
|
|
|
int First_multi_bitmap_num=-1;
|
|
|
|
array<bitmap_index, MAX_OBJ_BITMAPS> ObjBitmaps;
|
|
array<ushort, MAX_OBJ_BITMAPS> ObjBitmapPtrs; // These point back into ObjBitmaps, since some are used twice.
|
|
|
|
void gamedata_close()
|
|
{
|
|
free_polygon_models();
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
|
bm_free_extra_objbitmaps();
|
|
#endif
|
|
free_endlevel_data();
|
|
rle_cache_close();
|
|
piggy_close();
|
|
}
|
|
|
|
/*
|
|
* reads n tmap_info structs from a PHYSFS_File
|
|
*/
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
static void tmap_info_read(tmap_info &ti, PHYSFS_File *fp)
|
|
{
|
|
PHYSFS_read(fp, ti.filename, 13, 1);
|
|
ti.flags = PHYSFSX_readByte(fp);
|
|
ti.lighting = PHYSFSX_readFix(fp);
|
|
ti.damage = PHYSFSX_readFix(fp);
|
|
ti.eclip_num = PHYSFSX_readInt(fp);
|
|
}
|
|
|
|
//-----------------------------------------------------------------
|
|
// Initializes game properties data (including texture caching system) and sound data.
|
|
int gamedata_init()
|
|
{
|
|
int retval;
|
|
|
|
init_polygon_models();
|
|
init_endlevel();//adb: added, is also in bm_init_use_tbl (Chris: *Was* in bm_init_use_tbl)
|
|
retval = properties_init(); // This calls properties_read_cmp if appropriate
|
|
if (retval)
|
|
gamedata_read_tbl(retval == PIGGY_PC_SHAREWARE);
|
|
|
|
piggy_read_sounds(retval == PIGGY_PC_SHAREWARE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Read compiled properties data from descent.pig
|
|
void properties_read_cmp(PHYSFS_File * fp)
|
|
{
|
|
// bitmap_index is a short
|
|
|
|
NumTextures = PHYSFSX_readInt(fp);
|
|
bitmap_index_read_n(fp, Textures);
|
|
range_for (tmap_info &ti, TmapInfo)
|
|
tmap_info_read(ti, fp);
|
|
|
|
PHYSFS_read(fp, Sounds, sizeof(Sounds[0]), Sounds.size());
|
|
PHYSFS_read(fp, AltSounds, sizeof(AltSounds[0]), AltSounds.size());
|
|
|
|
Num_vclips = PHYSFSX_readInt(fp);
|
|
range_for (vclip &vc, Vclip)
|
|
vclip_read(fp, vc);
|
|
|
|
Num_effects = PHYSFSX_readInt(fp);
|
|
range_for (eclip &ec, Effects)
|
|
eclip_read(fp, ec);
|
|
|
|
Num_wall_anims = PHYSFSX_readInt(fp);
|
|
range_for (auto &w, WallAnims)
|
|
wclip_read(fp, w);
|
|
|
|
N_robot_types = PHYSFSX_readInt(fp);
|
|
range_for (auto &r, Robot_info)
|
|
robot_info_read(fp, r);
|
|
|
|
N_robot_joints = PHYSFSX_readInt(fp);
|
|
range_for (auto &r, Robot_joints)
|
|
jointpos_read(fp, r);
|
|
|
|
N_weapon_types = PHYSFSX_readInt(fp);
|
|
weapon_info_read_n(Weapon_info, MAX_WEAPON_TYPES, fp, 0);
|
|
|
|
N_powerup_types = PHYSFSX_readInt(fp);
|
|
range_for (auto &p, Powerup_info)
|
|
powerup_type_info_read(fp, p);
|
|
|
|
N_polygon_models = PHYSFSX_readInt(fp);
|
|
{
|
|
const auto &&r = partial_range(Polygon_models, N_polygon_models);
|
|
range_for (auto &p, r)
|
|
polymodel_read(&p, fp);
|
|
|
|
range_for (auto &p, r)
|
|
polygon_model_data_read(&p, fp);
|
|
}
|
|
|
|
bitmap_index_read_n(fp, partial_range(Gauges, MAX_GAUGE_BMS));
|
|
|
|
range_for (auto &i, Dying_modelnums)
|
|
i = PHYSFSX_readInt(fp);
|
|
range_for (auto &i, Dead_modelnums)
|
|
i = PHYSFSX_readInt(fp);
|
|
|
|
bitmap_index_read_n(fp, ObjBitmaps);
|
|
range_for (auto &i, ObjBitmapPtrs)
|
|
i = PHYSFSX_readShort(fp);
|
|
|
|
player_ship_read(&only_player_ship, fp);
|
|
|
|
Num_cockpits = PHYSFSX_readInt(fp);
|
|
bitmap_index_read_n(fp, cockpit_bitmap);
|
|
|
|
PHYSFS_read(fp, Sounds, sizeof(Sounds[0]), Sounds.size());
|
|
PHYSFS_read(fp, AltSounds, sizeof(AltSounds[0]), AltSounds.size());
|
|
|
|
Num_total_object_types = PHYSFSX_readInt(fp);
|
|
PHYSFS_read( fp, ObjType, sizeof(ubyte), MAX_OBJTYPE );
|
|
PHYSFS_read( fp, ObjId, sizeof(ubyte), MAX_OBJTYPE );
|
|
range_for (auto &i, ObjStrength)
|
|
i = PHYSFSX_readFix(fp);
|
|
|
|
First_multi_bitmap_num = PHYSFSX_readInt(fp);
|
|
Reactors[0].n_guns = PHYSFSX_readInt(fp);
|
|
|
|
range_for (auto &i, Reactors[0].gun_points)
|
|
PHYSFSX_readVector(fp, i);
|
|
range_for (auto &i, Reactors[0].gun_dirs)
|
|
PHYSFSX_readVector(fp, i);
|
|
|
|
exit_modelnum = PHYSFSX_readInt(fp);
|
|
destroyed_exit_modelnum = PHYSFSX_readInt(fp);
|
|
|
|
#ifdef EDITOR
|
|
//Build tmaplist
|
|
auto &&effect_range = partial_const_range(Effects, Num_effects);
|
|
Num_tmaps = TextureEffects + std::count_if(effect_range.begin(), effect_range.end(), [](const eclip &e) { return e.changing_wall_texture >= 0; });
|
|
#endif
|
|
}
|
|
#elif defined(DXX_BUILD_DESCENT_II)
|
|
static void tmap_info_read(tmap_info &ti, PHYSFS_File *fp)
|
|
{
|
|
ti.flags = PHYSFSX_readByte(fp);
|
|
PHYSFSX_readByte(fp);
|
|
PHYSFSX_readByte(fp);
|
|
PHYSFSX_readByte(fp);
|
|
ti.lighting = PHYSFSX_readFix(fp);
|
|
ti.damage = PHYSFSX_readFix(fp);
|
|
ti.eclip_num = PHYSFSX_readShort(fp);
|
|
ti.destroyed = PHYSFSX_readShort(fp);
|
|
ti.slide_u = PHYSFSX_readShort(fp);
|
|
ti.slide_v = PHYSFSX_readShort(fp);
|
|
}
|
|
|
|
//-----------------------------------------------------------------
|
|
// Initializes game properties data (including texture caching system) and sound data.
|
|
int gamedata_init()
|
|
{
|
|
init_polygon_models();
|
|
init_endlevel();
|
|
|
|
#ifdef EDITOR
|
|
// The pc_shareware argument is currently unused for Descent 2,
|
|
// but *may* be useful for loading Descent 1 Shareware texture properties.
|
|
if (!gamedata_read_tbl(0))
|
|
#endif
|
|
if (!properties_init()) // This calls properties_read_cmp
|
|
Error("Cannot open ham file\n");
|
|
|
|
piggy_read_sounds();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void bm_read_all(PHYSFS_File * fp)
|
|
{
|
|
unsigned t;
|
|
|
|
NumTextures = PHYSFSX_readInt(fp);
|
|
bitmap_index_read_n(fp, partial_range(Textures, NumTextures));
|
|
range_for (tmap_info &ti, partial_range(TmapInfo, NumTextures))
|
|
tmap_info_read(ti, fp);
|
|
|
|
t = PHYSFSX_readInt(fp);
|
|
PHYSFS_read( fp, Sounds, sizeof(ubyte), t );
|
|
PHYSFS_read( fp, AltSounds, sizeof(ubyte), t );
|
|
|
|
Num_vclips = PHYSFSX_readInt(fp);
|
|
range_for (vclip &vc, partial_range(Vclip, Num_vclips))
|
|
vclip_read(fp, vc);
|
|
|
|
Num_effects = PHYSFSX_readInt(fp);
|
|
range_for (eclip &ec, partial_range(Effects, Num_effects))
|
|
eclip_read(fp, ec);
|
|
|
|
Num_wall_anims = PHYSFSX_readInt(fp);
|
|
range_for (auto &w, partial_range(WallAnims, Num_wall_anims))
|
|
wclip_read(fp, w);
|
|
|
|
N_robot_types = PHYSFSX_readInt(fp);
|
|
range_for (auto &r, partial_range(Robot_info, N_robot_types))
|
|
robot_info_read(fp, r);
|
|
|
|
N_robot_joints = PHYSFSX_readInt(fp);
|
|
range_for (auto &r, partial_range(Robot_joints, N_robot_joints))
|
|
jointpos_read(fp, r);
|
|
|
|
N_weapon_types = PHYSFSX_readInt(fp);
|
|
weapon_info_read_n(Weapon_info, N_weapon_types, fp, Piggy_hamfile_version);
|
|
|
|
N_powerup_types = PHYSFSX_readInt(fp);
|
|
range_for (auto &p, partial_range(Powerup_info, N_powerup_types))
|
|
powerup_type_info_read(fp, p);
|
|
|
|
N_polygon_models = PHYSFSX_readInt(fp);
|
|
{
|
|
const auto &&r = partial_range(Polygon_models, N_polygon_models);
|
|
range_for (auto &p, r)
|
|
polymodel_read(&p, fp);
|
|
|
|
range_for (auto &p, r)
|
|
polygon_model_data_read(&p, fp);
|
|
}
|
|
|
|
range_for (auto &i, partial_range(Dying_modelnums, N_polygon_models))
|
|
i = PHYSFSX_readInt(fp);
|
|
range_for (auto &i, partial_range(Dead_modelnums, N_polygon_models))
|
|
i = PHYSFSX_readInt(fp);
|
|
|
|
t = PHYSFSX_readInt(fp);
|
|
bitmap_index_read_n(fp, partial_range(Gauges, t));
|
|
bitmap_index_read_n(fp, partial_range(Gauges_hires, t));
|
|
|
|
N_ObjBitmaps = PHYSFSX_readInt(fp);
|
|
bitmap_index_read_n(fp, partial_range(ObjBitmaps, N_ObjBitmaps));
|
|
range_for (auto &i, partial_range(ObjBitmapPtrs, N_ObjBitmaps))
|
|
i = PHYSFSX_readShort(fp);
|
|
|
|
player_ship_read(&only_player_ship, fp);
|
|
|
|
Num_cockpits = PHYSFSX_readInt(fp);
|
|
bitmap_index_read_n(fp, partial_range(cockpit_bitmap, Num_cockpits));
|
|
|
|
//@@ PHYSFS_read( fp, &Num_total_object_types, sizeof(int), 1 );
|
|
//@@ PHYSFS_read( fp, ObjType, sizeof(byte), Num_total_object_types );
|
|
//@@ PHYSFS_read( fp, ObjId, sizeof(byte), Num_total_object_types );
|
|
//@@ PHYSFS_read( fp, ObjStrength, sizeof(fix), Num_total_object_types );
|
|
|
|
First_multi_bitmap_num = PHYSFSX_readInt(fp);
|
|
|
|
Num_reactors = PHYSFSX_readInt(fp);
|
|
reactor_read_n(fp, partial_range(Reactors, Num_reactors));
|
|
|
|
Marker_model_num = PHYSFSX_readInt(fp);
|
|
|
|
//@@PHYSFS_read( fp, &N_controlcen_guns, sizeof(int), 1 );
|
|
//@@PHYSFS_read( fp, controlcen_gun_points, sizeof(vms_vector), N_controlcen_guns );
|
|
//@@PHYSFS_read( fp, controlcen_gun_dirs, sizeof(vms_vector), N_controlcen_guns );
|
|
|
|
if (Piggy_hamfile_version < 3) {
|
|
exit_modelnum = PHYSFSX_readInt(fp);
|
|
destroyed_exit_modelnum = PHYSFSX_readInt(fp);
|
|
}
|
|
else
|
|
exit_modelnum = destroyed_exit_modelnum = N_polygon_models;
|
|
}
|
|
|
|
int extra_bitmap_num = 0;
|
|
|
|
static void bm_free_extra_objbitmaps()
|
|
{
|
|
int i;
|
|
|
|
if (!extra_bitmap_num)
|
|
extra_bitmap_num = Num_bitmap_files;
|
|
|
|
for (i = Num_bitmap_files; i < extra_bitmap_num; i++)
|
|
{
|
|
N_ObjBitmaps--;
|
|
d_free(GameBitmaps[i].bm_mdata);
|
|
}
|
|
extra_bitmap_num = Num_bitmap_files;
|
|
}
|
|
|
|
static void bm_free_extra_models()
|
|
{
|
|
auto base = std::min(N_D2_POLYGON_MODELS, exit_modelnum);
|
|
range_for (auto &p, partial_range(Polygon_models, base, N_polygon_models))
|
|
free_model(&p);
|
|
N_polygon_models = base;
|
|
}
|
|
|
|
//type==1 means 1.1, type==2 means 1.2 (with weapons)
|
|
void bm_read_extra_robots(const char *fname, Mission::descent_version_type type)
|
|
{
|
|
int t,version;
|
|
|
|
auto fp = PHYSFSX_openReadBuffered(fname);
|
|
if (!fp)
|
|
{
|
|
Error("Failed to open HAM file \"%s\"", fname);
|
|
return;
|
|
}
|
|
|
|
if (type == Mission::descent_version_type::descent2z)
|
|
{
|
|
int sig;
|
|
|
|
sig = PHYSFSX_readInt(fp);
|
|
if (sig != MAKE_SIG('X','H','A','M'))
|
|
return;
|
|
version = PHYSFSX_readInt(fp);
|
|
}
|
|
else
|
|
version = 0;
|
|
(void)version; // NOTE: we do not need it, but keep it for possible further use
|
|
|
|
bm_free_extra_models();
|
|
bm_free_extra_objbitmaps();
|
|
|
|
//read extra weapons
|
|
|
|
t = PHYSFSX_readInt(fp);
|
|
N_weapon_types = N_D2_WEAPON_TYPES+t;
|
|
weapon_info_read_n(Weapon_info, N_weapon_types, fp, 3, N_D2_WEAPON_TYPES);
|
|
|
|
//now read robot info
|
|
|
|
t = PHYSFSX_readInt(fp);
|
|
N_robot_types = N_D2_ROBOT_TYPES+t;
|
|
if (N_robot_types >= MAX_ROBOT_TYPES)
|
|
Error("Too many robots (%d) in <%s>. Max is %d.",t,fname,MAX_ROBOT_TYPES-N_D2_ROBOT_TYPES);
|
|
range_for (auto &r, partial_range(Robot_info, N_D2_ROBOT_TYPES, N_robot_types))
|
|
robot_info_read(fp, r);
|
|
|
|
t = PHYSFSX_readInt(fp);
|
|
N_robot_joints = N_D2_ROBOT_JOINTS+t;
|
|
if (N_robot_joints >= MAX_ROBOT_JOINTS)
|
|
Error("Too many robot joints (%d) in <%s>. Max is %d.",t,fname,MAX_ROBOT_JOINTS-N_D2_ROBOT_JOINTS);
|
|
range_for (auto &r, partial_range(Robot_joints, N_D2_ROBOT_JOINTS, N_robot_joints))
|
|
jointpos_read(fp, r);
|
|
|
|
unsigned u = PHYSFSX_readInt(fp);
|
|
N_polygon_models = N_D2_POLYGON_MODELS+u;
|
|
if (N_polygon_models >= MAX_POLYGON_MODELS)
|
|
Error("Too many polygon models (%d) in <%s>. Max is %d.",u,fname,MAX_POLYGON_MODELS-N_D2_POLYGON_MODELS);
|
|
{
|
|
const auto &&r = partial_range(Polygon_models, N_D2_POLYGON_MODELS, N_polygon_models);
|
|
range_for (auto &p, r)
|
|
polymodel_read(&p, fp);
|
|
|
|
range_for (auto &p, r)
|
|
polygon_model_data_read(&p, fp);
|
|
}
|
|
|
|
range_for (auto &i, partial_range(Dying_modelnums, N_D2_POLYGON_MODELS, N_polygon_models))
|
|
i = PHYSFSX_readInt(fp);
|
|
range_for (auto &i, partial_range(Dead_modelnums, N_D2_POLYGON_MODELS, N_polygon_models))
|
|
i = PHYSFSX_readInt(fp);
|
|
|
|
t = PHYSFSX_readInt(fp);
|
|
if (N_D2_OBJBITMAPS+t >= ObjBitmaps.size())
|
|
Error("Too many object bitmaps (%d) in <%s>. Max is %" DXX_PRI_size_type "u.", t, fname, ObjBitmaps.size() - N_D2_OBJBITMAPS);
|
|
bitmap_index_read_n(fp, partial_range(ObjBitmaps, N_D2_OBJBITMAPS, N_D2_OBJBITMAPS + t));
|
|
|
|
t = PHYSFSX_readInt(fp);
|
|
if (N_D2_OBJBITMAPPTRS+t >= ObjBitmapPtrs.size())
|
|
Error("Too many object bitmap pointers (%d) in <%s>. Max is %" DXX_PRI_size_type "u.", t, fname, ObjBitmapPtrs.size() - N_D2_OBJBITMAPPTRS);
|
|
range_for (auto &i, partial_range(ObjBitmapPtrs, N_D2_OBJBITMAPPTRS, N_D2_OBJBITMAPPTRS + t))
|
|
i = PHYSFSX_readShort(fp);
|
|
}
|
|
|
|
int Robot_replacements_loaded = 0;
|
|
|
|
void load_robot_replacements(const d_fname &level_name)
|
|
{
|
|
int t,i,j;
|
|
char ifile_name[FILENAME_LEN];
|
|
|
|
change_filename_extension(ifile_name, level_name, ".HXM" );
|
|
|
|
auto fp = PHYSFSX_openReadBuffered(ifile_name);
|
|
if (!fp) //no robot replacement file
|
|
return;
|
|
|
|
t = PHYSFSX_readInt(fp); //read id "HXM!"
|
|
if (t!= 0x21584d48)
|
|
Error("ID of HXM! file incorrect");
|
|
|
|
t = PHYSFSX_readInt(fp); //read version
|
|
if (t<1)
|
|
Error("HXM! version too old (%d)",t);
|
|
|
|
t = PHYSFSX_readInt(fp); //read number of robots
|
|
for (j=0;j<t;j++) {
|
|
i = PHYSFSX_readInt(fp); //read robot number
|
|
if (i<0 || i>=N_robot_types)
|
|
Error("Robots number (%d) out of range in (%s). Range = [0..%d].",i,static_cast<const char *>(level_name),N_robot_types-1);
|
|
robot_info_read(fp, Robot_info[i]);
|
|
}
|
|
|
|
t = PHYSFSX_readInt(fp); //read number of joints
|
|
for (j=0;j<t;j++) {
|
|
i = PHYSFSX_readInt(fp); //read joint number
|
|
if (i<0 || i>=N_robot_joints)
|
|
Error("Robots joint (%d) out of range in (%s). Range = [0..%d].",i,static_cast<const char *>(level_name),N_robot_joints-1);
|
|
jointpos_read(fp, Robot_joints[i]);
|
|
}
|
|
|
|
t = PHYSFSX_readInt(fp); //read number of polygon models
|
|
for (j=0;j<t;j++)
|
|
{
|
|
i = PHYSFSX_readInt(fp); //read model number
|
|
if (i<0 || i>=N_polygon_models)
|
|
Error("Polygon model (%d) out of range in (%s). Range = [0..%d].",i,static_cast<const char *>(level_name),N_polygon_models-1);
|
|
|
|
free_model(&Polygon_models[i]);
|
|
polymodel_read(&Polygon_models[i], fp);
|
|
polygon_model_data_read(&Polygon_models[i], fp);
|
|
|
|
Dying_modelnums[i] = PHYSFSX_readInt(fp);
|
|
Dead_modelnums[i] = PHYSFSX_readInt(fp);
|
|
}
|
|
|
|
t = PHYSFSX_readInt(fp); //read number of objbitmaps
|
|
for (j=0;j<t;j++) {
|
|
i = PHYSFSX_readInt(fp); //read objbitmap number
|
|
if (i < 0 || i >= ObjBitmaps.size())
|
|
Error("Object bitmap number (%d) out of range in (%s). Range = [0..%" DXX_PRI_size_type "].", i, static_cast<const char *>(level_name), ObjBitmaps.size() - 1);
|
|
bitmap_index_read(fp, ObjBitmaps[i]);
|
|
}
|
|
|
|
t = PHYSFSX_readInt(fp); //read number of objbitmapptrs
|
|
for (j=0;j<t;j++) {
|
|
i = PHYSFSX_readInt(fp); //read objbitmapptr number
|
|
if (i < 0 || i >= ObjBitmapPtrs.size())
|
|
Error("Object bitmap pointer (%d) out of range in (%s). Range = [0..%" DXX_PRI_size_type "].", i, static_cast<const char *>(level_name), ObjBitmapPtrs.size() - 1);
|
|
ObjBitmapPtrs[i] = PHYSFSX_readShort(fp);
|
|
}
|
|
Robot_replacements_loaded = 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* Routines for loading exit models
|
|
*
|
|
* Used by d1 levels (including some add-ons), and by d2 shareware.
|
|
* Could potentially be used by d2 add-on levels, but only if they
|
|
* don't use "extra" robots...
|
|
*/
|
|
|
|
// formerly exitmodel_bm_load_sub
|
|
static bitmap_index read_extra_bitmap_iff(const char * filename )
|
|
{
|
|
bitmap_index bitmap_num;
|
|
grs_bitmap * n = &GameBitmaps[extra_bitmap_num];
|
|
palette_array_t newpal;
|
|
int iff_error; //reference parm to avoid warning message
|
|
|
|
bitmap_num.index = 0;
|
|
|
|
//MALLOC( new, grs_bitmap, 1 );
|
|
iff_error = iff_read_bitmap(filename, *n, &newpal);
|
|
if (iff_error != IFF_NO_ERROR) {
|
|
con_printf(CON_DEBUG, "Error loading exit model bitmap <%s> - IFF error: %s", filename, iff_errormsg(iff_error));
|
|
return bitmap_num;
|
|
}
|
|
|
|
if ( iff_has_transparency )
|
|
gr_remap_bitmap_good(*n, newpal, iff_transparent_color, 254);
|
|
else
|
|
gr_remap_bitmap_good(*n, newpal, -1, 254);
|
|
|
|
n->avg_color = 0; //compute_average_pixel(new);
|
|
|
|
bitmap_num.index = extra_bitmap_num;
|
|
|
|
GameBitmaps[extra_bitmap_num++] = *n;
|
|
|
|
//d_free( n );
|
|
return bitmap_num;
|
|
}
|
|
|
|
// formerly load_exit_model_bitmap
|
|
static grs_bitmap *bm_load_extra_objbitmap(const char *name)
|
|
{
|
|
assert(N_ObjBitmaps < ObjBitmaps.size());
|
|
{
|
|
ObjBitmaps[N_ObjBitmaps] = read_extra_bitmap_iff(name);
|
|
|
|
if (ObjBitmaps[N_ObjBitmaps].index == 0)
|
|
{
|
|
RAIIdmem<char[]> name2(d_strdup(name));
|
|
*strrchr(name2.get(), '.') = '\0';
|
|
ObjBitmaps[N_ObjBitmaps] = read_extra_bitmap_d1_pig(name2.get());
|
|
}
|
|
if (ObjBitmaps[N_ObjBitmaps].index == 0)
|
|
return NULL;
|
|
|
|
if (GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_w!=64 || GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_h!=64)
|
|
Error("Bitmap <%s> is not 64x64",name);
|
|
ObjBitmapPtrs[N_ObjBitmaps] = N_ObjBitmaps;
|
|
N_ObjBitmaps++;
|
|
assert(N_ObjBitmaps < ObjBitmaps.size());
|
|
return &GameBitmaps[ObjBitmaps[N_ObjBitmaps-1].index];
|
|
}
|
|
}
|
|
|
|
int load_exit_models()
|
|
{
|
|
int start_num;
|
|
|
|
bm_free_extra_models();
|
|
bm_free_extra_objbitmaps();
|
|
|
|
start_num = N_ObjBitmaps;
|
|
if (!bm_load_extra_objbitmap("steel1.bbm") ||
|
|
!bm_load_extra_objbitmap("rbot061.bbm") ||
|
|
!bm_load_extra_objbitmap("rbot062.bbm") ||
|
|
!bm_load_extra_objbitmap("steel1.bbm") ||
|
|
!bm_load_extra_objbitmap("rbot061.bbm") ||
|
|
!bm_load_extra_objbitmap("rbot063.bbm"))
|
|
{
|
|
con_printf(CON_NORMAL, "Can't load exit models!");
|
|
return 0;
|
|
}
|
|
if (auto exit_hamfile = PHYSFSX_openReadBuffered("exit.ham"))
|
|
{
|
|
exit_modelnum = N_polygon_models++;
|
|
destroyed_exit_modelnum = N_polygon_models++;
|
|
polymodel_read(&Polygon_models[exit_modelnum], exit_hamfile);
|
|
polymodel_read(&Polygon_models[destroyed_exit_modelnum], exit_hamfile);
|
|
Polygon_models[exit_modelnum].first_texture = start_num;
|
|
Polygon_models[destroyed_exit_modelnum].first_texture = start_num+3;
|
|
|
|
polygon_model_data_read(&Polygon_models[exit_modelnum], exit_hamfile);
|
|
|
|
polygon_model_data_read(&Polygon_models[destroyed_exit_modelnum], exit_hamfile);
|
|
} else if (PHYSFSX_exists("exit01.pof",1) && PHYSFSX_exists("exit01d.pof",1)) {
|
|
|
|
exit_modelnum = load_polygon_model("exit01.pof", 3, start_num, NULL);
|
|
destroyed_exit_modelnum = load_polygon_model("exit01d.pof", 3, start_num + 3, NULL);
|
|
|
|
#ifdef OGL
|
|
ogl_cache_polymodel_textures(exit_modelnum);
|
|
ogl_cache_polymodel_textures(destroyed_exit_modelnum);
|
|
#endif
|
|
}
|
|
else if ((exit_hamfile = PHYSFSX_openReadBuffered(D1_PIGFILE)))
|
|
{
|
|
int offset, offset2;
|
|
int hamsize;
|
|
hamsize = PHYSFS_fileLength(exit_hamfile);
|
|
switch (hamsize) { //total hack for loading models
|
|
case D1_PIGSIZE:
|
|
offset = 91848; /* and 92582 */
|
|
offset2 = 383390; /* and 394022 */
|
|
break;
|
|
default:
|
|
case D1_SHARE_BIG_PIGSIZE:
|
|
case D1_SHARE_10_PIGSIZE:
|
|
case D1_SHARE_PIGSIZE:
|
|
case D1_10_BIG_PIGSIZE:
|
|
case D1_10_PIGSIZE:
|
|
Int3(); /* exit models should be in .pofs */
|
|
case D1_OEM_PIGSIZE:
|
|
case D1_MAC_PIGSIZE:
|
|
case D1_MAC_SHARE_PIGSIZE:
|
|
con_printf(CON_NORMAL, "Can't load exit models!");
|
|
return 0;
|
|
}
|
|
PHYSFSX_fseek(exit_hamfile, offset, SEEK_SET);
|
|
exit_modelnum = N_polygon_models++;
|
|
destroyed_exit_modelnum = N_polygon_models++;
|
|
polymodel_read(&Polygon_models[exit_modelnum], exit_hamfile);
|
|
polymodel_read(&Polygon_models[destroyed_exit_modelnum], exit_hamfile);
|
|
Polygon_models[exit_modelnum].first_texture = start_num;
|
|
Polygon_models[destroyed_exit_modelnum].first_texture = start_num+3;
|
|
|
|
PHYSFSX_fseek(exit_hamfile, offset2, SEEK_SET);
|
|
polygon_model_data_read(&Polygon_models[exit_modelnum], exit_hamfile);
|
|
polygon_model_data_read(&Polygon_models[destroyed_exit_modelnum], exit_hamfile);
|
|
} else {
|
|
con_printf(CON_NORMAL, "Can't load exit models!");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
void compute_average_rgb(grs_bitmap *bm, array<fix, 3> &rgb)
|
|
{
|
|
rgb = {};
|
|
if (unlikely(!bm->get_bitmap_data()))
|
|
return;
|
|
const uint_fast32_t bm_h = bm->bm_h;
|
|
const uint_fast32_t bm_w = bm->bm_w;
|
|
if (unlikely(!bm_h) || unlikely(!bm_w))
|
|
return;
|
|
|
|
const auto process_one = [&rgb](uint8_t color) {
|
|
if (color == TRANSPARENCY_COLOR)
|
|
return;
|
|
auto &t_rgb = gr_palette[color];
|
|
if (t_rgb.r == t_rgb.g && t_rgb.r == t_rgb.b)
|
|
return;
|
|
rgb[0] += t_rgb.r;
|
|
rgb[1] += t_rgb.g;
|
|
rgb[2] += t_rgb.b;
|
|
};
|
|
if (bm->bm_flags & BM_FLAG_RLE){
|
|
auto buf = make_unique<uint8_t[]>(bm_w);
|
|
int data_offset;
|
|
|
|
data_offset = 1;
|
|
if (bm->bm_flags & BM_FLAG_RLE_BIG)
|
|
data_offset = 2;
|
|
|
|
auto sbits = &bm->get_bitmap_data()[4 + (bm->bm_h * data_offset)];
|
|
for (uint_fast32_t i = 0; i != bm_h; ++i)
|
|
{
|
|
#ifdef DXX_HAVE_POISON
|
|
/* Reallocate to undefine buffer */
|
|
buf = make_unique<uint8_t[]>(bm_w);
|
|
#endif
|
|
auto dbits = buf.get();
|
|
gr_rle_decode({sbits, dbits}, {end(*bm), dbits + bm_w});
|
|
if ( bm->bm_flags & BM_FLAG_RLE_BIG )
|
|
sbits += GET_INTEL_SHORT(&bm->bm_data[4 + (i * data_offset)]);
|
|
else
|
|
sbits += static_cast<int>(bm->bm_data[4+i]);
|
|
range_for (const auto color, unchecked_partial_range(dbits, bm_w))
|
|
process_one(color);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
range_for (const auto color, unchecked_partial_range(bm->bm_data, bm_w * bm_h))
|
|
process_one(color);
|
|
}
|
|
}
|