1 /*
2 
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 /*
20  * $Source: r:/prj/cit/src/RCS/olhscan.c $
21  * $Revision: 1.6 $
22  * $Author: dc $
23  * $Date: 1994/11/21 09:10:45 $
24  */
25 
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "faketime.h"
30 
31 #include "frtypes.h"
32 #include "frintern.h"
33 #include "frparams.h"
34 #include "frflags.h"
35 #include "olhint.h"
36 #include "objects.h"
37 #include "objprop.h"
38 #include "game_screen.h"
39 #include "fullscrn.h"
40 
41 #define SCAN_OBJ_LIST 8
42 
43 #define MIN_OLH_RADIUS 2
44 #define MAX_OLH_RADIUS 5
45 
46 ubyte olh_radius = MIN_OLH_RADIUS;
47 
48 #define BOTTOM_MARGIN (SCAN_HGT - 15 / SCAN_RATIO)
49 #define RIGHT_MARGIN (OLH_WRAP_WID / SCAN_RATIO)
50 
51 fauxrend_context *olh_full_context = NULL;
52 
53 extern fauxrend_context *svga_render_context;
54 
55 #define FULL_SCAN_WID (FULL_VIEW_WIDTH / SCAN_RATIO)
56 #define FULL_SCAN_HGT (FULL_VIEW_HEIGHT / SCAN_RATIO)
57 
58 void olh_init_single_scan(fauxrend_context **outxt, fauxrend_context *intxt);
59 void olh_init_scan(void);
60 void olh_free_scan(void);
61 void olh_svga_deal(void);
62 ushort olh_scan_objs(void);
63 
olh_init_single_scan(fauxrend_context ** outxt,fauxrend_context * intxt)64 void olh_init_single_scan(fauxrend_context **outxt, fauxrend_context *intxt) {
65     uchar *mem = ((grs_canvas *)fr_get_canvas(intxt))->bm.bits;
66 
67     *outxt = (fauxrend_context *)fr_place_view(FR_NEWVIEW, FR_DEFCAM, mem,
68                                                FR_CURVIEW_STRT | FR_DOUBLEB_MASK | FR_PICKUPM_MASK, 0, 0, 0, 0,
69                                                intxt->xwid / SCAN_RATIO, intxt->ywid / SCAN_RATIO);
70     fr_set_callbacks(*outxt, NULL, NULL, NULL);
71 }
72 
73 /*KLC - no longer used
74 void olh_init_scan(void)
75 {
76    olh_init_single_scan(&olh_full_context, (fauxrend_context *)full_game_fr_context);
77 }
78 */
olh_free_scan(void)79 void olh_free_scan(void) {
80     if (olh_full_context)
81         fr_free_view(olh_full_context);
82 }
83 
84 fix x_mul = fix_make(1, 0), y_mul = fix_make(1, 0);
olh_svga_deal(void)85 void olh_svga_deal(void) {
86     if (olh_full_context)
87         fr_free_view(olh_full_context);
88     olh_init_single_scan(&olh_full_context, svga_render_context);
89     x_mul = fix_div(fix_make(320, 0), fix_make(grd_mode_cap.w, 0));
90     y_mul = fix_div(fix_make(200, 0), fix_make(grd_mode_cap.h, 0));
91 }
92 
93 extern int last_real_time;
94 
olh_scan_objs(void)95 ushort olh_scan_objs(void) {
96     int xl, yl;
97     int col;
98     int (*fr_ptr_idx)(void) = fr_get_idx;
99     short x, y;
100     struct _obj_scandata {
101         ObjID obj;
102         int x, y; // TOTAL x and y coordinates for all samples
103         ushort count;
104     } objdata[SCAN_OBJ_LIST];
105     short objcount = 0;
106 #ifdef SVGA_SUPPORT
107     fauxrend_context *fr = olh_full_context;
108 #else
109     fauxrend_context *fr = (full_game_3d) ? olh_full_context : olh_context;
110 #endif
111     ubyte save_radius = _frp.view.radius;
112 
113     // Do a monochrome render
114     //   olh_replace_view(SCREEN_CONTEXT->xwid/SCAN_RATIO,SCREEN_CONTEXT->ywid/SCAN_RATIO);
115     //   _fr_top(fr);
116     _fr_glob_flags |= FR_PICKUPM_MASK;
117     fr_cur_obj_col = FR_CUR_OBJ_BASE;
118     fr_get_idx = fr_pickup_idx;
119     _frp.view.radius = olh_radius;
120     fr_rend(fr);
121     _frp.view.radius = save_radius;
122     fr_get_idx = fr_ptr_idx;
123     _fr_glob_flags &= ~FR_PICKUPM_MASK;
124 
125     if (*tmd_ticks - last_real_time < CIT_CYCLE / 15)
126         olh_radius = lg_min(olh_radius + 1, MAX_OLH_RADIUS);
127     else if (*tmd_ticks - last_real_time > CIT_CYCLE / 10)
128         olh_radius = lg_max(olh_radius - 1, MIN_OLH_RADIUS);
129 
130     xl = yl = 0;
131 
132 #ifdef DEBUGGING_BLIT
133     gr_push_canvas(grd_screen_canvas);
134     gr_bitmap(&fr->draw_canvas.bm, 0, 200 - fr->draw_canvas.bm.h);
135     gr_pop_canvas();
136 #endif
137 
138     olh_object.obj = OBJ_NULL;
139     // collect samples
140     for (y = yl; y < fr->draw_canvas.bm.h; y++)
141         for (x = xl; x < fr->draw_canvas.bm.w; x++) {
142             if (y > BOTTOM_MARGIN && x > fr->draw_canvas.bm.w - RIGHT_MARGIN)
143                 break;
144             col = (int)(*((fr->draw_canvas.bm.bits) + (y * fr->draw_canvas.bm.row) + (x)));
145             if ((col >= FR_CUR_OBJ_BASE) && (col < fr_cur_obj_col)) // if we are actually exactly over an object
146             {
147                 ObjID obj = (ObjID)fr_col_to_obj[col - FR_CUR_OBJ_BASE];
148                 if (olh_candidate(obj)) {
149                     int i;
150                     for (i = 0; i < objcount; i++)
151                         if (objdata[i].obj == obj) {
152                             objdata[i].x += x;
153                             objdata[i].y += y;
154                             objdata[i].count++;
155                             goto found;
156                         }
157                     // not found, so add the object
158                     if (objcount >= SCAN_OBJ_LIST) // no more room in list, how sad.
159                         continue;
160                     i = objcount++;
161                     objdata[i].obj = obj;
162                     objdata[i].x = x;
163                     objdata[i].y = y;
164                     objdata[i].count = 1;
165                 found:
166                     //               mprintf ("found %d at (%d,%d) (x,y) now (%d,%d), count now
167                     //               %d\n",obj,x,y,objdata[i].x,objdata[i].y,objdata[i].count);
168                     ;
169                 }
170             }
171         }
172 
173     // now pick the best one.
174     if (objcount > 0) {
175         int i;
176         uint best_weight = 0;
177         for (i = 0; i < objcount; i++) {
178             struct _obj_scandata *dat = &objdata[i];
179             LGPoint pos = MakePoint((short)(dat->x / dat->count), (short)(dat->y / dat->count));
180             uint weight =
181                 dat->count * (fr->xwid + fr->ywid) / (abs(2 * pos.x - fr->xwid) + abs(2 * pos.y - fr->ywid) + 1);
182             if (weight > best_weight) {
183                 olh_object.obj = dat->obj;
184                 olh_object.loc = pos;
185                 best_weight = weight;
186             }
187         }
188 #ifdef SVGA_SUPPORT
189         {
190             fix tmp;
191             tmp = fix_make(olh_object.loc.x, 0);
192             tmp = fix_mul(tmp, x_mul);
193             olh_object.loc.x = fix_int(tmp);
194             tmp = fix_make(olh_object.loc.y, 0);
195             tmp = fix_mul(tmp, y_mul);
196             olh_object.loc.y = fix_int(tmp);
197         }
198 #endif
199     } else
200         olh_object.obj = OBJ_NULL;
201     return OBJ_NULL;
202 }
203