/* 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 . */ /* * 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 #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++; }