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/view360.c $
21  * $Revision: 1.33 $
22  * $Author: xemu $
23  * $Date: 1994/10/27 04:53:06 $
24  */
25 
26 #include <string.h>
27 
28 #include "frprotox.h"
29 #include "frcamera.h"
30 #include "frflags.h"
31 #include "invent.h"
32 #include "mfdint.h"
33 #include "mfdext.h"
34 #include "mfddims.h"
35 #include "wares.h"
36 #include "mainloop.h"
37 #include "gameloop.h"
38 #include "tools.h"
39 #include "frflags.h"
40 #include "musicai.h"
41 #include "sfxlist.h"
42 #include "objsim.h"
43 #include "faketime.h"
44 #include "gamestrn.h"
45 #include "colors.h"
46 #include "fullscrn.h"
47 #include "invpages.h"
48 #include "view360.h"
49 #include "gr2ss.h"
50 
51 #include "otrip.h"
52 #include "cybstrng.h"
53 #include "gamescr.h"
54 
55 #include "OpenGL.h"
56 
57 extern uchar dirty_inv_canvas;
58 
59 // -------
60 // GLOBALS
61 // -------
62 frc *view360_contexts[NUM_360_CONTEXTS]; // the renderer contexts for each view window
63 frc *view360_fullscreen_contexts[NUM_360_CONTEXTS];
64 #define CONTEXT ((full_game_3d) ? view360_fullscreen_contexts : view360_contexts)
65 uchar view360_active_contexts[NUM_360_CONTEXTS]; // which contexts should actually draw
66 #define ACTIVE view360_active_contexts
67 uchar view360_context_views[NUM_360_CONTEXTS]; // which view is being shown by a given context
68 #define VIEW view360_context_views
69 
70 uchar view360_message_obscured = FALSE;
71 uchar view360_render_on = FALSE;
72 short view360_last_update = 0;
73 uchar view360_is_rendering = FALSE;
74 
75 // ---------
76 // INTERNALS
77 // ---------
78 void view360_setup_mode(uchar mode);
79 void view360_restore_inventory(void);
80 int view360_fullscrn_draw_callback(void *, void *vbm, int x, int y, int flg);
81 uchar inv_is_360_view(void);
82 void view360_init(void);
83 void view360_shutdown(void);
84 void view360_update_screen_mode(void);
85 void view360_render(void);
86 void mfd_view360_expose(MFD *mfd, ubyte control);
87 void view360_turnon(uchar visible, uchar real_start);
88 void view360_turnoff(uchar visible, uchar real_stop);
89 bool view360_check(void);
90 
91 // Set up/turn on all contexts & cameras for the specified mode.
view360_setup_mode(uchar mode)92 void view360_setup_mode(uchar mode) {
93     ubyte version = player_struct.hardwarez[CPTRIP(SENS_HARD_TRIPLE)];
94     if ((version > 2 && mode == MODE_360) || mode == MODE_270) {
95         VIEW[LEFT_CONTEXT] = CAMANG_LEFT;
96         ACTIVE[LEFT_CONTEXT] = TRUE;
97         VIEW[RIGHT_CONTEXT] = CAMANG_RIGHT;
98         ACTIVE[RIGHT_CONTEXT] = TRUE;
99         mfd_notify_func(MFD_3DVIEW_FUNC, MFD_INFO_SLOT, TRUE, MFD_ACTIVE, FALSE);
100         mfd_change_slot(MFD_LEFT, MFD_INFO_SLOT);
101         mfd_change_slot(MFD_RIGHT, MFD_INFO_SLOT);
102     }
103     if (mode == MODE_360) {
104         inventory_clear();
105         VIEW[MID_CONTEXT] = CAMANG_BACK;
106         ACTIVE[MID_CONTEXT] = TRUE;
107         inv_last_page = inventory_page;
108         inventory_page = INV_3DVIEW_PAGE;
109     }
110     if (mode == MODE_REAR) {
111         int mfd;
112         for (mfd = 0; mfd < NUM_MFDS; mfd++) {
113             if (mfd_get_func(mfd, player_struct.mfd_current_slots[mfd]) == MFD_3DVIEW_FUNC)
114                 break;
115         }
116         if (mfd >= NUM_MFDS)
117             mfd = mfd_grab();
118         VIEW[mfd] = CAMANG_BACK;
119         ACTIVE[mfd] = TRUE;
120         mfd_notify_func(MFD_3DVIEW_FUNC, MFD_INFO_SLOT, TRUE, MFD_ACTIVE, FALSE);
121         mfd_change_slot(mfd, MFD_INFO_SLOT);
122     }
123 }
124 
view360_restore_inventory()125 void view360_restore_inventory() {
126     if (_current_loop == GAME_LOOP) {
127         extern void inv_change_fullscreen(uchar on);
128         chg_set_flg(INVENTORY_UPDATE);
129         inv_change_fullscreen(full_game_3d);
130         view360_message_obscured = FALSE;
131         inv_last_page = INV_BLANK_PAGE;
132         message_info(""); // This should be NULL as soon as the 2d can handle it.
133     }
134     ACTIVE[MID_CONTEXT] = FALSE;
135 }
136 
137 // what/where are these???
138 extern grs_canvas _offscreen_mfd, _fullscreen_mfd, inv_view360_canvas;
139 
140 static uchar rendered_inv_fullscrn = FALSE;
141 
142 extern void shock_hflip_in_place(grs_bitmap *bm);
143 
view360_fullscrn_draw_callback(void * v,void * vbm,int x,int y,int flg)144 int view360_fullscrn_draw_callback(void *v, void *vbm, int x, int y, int flg) {
145     // KLC   shock_hflip_in_place((grs_bitmap *)vbm);
146     return FALSE;
147 }
148 
149 // ---------
150 // EXTERNALS
151 // ---------
152 
inv_is_360_view(void)153 uchar inv_is_360_view(void) { return ACTIVE[MID_CONTEXT]; }
154 
155 // then or in with palette
156 //#define VIEW360_BASEFR (FR_DOUBLEB_MASK|FR_DOHFLIP_MASK)
157 #define VIEW360_BASEFR (FR_DOUBLEB_MASK)
158 
view360_init(void)159 void view360_init(void) {
160     frc *c;
161     uchar *canv;
162     short x, y, w, h;
163 
164     canv = _offscreen_mfd.bm.bits;
165     x = MFD_VIEW_LFTX;
166     y = MFD_VIEW_Y;
167     w = MFD_VIEW_WID;
168     h = MFD_VIEW_HGT;
169 #ifdef SVGA_SUPPORT
170     ss_point_convert(&x, &y, FALSE);
171     ss_point_convert(&w, &h, FALSE);
172     h = lg_min(h, 137);
173 #endif
174     view360_contexts[LEFT_CONTEXT] =
175         fr_place_view(FR_NEWVIEW, FR_DEFCAM, canv, VIEW360_BASEFR | FR_CURVIEW_LEFT, 0, 0, x, y, w, h);
176     c = view360_fullscreen_contexts[LEFT_CONTEXT] =
177         fr_place_view(FR_NEWVIEW, FR_DEFCAM, canv, VIEW360_BASEFR | FR_CURVIEW_LEFT, 0, 0, x, y, w, h);
178     fr_set_callbacks(c, view360_fullscrn_draw_callback, NULL, NULL);
179 
180     x = MFD_VIEW_RGTX;
181     y = MFD_VIEW_Y;
182     w = MFD_VIEW_WID;
183     h = MFD_VIEW_HGT;
184 #ifdef SVGA_SUPPORT
185     ss_point_convert(&x, &y, FALSE);
186     ss_point_convert(&w, &h, FALSE);
187     h = lg_min(h, 137);
188 #endif
189     view360_contexts[RIGHT_CONTEXT] =
190         fr_place_view(FR_NEWVIEW, FR_DEFCAM, canv, VIEW360_BASEFR | FR_CURVIEW_RGHT, 0, 0, x, y, w, h);
191     canv = _fullscreen_mfd.bm.bits;
192     c = view360_fullscreen_contexts[RIGHT_CONTEXT] =
193         fr_place_view(FR_NEWVIEW, FR_DEFCAM, canv, VIEW360_BASEFR | FR_CURVIEW_RGHT, 0, 0, x, y, w, h);
194     fr_set_callbacks(c, view360_fullscrn_draw_callback, NULL, NULL);
195 
196     x = GAME_MESSAGE_X;
197     y = GAME_MESSAGE_Y;
198     w = INV_FULL_WD;
199     h = INV_FULL_HT;
200 #ifdef SVGA_SUPPORT
201     ss_point_convert(&x, &y, FALSE);
202     ss_point_convert(&w, &h, FALSE);
203 #endif
204     canv = inv_view360_canvas.bm.bits;
205     view360_contexts[MID_CONTEXT] =
206         fr_place_view(FR_NEWVIEW, FR_DEFCAM, canv, VIEW360_BASEFR | FR_CURVIEW_BACK, 0, REAR_FOV, x, y, w, h);
207     c = view360_fullscreen_contexts[MID_CONTEXT] =
208         fr_place_view(FR_NEWVIEW, FR_DEFCAM, canv, VIEW360_BASEFR | FR_CURVIEW_BACK, 0, REAR_FOV, x, y, w, h);
209     fr_set_callbacks(c, view360_fullscrn_draw_callback, NULL, NULL);
210 }
211 
view360_shutdown(void)212 void view360_shutdown(void) {
213     int i;
214     for (i = LEFT_CONTEXT; i <= MID_CONTEXT; i++) {
215         fr_free_view(view360_contexts[i]);
216         fr_free_view(view360_fullscreen_contexts[i]);
217     }
218 }
219 
view360_update_screen_mode()220 void view360_update_screen_mode() {
221     view360_shutdown();
222     view360_init();
223 }
224 
225 char update_string[30] = "";
226 
view360_render(void)227 void view360_render(void) {
228     opengl_begin_sensaround(player_struct.hardwarez[CPTRIP(SENS_HARD_TRIPLE)]);
229     uchar on = FALSE;
230 
231     if (inventory_page != INV_3DVIEW_PAGE && ACTIVE[MID_CONTEXT]) {
232         view360_restore_inventory();
233     }
234     view360_message_obscured = ACTIVE[MID_CONTEXT];
235     if (ACTIVE[MID_CONTEXT] && player_struct.hardwarez[CPTRIP(SENS_HARD_TRIPLE)] == 1) {
236         short update = *tmd_ticks / CIT_CYCLE;
237         if (dirty_inv_canvas && update == view360_last_update && (full_game_3d || !rendered_inv_fullscrn)) {
238             short basex = INVENTORY_PANEL_X;
239             short basey = INVENTORY_PANEL_Y + INVENTORY_PANEL_HEIGHT;
240             LGRect r;
241             char buf[sizeof(update_string)];
242             short w, h;
243             if (strlen(update_string) + 1 >= sizeof(update_string)) {
244                 opengl_end_sensaround();
245                 return;
246             }
247             if (update_string[0] == '\0')
248                 get_string(REF_STR_View360Update, buf, sizeof(buf));
249             else
250                 strcpy(buf, ".");
251             if (full_game_3d) {
252                 basex = 0;
253                 basey = INV_FULL_HT;
254                 gr_push_canvas(&inv_view360_canvas);
255             } else {
256                 gr_push_canvas(grd_screen_canvas);
257             }
258             gr_set_fcolor(WHITE);
259             gr_set_font(ResLock(RES_tinyTechFont));
260             gr_string_size(update_string, &w, &h);
261             RECT_FILL(&r, basex + w + 2, basey - h - 2, basex + w + 2 + gr_string_width(buf), basey - h - 2 + h);
262             if (!full_game_3d)
263                 uiHideMouse(&r);
264             res_draw_text(RES_tinyTechFont, buf, r.ul.x, r.ul.y);
265             if (!full_game_3d)
266                 uiShowMouse(&r);
267             ResUnlock(RES_tinyTechFont);
268             gr_pop_canvas();
269             strcat(update_string, buf);
270 
271             opengl_end_sensaround();
272             return;
273         }
274         update_string[0] = '\0';
275         view360_last_update = update;
276         rendered_inv_fullscrn = FALSE;
277     }
278     if (ACTIVE[MID_CONTEXT]) {
279         dirty_inv_canvas = TRUE;
280     }
281 
282     // Render the 360 view scenes.
283     view360_is_rendering = TRUE;
284     for (uint8_t i = 0; i < NUM_360_CONTEXTS; i++)
285         if (ACTIVE[i]) {
286             fr_rend(CONTEXT[i]);
287             if (full_game_3d) {
288 #ifdef STEREO_SUPPORT
289                 if (convert_use_mode == 5)
290                     full_visible = VISIBLE_BIT(i);
291                 else
292 #endif
293                     full_visible |= VISIBLE_BIT(i);
294             }
295             on = TRUE;
296         }
297     view360_is_rendering = FALSE;
298     view360_render_on = on;
299 
300     if (on == !(player_struct.hardwarez_status[HARDWARE_360] & WARE_ON))
301         use_ware(WARE_HARD, HARDWARE_360);
302 
303     opengl_end_sensaround();
304 }
305 
306 // ------------------
307 // MFD FUNC FOR VIEWS
308 // ------------------
309 
mfd_view360_expose(MFD * mfd,ubyte control)310 void mfd_view360_expose(MFD *mfd, ubyte control) { ACTIVE[mfd->id] = control; }
311 
312 // --------------------------
313 // WARE STARTUP/SHUTDOWN CODE
314 // --------------------------
315 
316 #define MODE_MASK 0xC0u
317 #define MODE_SHF 6u
318 #define VIEW_MODE(s) (((s)&MODE_MASK) >> MODE_SHF)
319 #define VIEW_MODE_SET(s, v) ((s) = ((s) & ~MODE_MASK) | ((v) << MODE_SHF))
320 
view360_turnon(uchar visible,uchar real_stop)321 void view360_turnon(uchar visible, uchar real_stop) {
322     uint8_t s = player_struct.hardwarez_status[HARDWARE_360];
323 
324     if (visible) {
325         view360_setup_mode(VIEW_MODE(s));
326         chg_set_flg(_current_3d_flag);
327     }
328     view360_render_on = TRUE;
329 }
330 
view360_turnoff(uchar visible,uchar real_stop)331 void view360_turnoff(uchar visible, uchar real_stop) {
332     // restore inventory
333     if (visible) {
334         if (real_stop && ACTIVE[MID_CONTEXT]) {
335             inventory_page = inv_last_page;
336             if (inventory_page < 0)
337                 inventory_page = 0;
338             if (full_game_3d) {
339                 full_visible &= ~VISIBLE_BIT(MID_CONTEXT);
340             } else {
341                 view360_restore_inventory();
342                 inventory_clear();
343                 inventory_draw();
344             }
345         }
346         // empty the mfd slot
347         if ((ACTIVE[LEFT_CONTEXT] || ACTIVE[RIGHT_CONTEXT]) && real_stop)
348             mfd_notify_func(MFD_EMPTY_FUNC, MFD_INFO_SLOT, TRUE, MFD_EMPTY, FALSE);
349         // turn off all views
350         for (uint8_t i = 0; i < NUM_360_CONTEXTS; i++) {
351             ACTIVE[i] = false;
352         }
353         if (real_stop)
354             play_digi_fx(SFX_VIDEO_DOWN, 1);
355     }
356     view360_render_on = view360_message_obscured = FALSE;
357 }
358 
view360_check()359 bool view360_check() {
360     extern uchar hack_takeover;
361     if (hack_takeover)
362         return false;
363     return true;
364 }
365