Files
questshock/engine/src/GameSrc/gamesort.c
T
ml a5ec8db5f7
build / build (push) Failing after 5s
Vendor the Shockolate engine and build it via a Docker image with every
dependency (SDL2, SDL2_mixer, fluidsynth-lite, a MIDI soundfont)
prebuilt, so compiling the engine needs no network access - just the
image and the engine source. Add res/assets/extract_assets.sh to pull
the game's data files out of a purchased GOG installer, and a Makefile
that assembles a runnable dist/ from the two.

Also add `make package`, which builds a redistributable tarball that
omits the proprietary game assets (shipping res/GET_ASSETS.txt instead)
plus license information for both the MIT tooling and the GPLv3 engine,
and a Gitea Actions workflow that builds and publishes it to
dl.ladkau.de on every push.
2026-07-19 15:43:38 +02:00

312 lines
9.1 KiB
C

/*
Copyright (C) 2015-2018 Night Dive Studios, LLC.
This program 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 3 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, see <http://www.gnu.org/licenses/>.
*/
/*
* GameSort.c
*
* $Source: r:/prj/cit/src/RCS/gamesort.c $
* $Revision: 1.10 $
* $Author: dc $
* $Date: 1994/08/24 06:19:35 $
*
* Game system object sorting
*/
#include <stdlib.h>
#include "map.h"
#include "objects.h"
#include "objsim.h"
#include "objprop.h"
#include "objclass.h"
#include "otrip.h"
#include "frcamera.h"
#include "gameobj.h"
#include "gamesort.h"
// want outrageous mprintf's? of course you do!
//#define SORT_SPEW
// Internal Prototypes
void sort_section(int low, int hi);
void score_objs(int o_num);
int do_part_sort(int ptype, int lo, int hi, int ploc);
void partition_sort(void);
#define MAX_SORTED_REFS 64
#define PRT_NONE 0
#define PRT_HORIZ 0x20
#define PRT_VERT 0x40
#define PRT_BOTH 0x60
#define PRT_MASK 0x60
// this just isnt going to work
#define SCORE_SHIFT 8
#define SCORE_HALF_ENTRY 0x80
#define SCORE_REFIDX_MASK 0x1F
#define SCORE_SCORE_MASK 0xFFFFFF00
// public, rendtool sets this for camera controls
ObjID no_render_obj = -1;
static ObjID sq_Refs[MAX_SORTED_REFS];
static uint score_list[MAX_SORTED_REFS]; // at first holds obj_type8.objtrip24, then objscore24.exp1.partition2.refidx5
// thus we can sort it w/o losing the refidx, which looks up in sqrefs
static ushort partition_loc[MAX_SORTED_REFS]; // for the partitions
static uchar partition_type;
static uchar partition_cnt;
static uint cur_obj_num, draw_last_cnt;
static uint osort_xc, osort_yc, osort_zc;
// set up data space,
void render_sort_start(void) {
cur_obj_num = 0;
osort_xc = fr_camera_last[0] >> 8;
osort_yc = fr_camera_last[1] >> 8;
osort_zc = fr_camera_last[2] >> (16 - SLOPE_SHIFT - 3); // oh yea
}
void sort_section(int low, int hi) {
int iloop, oloop;
uint tmp;
for (oloop = hi - 1; oloop >= low; oloop--)
for (iloop = low; iloop <= oloop; iloop++)
if (score_list[iloop] < score_list[iloop + 1]) {
tmp = score_list[iloop];
score_list[iloop] = score_list[iloop + 1];
score_list[iloop + 1] = tmp;
}
}
void score_objs(int o_num) {
ObjID cobjid;
short objtrip;
Obj *_os_cobj;
extern uchar cam_mode;
int partition = PRT_NONE, obj_type, our_score;
cobjid = sq_Refs[o_num];
obj_type = score_list[o_num] >> 24;
objtrip = score_list[o_num] & 0xffffff;
_os_cobj = &objs[cobjid];
switch (obj_type) {
case FAUBJ_SPECIAL:
switch (ID2TRIP(cobjid)) {
case TRIPBEAM_TRIPLE:
partition = PRT_HORIZ;
break;
case FORCE_BRIJ_TRIPLE:
case BRIDGE_TRIPLE:
case CATWALK_TRIPLE:
partition = PRT_VERT;
break;
}
break;
case FAUBJ_TL_POLY:
case FAUBJ_TEXBITMAP:
case FAUBJ_TPOLY:
if (_os_cobj->obclass == CLASS_DOOR)
if (((_os_cobj->loc.p + 0x20) & 0x7f) < 0x40)
partition = PRT_HORIZ;
else
partition = PRT_VERT;
else
partition = -1; // secret i am a freebie code
break;
}
our_score =
abs((int)osort_xc - (int)_os_cobj->loc.x) +
abs((int)osort_yc - (int)_os_cobj->loc.y) +
abs((int)osort_zc - (int)_os_cobj->loc.z);
our_score <<= 8; // 24 bits of score, should do for now
// if bloodstain, want to | 0x80 here...
if (partition > 0) {
our_score |= partition | o_num;
partition_loc[partition_cnt] = o_num;
partition_cnt++;
partition_type |= partition;
} else if (partition < 0) {
int tmp = our_score | o_num;
if (draw_last_cnt != o_num) {
our_score = score_list[draw_last_cnt];
if (our_score & PRT_MASK) {
int i = 0;
while (i < partition_cnt)
if (partition_loc[i] == draw_last_cnt) {
partition_loc[i] = o_num;
break;
}
if (i == partition_cnt)
WARN("%s: lost my partition", __FUNCTION__);
}
score_list[draw_last_cnt] = tmp;
} else {
our_score = tmp;
}
draw_last_cnt++;
} else {
our_score |= o_num;
}
score_list[o_num] = our_score;
}
#define get_part_val(tval, ob, which) \
switch (which) { \
case 0: tval = ob->loc.x; break; \
case 1: tval = ob->loc.y; break; \
case 2: tval = ob->loc.z; break; \
}
int do_part_sort(int ptype, int lo, int hi, int ploc) {
Obj *cur_obj, *part_obj;
int cur_val, part_val, pdir, cam_val, near_f, loidx, hiidx;
int ptptr[2], ptdelta[2], tmpstore = -1, mloc;
part_obj = &objs[sq_Refs[ploc]];
pdir = (ptype == PRT_VERT) ? 2 : (part_obj->loc.h & 0x40) ? 0 : 1;
get_part_val(part_val, part_obj, pdir);
cam_val = pdir == 0 ? osort_xc : pdir == 1 ? osort_yc : osort_zc;
near_f = (cam_val < part_val);
if ((lo <= ploc) && (ploc < hi)) {
tmpstore = score_list[ploc];
if (ploc < --hi)
score_list[ploc] = score_list[hi];
} else
WARN("%s: Partition not in list", __FUNCTION__);
if (near_f) {
ptptr[0] = hi - 1;
ptdelta[0] = -1;
ptptr[1] = lo;
ptdelta[1] = 1;
loidx = 1;
hiidx = 0;
} else {
ptptr[0] = lo;
ptdelta[0] = 1;
ptptr[1] = hi - 1;
ptdelta[1] = -1;
loidx = 0;
hiidx = 1;
}
// ok, this checks in a massively gruesomely redundant way, rewrite for real in asm
while (ptptr[loidx] <= ptptr[hiidx]) {
cur_obj = &objs[sq_Refs[score_list[ptptr[0]] & SCORE_REFIDX_MASK]];
get_part_val(cur_val, cur_obj, pdir);
while (cur_val < part_val) {
ptptr[0] += ptdelta[0];
if (ptptr[loidx] > ptptr[hiidx])
goto done_psort;
cur_obj = &objs[sq_Refs[score_list[ptptr[0]] & SCORE_REFIDX_MASK]];
get_part_val(cur_val, cur_obj, pdir);
}
cur_obj = &objs[sq_Refs[score_list[ptptr[1]] & SCORE_REFIDX_MASK]];
get_part_val(cur_val, cur_obj, pdir);
while (cur_val > part_val) {
ptptr[1] += ptdelta[1];
if (ptptr[loidx] > ptptr[hiidx])
goto done_psort;
cur_obj = &objs[sq_Refs[score_list[ptptr[1]] & SCORE_REFIDX_MASK]];
get_part_val(cur_val, cur_obj, pdir);
}
{
int tmpptr = score_list[ptptr[0]];
score_list[ptptr[0]] = score_list[ptptr[1]];
score_list[ptptr[1]] = tmpptr;
ptptr[0] += ptdelta[0]; // now move on in
ptptr[1] += ptdelta[1];
}
}
done_psort:
mloc = ptptr[loidx];
if (tmpstore != -1) {
score_list[hi++] = score_list[mloc];
score_list[mloc] = tmpstore;
}
return mloc;
}
void partition_sort(void) {
if ((partition_cnt > 1) || (partition_type == PRT_BOTH))
; // KLC Warning(("Dual partitions\n"));
else {
int mloc;
#ifdef COW_COW
if (cur_obj_num == partition_loc[0])
sort_section(draw_last_cnt, cur_obj_num - 1);
else if (draw_last_cnt == partition_loc[0])
sort_section(draw_last_cnt + 1, cur_obj_num);
else
#endif // __FEAR__ the COW COW
{
mloc = do_part_sort(partition_type, draw_last_cnt, cur_obj_num, partition_loc[0]);
sort_section(draw_last_cnt, mloc - 1);
sort_section(mloc + 1, cur_obj_num - 1);
}
}
}
// go through, do the sort, call show_obj a lot
// for now, just do oscore straight...
void render_sorted_objs(void) {
extern int _fdt_x, _fdt_y;
int i;
partition_cnt = partition_type = draw_last_cnt = 0;
if (cur_obj_num > 1) {
for (i = 0; i < cur_obj_num; i++)
score_objs(i);
if (partition_cnt)
partition_sort();
else
sort_section(draw_last_cnt, cur_obj_num - 1);
for (i = 0; i < cur_obj_num; i++)
show_obj(sq_Refs[score_list[i] & SCORE_REFIDX_MASK]);
} else if (cur_obj_num == 1)
show_obj(sq_Refs[0]);
cur_obj_num = 0;
}
void sort_show_obj(ObjID cobjid) {
short objtrip;
int obj_type;
if (cur_obj_num >= MAX_SORTED_REFS)
return;
if (cobjid == no_render_obj)
return;
objtrip = OPNUM(cobjid);
obj_type = ObjProps[objtrip].render_type;
if (obj_type == FAUBJ_NOOBJ)
return;
score_list[cur_obj_num] = (obj_type << 24) + objtrip;
sq_Refs[cur_obj_num] = cobjid;
cur_obj_num++;
}