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