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