1 /*
2
3 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 and the "Aleph One" developers.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 This license is contained in the file "COPYING",
17 which is included with this source code; it is available online at
18 http://www.gnu.org/licenses/gpl.html
19
20 May 22, 2000 (Loren Petrich)
21
22 The work of the view controller.
23
24 Oct 13, 2000 (Loren Petrich)
25 Using the STL for the landscape-option-data container
26
27 Nov 29, 2000 (Loren Petrich):
28 Added making view-folding effect optional
29 Added making teleport static/fold effect optional
30
31 Dec 17, 2000 (Loren Petrich:
32 Added teleport-sound control for Marathon 1 compatibility
33 */
34
35 #include <vector>
36 #include <string.h>
37 #include "cseries.h"
38 #include "world.h"
39 #include "SoundManager.h"
40 #include "shell.h"
41 #include "screen.h"
42 #include "ViewControl.h"
43 #include "InfoTree.h"
44
45
46 struct view_settings_definition {
47 bool MapActive;
48 bool DoFoldEffect;
49 bool DoStaticEffect;
50 bool DoInterlevelTeleportInEffects;
51 bool DoInterlevelTeleportOutEffects;
52 };
53
54 // Defaults:
55 struct view_settings_definition view_settings = {
56 true, // overhead map is active
57 true, // do the view folding effect (stretch horizontally, squeeze vertically) when teleporting,
58 true, // also do the static effect / folding effect on viewed teleported objects
59 true, // do all effects (and sounds) teleporting into the level
60 true // do all effects (and sounds) teleporting out of the level
61 };
62
63 // Accessors:
View_MapActive()64 bool View_MapActive() {return view_settings.MapActive;}
View_DoFoldEffect()65 bool View_DoFoldEffect() {return view_settings.DoFoldEffect;}
View_DoStaticEffect()66 bool View_DoStaticEffect() {return view_settings.DoStaticEffect;}
View_DoInterlevelTeleportInEffects()67 bool View_DoInterlevelTeleportInEffects() { return view_settings.DoInterlevelTeleportInEffects; }
View_DoInterlevelTeleportOutEffects()68 bool View_DoInterlevelTeleportOutEffects() { return view_settings.DoInterlevelTeleportOutEffects; }
69
70
71 // This frame value means that a landscape option will be applied to any frame in a collection:
72 const int AnyFrame = -1;
73
74 // Field-of-view stuff with defaults:
75 struct FOV_settings_definition {
76 float Normal;
77 float ExtraVision;
78 float TunnelVision;
79 float ChangeRate; // this is 50 degrees/s
80 bool FixHorizontalNotVertical;
81 };
82
83 struct FOV_settings_definition FOV_settings = {
84 80,
85 130,
86 30,
87 1.66666667F, // this is 50 degrees/s
88 false
89 };
90
91 #define FOV_Normal FOV_settings.Normal
92 #define FOV_ExtraVision FOV_settings.ExtraVision
93 #define FOV_TunnelVision FOV_settings.TunnelVision
94 #define FOV_ChangeRate FOV_settings.ChangeRate
95 #define FOV_FixHorizontalNotVertical FOV_settings.FixHorizontalNotVertical
96
97
98 static FontSpecifier OnScreenFont = {"Monaco", 12, styleNormal, 0, "mono"};
99 static FontSpecifier LoadedOnScreenFont = OnScreenFont;
100 static bool ScreenFontInited = false;
101 static short ScreenFontInitedSize = -1;
102
103 // Accessors:
View_FOV_Normal()104 float View_FOV_Normal() {return FOV_Normal;}
View_FOV_ExtraVision()105 float View_FOV_ExtraVision() {return FOV_ExtraVision;}
View_FOV_TunnelVision()106 float View_FOV_TunnelVision() {return FOV_TunnelVision;}
107
GetOnScreenFont()108 FontSpecifier& GetOnScreenFont()
109 {
110 short NeededSize = OnScreenFont.Size;
111 switch (get_screen_mode()->hud_scale_level) {
112 case 1:
113 if(MainScreenLogicalHeight() > 960) NeededSize *= 2;
114 break;
115 case 2:
116 if(MainScreenLogicalHeight() > 480)
117 NeededSize = NeededSize * MainScreenLogicalHeight() / 480;
118 break;
119 }
120 if (ScreenFontInitedSize != NeededSize) {
121 LoadedOnScreenFont = OnScreenFont;
122 LoadedOnScreenFont.Size = NeededSize;
123 if (ScreenFontInited)
124 LoadedOnScreenFont.Update();
125 else {
126 LoadedOnScreenFont.Init();
127 ScreenFontInited = true;
128 }
129 ScreenFontInitedSize = NeededSize;
130 }
131 return LoadedOnScreenFont;
132 }
133
134 // Move field-of-view value closer to some target value:
View_AdjustFOV(float & FOV,float FOV_Target)135 bool View_AdjustFOV(float& FOV, float FOV_Target)
136 {
137 bool Changed = false;
138 if (FOV_ChangeRate < 0) FOV_ChangeRate *= -1;
139
140 if (FOV > FOV_Target)
141 {
142 FOV -= FOV_ChangeRate;
143 FOV = MAX(FOV,FOV_Target);
144 Changed = true;
145 }
146 else if (FOV < FOV_Target)
147 {
148 FOV += FOV_ChangeRate;
149 FOV = MIN(FOV,FOV_Target);
150 Changed = true;
151 }
152
153 return Changed;
154 }
155
156 // Indicates whether to fix the horizontal or the vertical field-of-view angle
157 // (default: fix vertical FOV angle)
View_FOV_FixHorizontalNotVertical()158 bool View_FOV_FixHorizontalNotVertical() {return get_screen_mode()->fix_h_not_v;}
159
160 // Landscape stuff: this is for being able to return a pointer to the default one
161 static LandscapeOptions DefaultLandscape;
162
163
164 // Store landscape stuff as a vector member
165 struct LandscapeOptionsEntry
166 {
167 // Which frame to apply to (default: 0, since there is usually only one)
168 short Frame;
169
170 // Make a member for more convenient access
171 LandscapeOptions OptionsData;
172
LandscapeOptionsEntryLandscapeOptionsEntry173 LandscapeOptionsEntry(): Frame(0) {}
174 };
175
176 // Separate landscape-texture sequence lists for each collection ID,
177 // to speed up searching.
178 static vector<LandscapeOptionsEntry> LOList[NUMBER_OF_COLLECTIONS];
179
180 // Deletes a collection's landscape-texture sequences
LODelete(int c)181 static void LODelete(int c)
182 {
183 LOList[c].clear();
184 }
185
186 // Deletes all of them
LODeleteAll()187 static void LODeleteAll()
188 {
189 for (int c=0; c<NUMBER_OF_COLLECTIONS; c++) LODelete(c);
190 }
191
192
View_GetLandscapeOptions(shape_descriptor Desc)193 LandscapeOptions *View_GetLandscapeOptions(shape_descriptor Desc)
194 {
195 // Pull out frame and collection ID's:
196 short Frame = GET_DESCRIPTOR_SHAPE(Desc);
197 short CollCT = GET_DESCRIPTOR_COLLECTION(Desc);
198 short Collection = GET_COLLECTION(CollCT);
199
200 vector<LandscapeOptionsEntry>& LOL = LOList[Collection];
201 for (vector<LandscapeOptionsEntry>::iterator LOIter = LOL.begin(); LOIter < LOL.end(); LOIter++)
202 {
203 if (LOIter->Frame == Frame || LOIter->Frame == AnyFrame)
204 {
205 // Get a pointer from the iterator in order to return it
206 return &(LOIter->OptionsData);
207 }
208 }
209
210 // Return the default if no matching entry was found
211 return &DefaultLandscape;
212 }
213
214
215 struct FOV_settings_definition *original_FOV_settings = NULL;
216 struct view_settings_definition *original_view_settings = NULL;
217 static FontSpecifier original_OnScreenFont = OnScreenFont;
218
reset_mml_view()219 void reset_mml_view()
220 {
221 if (original_view_settings) {
222 view_settings = *original_view_settings;
223 free(original_view_settings);
224 original_view_settings = NULL;
225 }
226
227 // reset on-screen font and update if needed
228 OnScreenFont = original_OnScreenFont;
229 ScreenFontInitedSize = -1;
230
231 if (original_FOV_settings) {
232 FOV_settings = *original_FOV_settings;
233 free(original_FOV_settings);
234 original_FOV_settings = NULL;
235 }
236 }
237
parse_mml_view(const InfoTree & root)238 void parse_mml_view(const InfoTree& root)
239 {
240 // backup old values first
241 if (!original_view_settings) {
242 original_view_settings = (struct view_settings_definition *) malloc(sizeof(struct view_settings_definition));
243 assert(original_view_settings);
244 *original_view_settings = view_settings;
245 }
246
247 if (!original_FOV_settings) {
248 original_FOV_settings = (struct FOV_settings_definition *) malloc(sizeof(struct FOV_settings_definition));
249 assert(original_FOV_settings);
250 *original_FOV_settings = FOV_settings;
251 }
252
253 root.read_attr("map", view_settings.MapActive);
254 root.read_attr("fold_effect", view_settings.DoFoldEffect);
255 root.read_attr("static_effect", view_settings.DoStaticEffect);
256 root.read_attr("interlevel_in_effects", view_settings.DoInterlevelTeleportInEffects);
257 root.read_attr("interlevel_out_effects", view_settings.DoInterlevelTeleportOutEffects);
258
259 BOOST_FOREACH(InfoTree font, root.children_named("font"))
260 {
261 font.read_font(OnScreenFont);
262 ScreenFontInitedSize = -1;
263 }
264
265 BOOST_FOREACH(InfoTree fov, root.children_named("fov"))
266 {
267 fov.read_attr_bounded<float>("normal", FOV_Normal, 0, 180);
268 fov.read_attr_bounded<float>("extra", FOV_ExtraVision, 0, 180);
269 fov.read_attr_bounded<float>("tunnel", FOV_TunnelVision, 0, 180);
270 fov.read_attr_bounded<float>("rate", FOV_ChangeRate, 0, 180);
271 fov.read_attr("fix_h_not_v", FOV_FixHorizontalNotVertical);
272 }
273 }
274
reset_mml_landscapes()275 void reset_mml_landscapes()
276 {
277 LODeleteAll();
278 }
279
parse_mml_landscapes(const InfoTree & root)280 void parse_mml_landscapes(const InfoTree& root)
281 {
282 BOOST_FOREACH(const InfoTree::value_type &v, root)
283 {
284 const std::string& name = v.first;
285 const InfoTree& child = v.second;
286 if (name == "clear")
287 {
288 int16 coll;
289 if (child.read_indexed("coll", coll, NUMBER_OF_COLLECTIONS))
290 LODelete(coll);
291 else
292 LODeleteAll();
293 }
294 else if (name == "landscape")
295 {
296 int16 coll;
297 if (!child.read_indexed("coll", coll, NUMBER_OF_COLLECTIONS))
298 continue;
299
300 int16 frame = AnyFrame;
301 child.read_indexed("frame", frame, MAXIMUM_SHAPES_PER_COLLECTION);
302
303 LandscapeOptions data = DefaultLandscape;
304 child.read_attr("horiz_exp", data.HorizExp);
305 child.read_attr("vert_exp", data.VertExp);
306 child.read_attr("vert_repeat", data.VertRepeat);
307 child.read_attr("ogl_asprat_exp", data.OGL_AspRatExp);
308 child.read_angle("azimuth", data.Azimuth);
309
310 // Check to see if a frame is already accounted for
311 bool found = false;
312 vector<LandscapeOptionsEntry>& LOL = LOList[coll];
313 for (vector<LandscapeOptionsEntry>::iterator LOIter = LOL.begin(); LOIter < LOL.end(); LOIter++)
314 {
315 if (LOIter->Frame == frame)
316 {
317 // Replace the data
318 LOIter->OptionsData = data;
319 found = true;
320 break;
321 }
322 }
323
324 // If not, then add a new frame entry
325 if (!found)
326 {
327 LandscapeOptionsEntry DataEntry;
328 DataEntry.Frame = frame;
329 DataEntry.OptionsData = data;
330 LOL.push_back(DataEntry);
331 }
332 }
333 }
334 }
335