• R/O
  • SSH
  • HTTPS

marathon: コミット


コミットメタ情報

リビジョン510 (tree)
日時2011-12-26 21:06:17
作者logue

ログメッセージ

公式版r4676とマージ。
・Luaが原因でクラッシュするのを防いだ
・使用されていない形態パッチのタグを無視
・使われていない形態パッチのテスクチャオプションを削除
・Luaのアクセサに、MonsterType.cannot_be_dropped, .major, .minorを追加
以下、日本語
・フォント読み込み処理とシステムフォントを読み込む処理が分かれていたのを統合
・キー設定画面で、画面の大きさよりもダイアログが大きくなってしまう問題を解消
・その他、訳文を変更。

変更サマリ

差分

--- marathon/trunk/Source_Files/Lua/lua_hud_objects.cpp (revision 509)
+++ marathon/trunk/Source_Files/Lua/lua_hud_objects.cpp (revision 510)
@@ -417,7 +417,7 @@
417417 char path[256] = "";
418418 lua_pushstring(L, "path");
419419 lua_gettable(L, 1);
420- if (!lua_isnil(L, -1))
420+ if (lua_isstring(L, -1))
421421 {
422422 strncpy(path, lua_tostring(L, -1), 256);
423423 path[255] = 0;
@@ -434,7 +434,7 @@
434434 char mask[256] = "";
435435 lua_pushstring(L, "mask");
436436 lua_gettable(L, 1);
437- if (!lua_isnil(L, -1))
437+ if (lua_isstring(L, -1))
438438 {
439439 strncpy(mask, lua_tostring(L, -1), 256);
440440 path[255] = 0;
@@ -772,6 +772,9 @@
772772
773773 int Lua_Font_Measure_Text(lua_State *L)
774774 {
775+ if (!lua_isstring(L, 2))
776+ luaL_error(L, "measure_text: incorrect argument type");
777+
775778 lua_pushnumber(L, Lua_Font::Object(L, 1)->TextWidth(lua_tostring(L, 2)));
776779 lua_pushnumber(L, Lua_Font::Object(L, 1)->LineSpacing);
777780 return 2;
@@ -779,6 +782,9 @@
779782
780783 int Lua_Font_Draw_Text(lua_State *L)
781784 {
785+ if (!lua_isstring(L, 2))
786+ luaL_error(L, "draw_text: incorrect argument type");
787+
782788 const char *str = lua_tostring(L, 2);
783789 float x = static_cast<float>(lua_tonumber(L, 3));
784790 float y = static_cast<float>(lua_tonumber(L, 4));
@@ -877,7 +883,7 @@
877883
878884 lua_pushstring(L, "file");
879885 lua_gettable(L, 1);
880- if (!lua_isnil(L, -1))
886+ if (lua_isstring(L, -1))
881887 {
882888 strncpy(f.File, lua_tostring(L, -1), FontSpecifier::NameSetLen);
883889 f.File[FontSpecifier::NameSetLen-1] = 0;
--- marathon/trunk/Source_Files/Lua/lua_monsters.cpp (revision 509)
+++ marathon/trunk/Source_Files/Lua/lua_monsters.cpp (revision 510)
@@ -249,6 +249,7 @@
249249 return index >= 0 && index < NUMBER_OF_MONSTER_TYPES;
250250 }
251251
252+
252253 static int Lua_MonsterType_Get_Class(lua_State *L) {
253254 monster_definition *definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
254255 Lua_MonsterClass::Push(L, definition->_class);
@@ -260,6 +261,15 @@
260261 return 1;
261262 }
262263
264+template<uint32 flag>
265+static int Lua_MonsterType_Get_Flag(lua_State* L)
266+{
267+ monster_definition* definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
268+ lua_pushboolean(L, definition->flags & flag);
269+ return 1;
270+}
271+
272+
263273 static int Lua_MonsterType_Get_Height(lua_State *L) {
264274 monster_definition *definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
265275 lua_pushnumber(L, (double) definition->height / WORLD_ONE);
@@ -348,6 +358,25 @@
348358 return 0;
349359 }
350360
361+template<uint32 flag>
362+static int Lua_MonsterType_Set_Flag(lua_State* L)
363+{
364+ if (!lua_isboolean(L, 2))
365+ return luaL_error(L, "monster flag: incorrect argument type");
366+
367+ monster_definition* definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
368+ if (lua_toboolean(L, 2))
369+ {
370+ definition->flags |= flag;
371+ }
372+ else
373+ {
374+ definition->flags &= ~flag;
375+ }
376+
377+ return 0;
378+}
379+
351380 static int Lua_MonsterType_Set_Item(lua_State *L) {
352381 int item_type = 0;
353382 if (lua_isnumber(L, 2))
@@ -453,6 +482,7 @@
453482 }
454483
455484 const luaL_reg Lua_MonsterType_Get[] = {
485+ {"cannot_be_dropped", Lua_MonsterType_Get_Flag<_monster_cannot_be_dropped>},
456486 {"class", Lua_MonsterType_Get_Class},
457487 {"enemies", Lua_MonsterType_Get_Enemies},
458488 {"friends", Lua_MonsterType_Get_Friends},
@@ -460,9 +490,11 @@
460490 {"immunities", Lua_MonsterType_Get_Immunities},
461491 {"impact_effect", Lua_MonsterType_Get_Impact_Effect},
462492 {"initial_count", Lua_MonsterType_Get_Initial_Count},
493+ {"major", Lua_MonsterType_Get_Flag<_monster_major>},
463494 {"maximum_count", Lua_MonsterType_Get_Maximum_Count},
464495 {"melee_impact_effect", Lua_MonsterType_Get_Melee_Impact_Effect},
465496 {"minimum_count", Lua_MonsterType_Get_Minimum_Count},
497+ {"minor", Lua_MonsterType_Get_Flag<_monster_minor>},
466498 {"item", Lua_MonsterType_Get_Item},
467499 {"radius", Lua_MonsterType_Get_Radius},
468500 {"random_chance", Lua_MonsterType_Get_Random_Chance},
@@ -473,11 +505,14 @@
473505 };
474506
475507 const luaL_reg Lua_MonsterType_Set[] = {
508+ {"cannot_be_dropped", Lua_MonsterType_Set_Flag<_monster_cannot_be_dropped>},
476509 {"class", Lua_MonsterType_Set_Class},
477510 {"initial_count", Lua_MonsterType_Set_Initial_Count},
478511 {"item", Lua_MonsterType_Set_Item},
512+ {"major", Lua_MonsterType_Set_Flag<_monster_major>},
479513 {"maximum_count", Lua_MonsterType_Set_Maximum_Count},
480514 {"minimum_count", Lua_MonsterType_Set_Minimum_Count},
515+ {"minor", Lua_MonsterType_Set_Flag<_monster_minor>},
481516 {"random_chance", Lua_MonsterType_Set_Random_Chance},
482517 {"random_location", Lua_MonsterType_Set_Random_Location},
483518 {"total_available", Lua_MonsterType_Set_Random_Count},
--- marathon/trunk/Source_Files/RenderOther/sdl_fonts.cpp (revision 509)
+++ marathon/trunk/Source_Files/RenderOther/sdl_fonts.cpp (revision 510)
@@ -237,8 +237,6 @@
237237 return info;
238238 }
239239 */
240-#include <iostream> // std::cout を使うのに必要
241-#include <boost/format.hpp> // boost::format を使うのに必要
242240 #ifdef HAVE_SDL_TTF
243241 static TTF_Font *load_ttf_font(const std::string& path, uint16 style, int16 size)
244242 {
@@ -259,53 +257,50 @@
259257 if (path == "mono")
260258 {
261259 // Japanese Font cannot render as embeded font.
262- FILE* fp = fopen( FONT_PATH, "r" );
263- if( fp ){
264- // Fonts.ttf is exists, Load this Font.
265- font = TTF_OpenFont(FONT_PATH, size);
266- fclose( fp );
267- }else{
268- // If Fonts.ttf is missing, Load from System Font
269- const string fontPath[] = {
260+ // If Fonts.ttf is missing, Load from System Font
261+ const string fontPath[] = {
262+ FONT_PATH,
270263 #if defined(__WIN32__)
271- // for Windows 7 (Meiryo Bold)
272- "c:/Windows/winsxs/x86_microsoft-windows-f..truetype-meiryobold_31bf3856ad364e35_6.1.7600.16385_none_cd23f5e0d8f9c6fa/meiryob.ttc",
273- "c:/Windows/winsxs/amd64_microsoft-windows-f..truetype-meiryobold_31bf3856ad364e35_6.1.7600.16385_none_2942916491573830/meiryob.ttc",
274- // for Windows Vista
275- "c:/Windows/Fonts/meiryob.ttc",
276- // for less than Windows XP (MS Gothic)
277- "c:/windows/fonts/msgothic.ttc",
278- "c:/winnt/fonts/msgothic.ttc",
264+ // Path to the below Windows directory
265+ // for Windows 7 (Meiryo Bold)
266+ "C:/Windows/winsxs/x86_microsoft-windows-f..truetype-meiryobold_31bf3856ad364e35_6.1.7600.16385_none_cd23f5e0d8f9c6fa/meiryob.ttc",
267+ "C:/Windows/winsxs/amd64_microsoft-windows-f..truetype-meiryobold_31bf3856ad364e35_6.1.7600.16385_none_2942916491573830/meiryob.ttc",
268+ // for Windows Vista
269+ "C:/Windows/Fonts/meiryob.ttc",
270+ // for less than Windows XP (MS Gothic)
271+ "C:/Windows/fonts/msgothic.ttc",
279272 #elif defined(__MACOS__)
280- // for MacOS (Hiragino Kaku Gothic Pro W6)
281- "/System/Library/Fonts/Hiragino Kaku Gothic Pro W6.otf",
282- "/System/Library/Fonts/Cache/HiraginoKakuGothicProNW6.otf"
273+ // for MacOS (Hiragino Kaku Gothic Pro W6)
274+ "/System/Library/Fonts/Hiragino Kaku Gothic Pro W6.otf",
275+ "/System/Library/Fonts/Cache/HiraginoKakuGothicProNW6.otf" // for iOS
283276 #else
284- // for Linux
285- "/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf",
286- "/usr/X11R6/lib/X11/fonts/TrueType/VL-Gothic-Regular.ttf",
287- "/usr/X11/lib/X11/fonts/truetype/VL-Gothic-Regular.ttf",
288- "/usr/share/fonts/ja-ipafonts/ipag.ttc",
289-
290- "/usr/share/fonts/TrueType/mika.ttf",
291- "/usr/X11R6/lib/X11/fonts/TrueType/mika.ttf",
292- "/usr/X11R6/lib/X11/fonts/truetype/sazanami-gothic.ttf",
293- "/usr/X11/lib/X11/fonts/truetype/sazanami-gothic.ttf",
294- "/usr/share/fonts/TrueType/sazanami-gothic.ttf",
295- "/usr/X11R6/lib/X11/fonts/TrueType/sazanami-gothic.ttf",
296- "/usr/share/fonts/truetype/sazanami-gothic.ttf",
297- "/usr/share/fonts/TrueType/FS-Gothic-gs.ttf",
298- "/usr/X11R6/lib/X11/fonts/TrueType/FS-Gothic.ttf",
299- "/usr/share/fonts/TrueType/gt200001.ttf",
300- "/usr/X11R6/lib/X11/fonts/TrueType/gt200001.ttf",
277+ // for Linux
278+ "/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf",
279+ "/usr/X11R6/lib/X11/fonts/TrueType/VL-Gothic-Regular.ttf",
280+ "/usr/X11/lib/X11/fonts/truetype/VL-Gothic-Regular.ttf",
281+
282+ "/usr/share/fonts/truetype/takao/TakaoExGothic.ttf"
283+ "/usr/share/fonts/ja-ipafonts/ipag.ttc",
284+
285+ "/usr/share/fonts/TrueType/mika.ttf",
286+ "/usr/X11R6/lib/X11/fonts/TrueType/mika.ttf",
287+ "/usr/X11R6/lib/X11/fonts/truetype/sazanami-gothic.ttf",
288+ "/usr/X11/lib/X11/fonts/truetype/sazanami-gothic.ttf",
289+ "/usr/share/fonts/TrueType/sazanami-gothic.ttf",
290+ "/usr/X11R6/lib/X11/fonts/TrueType/sazanami-gothic.ttf",
291+ "/usr/share/fonts/truetype/sazanami-gothic.ttf",
292+ "/usr/share/fonts/TrueType/FS-Gothic-gs.ttf",
293+ "/usr/X11R6/lib/X11/fonts/TrueType/FS-Gothic.ttf",
294+ "/usr/share/fonts/TrueType/gt200001.ttf",
295+ "/usr/X11R6/lib/X11/fonts/TrueType/gt200001.ttf",
301296 #endif
302- };
297+ };
303298
304- for ( int i=0; !fontPath[i].empty(); i++ ) {
305- font = TTF_OpenFont(fontPath[i].c_str(), size);
306- if ( !font ) { continue; }
307- else { break; }
308- }
299+ for ( int i=0; !fontPath[i].empty(); i++ ) {
300+ const char* file = fontPath[i].c_str();
301+ font = TTF_OpenFont(file , size);
302+ if ( !font ) { continue; }
303+ else { break; }
309304 }
310305 if( !font ){
311306 font = TTF_OpenFontRW(SDL_RWFromConstMem(aleph_sans_mono_bold, sizeof(aleph_sans_mono_bold)), 0, size);
--- marathon/trunk/Source_Files/RenderMain/OGL_Subst_Texture_Def.cpp (revision 509)
+++ marathon/trunk/Source_Files/RenderMain/OGL_Subst_Texture_Def.cpp (revision 510)
@@ -256,21 +256,35 @@
256256 logWarning("Ignoring deprecated image_scale tag");
257257 return true;
258258 }
259+ else if (StringsEqual(Tag, "x_offset"))
260+ {
261+ logWarning("Ignoring deprecated x_offset tag");
262+ return true;
263+ }
264+ else if (StringsEqual(Tag, "y_offset"))
265+ {
266+ logWarning("Ignoring deprecated y_offset tag");
267+ return true;
268+ }
259269 else if (StringsEqual(Tag,"shape_width"))
260270 {
261- return ReadInt16Value(Value,Data.shape_width);
271+ logWarning("Ignoring deprecated shape_width tag");
272+ return true;
262273 }
263274 else if (StringsEqual(Tag,"shape_height"))
264275 {
265- return ReadInt16Value(Value,Data.shape_height);
276+ logWarning("Ignoring deprecated shape_height tag");
277+ return true;
266278 }
267279 else if (StringsEqual(Tag,"offset_x"))
268280 {
269- return ReadInt16Value(Value,Data.offset_x);
281+ logWarning("Ignoring deprecated offset_x tag");
282+ return true;
270283 }
271284 else if (StringsEqual(Tag,"offset_y"))
272285 {
273- return ReadInt16Value(Value,Data.offset_y);
286+ logWarning("Ignoring deprecated offset_y tag");
287+ return true;
274288 }
275289 else if (StringsEqual(Tag,"actual_height"))
276290 {
@@ -401,26 +415,6 @@
401415 it->second.GlowBlend = Data.GlowBlend;
402416 }
403417
404- if (Attributes.count("shape_width"))
405- {
406- it->second.shape_width = Data.shape_width;
407- }
408-
409- if (Attributes.count("shape_height"))
410- {
411- it->second.shape_height = Data.shape_height;
412- }
413-
414- if (Attributes.count("offset_x"))
415- {
416- it->second.offset_x = Data.offset_x;
417- }
418-
419- if (Attributes.count("offset_y"))
420- {
421- it->second.offset_y = Data.offset_y;
422- }
423-
424418 if (Attributes.count("actual_height"))
425419 {
426420 it->second.actual_height = Data.actual_height;
--- marathon/trunk/Source_Files/RenderMain/shapes.cpp (revision 509)
+++ marathon/trunk/Source_Files/RenderMain/shapes.cpp (revision 510)
@@ -1,3031 +1,2987 @@
1-/*
2-SHAPES.C
3-
4- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5- and the "Aleph One" developers.
6-
7- This program is free software; you can redistribute it and/or modify
8- it under the terms of the GNU General Public License as published by
9- the Free Software Foundation; either version 3 of the License, or
10- (at your option) any later version.
11-
12- This program is distributed in the hope that it will be useful,
13- but WITHOUT ANY WARRANTY; without even the implied warranty of
14- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15- GNU General Public License for more details.
16-
17- This license is contained in the file "COPYING",
18- which is included with this source code; it is available online at
19- http://www.gnu.org/licenses/gpl.html
20-
21-Saturday, September 4, 1993 9:26:41 AM
22-
23-Thursday, May 19, 1994 9:06:28 AM
24- unification of wall and object shapes complete, new shading table builder.
25-Wednesday, June 22, 1994 11:55:07 PM
26- we now read data from alainユs shape extractor.
27-Saturday, July 9, 1994 3:22:11 PM
28- lightening_table removed; we now build darkening tables on a collection-by-collection basis
29- (one 8k darkening table per clut permutation of the given collection)
30-Monday, October 3, 1994 4:17:15 PM (Jason)
31- compressed or uncompressed collection resources
32-Friday, June 16, 1995 11:34:08 AM (Jason)
33- self-luminescent colors
34-
35-Jan 30, 2000 (Loren Petrich):
36- Changed "new" to "_new" to make data structures more C++-friendly
37- Did some typecasts
38-
39-Feb 3, 2000 (Loren Petrich):
40- Changed _collection_madd to _collection_vacbob (later changed all "vacbob"'s to "civilian_fusion"'s)
41-
42-Feb 4, 2000 (Loren Petrich):
43- Changed halt() to assert(false) for better debugging
44-
45-Feb 12, 2000 (Loren Petrich):
46- Set up a fallback strategy for the colors;
47- when there are more colors in all the tables than there are in the general color table,
48- then look for the nearest one.
49-
50-Feb 24, 2000 (Loren Petrich):
51- Added get_number_of_collection_frames(), so as to assist in wall-texture error checking
52-
53-Mar 14, 2000 (Loren Petrich):
54- Added accessors for number of bitmaps and which bitmap index for a frame index;
55- these will be useful for OpenGL rendering
56-
57-Mar 23, 2000 (Loren Petrich):
58- Made infravision tinting more generic and reassignable
59-
60-Aug 12, 2000 (Loren Petrich):
61- Using object-oriented file handler
62-
63-Aug 14, 2000 (Loren Petrich):
64- Turned collection and shading-table handles into pointers,
65- because handles are needlessly MacOS-specific,
66- and because these are variable-format objects.
67-
68-Aug 26, 2000 (Loren Petrich):
69- Moved get_default_shapes_spec() to preprocess_map_mac.c
70-
71-Sept 2, 2000 (Loren Petrich):
72- Added shapes-file unpacking.
73-
74-Jan 17, 2001 (Loren Petrich):
75- Added support for offsets for OpenGL-rendered substitute textures
76-*/
77-
78-/*
79-//gracefully handle out-of-memory conditions when loading shapes. it will happen.
80-//get_shape_descriptors() needs to look at high-level instead of low-level shapes when fetching scenery instead of walls/ceilings/floors
81-//get_shape_information() is called often, and is quite slow
82-//it is possible to have more than 255 low-level shapes in a collection, which means the existing shape_descriptor is too small
83-//must build different shading tables for each collection (even in 8-bit, for alternate color tables)
84-*/
85-
86-#include "cseries.h"
87-
88-#include <stdio.h>
89-#include <stdlib.h>
90-#include <string.h>
91-
92-#include "shell.h"
93-#include "render.h"
94-#include "interface.h"
95-#include "collection_definition.h"
96-#include "screen.h"
97-#include "game_errors.h"
98-#include "FileHandler.h"
99-#include "progress.h"
100-
101-#include "map.h"
102-
103-// LP addition: OpenGL support
104-#include "OGL_Render.h"
105-#include "OGL_LoadScreen.h"
106-
107-// LP addition: infravision XML setup needs colors
108-#include "ColorParser.h"
109-
110-#include "Packing.h"
111-#include "SW_Texture_Extras.h"
112-
113-#include <SDL_rwops.h>
114-#include <memory>
115-
116-#include <boost/shared_ptr.hpp>
117-
118-#include "Plugins.h"
119-
120-#ifdef env68k
121-#pragma segment shell
122-#endif
123-
124-/* ---------- constants */
125-
126-#define iWHITE 1
127-#ifdef SCREAMING_METAL
128-#define iBLACK 255
129-#else
130-#define iBLACK 18
131-#endif
132-
133-/* each collection has a tint table which (fully) tints the clut of that collection to whatever it
134- looks like through the light enhancement goggles */
135-#define NUMBER_OF_TINT_TABLES 1
136-
137-// Moved from shapes_macintosh.c:
138-
139-// Possibly of historical interest:
140-// #define COLLECTIONS_RESOURCE_BASE 128
141-// #define COLLECTIONS_RESOURCE_BASE16 1128
142-
143-enum /* collection status */
144-{
145- markNONE,
146- markLOAD= 1,
147- markUNLOAD= 2,
148- markSTRIP= 4 /* we donユt want bitmaps, just high/low-level shape data */,
149- markPATCHED = 8 /* force re-load */
150-};
151-
152-enum /* flags */
153-{
154- _collection_is_stripped= 0x0001
155-};
156-
157-/* ---------- macros */
158-
159-// LP: fake portable-files stuff
160-#ifdef mac
161-inline short memory_error() {return MemError();}
162-#else
163-inline short memory_error() {return 0;}
164-#endif
165-
166-/* ---------- structures */
167-
168-/* ---------- globals */
169-
170-extern SDL_Surface* world_pixels;
171-
172-#include "shape_definitions.h"
173-
174-static pixel16 *global_shading_table16= (pixel16 *) NULL;
175-static pixel32 *global_shading_table32= (pixel32 *) NULL;
176-
177-short number_of_shading_tables, shading_table_fractional_bits, shading_table_size;
178-
179-// LP addition: opened-shapes-file object
180-static OpenedFile ShapesFile;
181-static OpenedResourceFile M1ShapesFile;
182-static bool m1_shapes;
183-
184-/* ---------- private prototypes */
185-
186-static void update_color_environment(bool is_opengl);
187-static short find_or_add_color(struct rgb_color_value *color, struct rgb_color_value *colors, short *color_count, bool update_flags);
188-static void _change_clut(void (*change_clut_proc)(struct color_table *color_table), struct rgb_color_value *colors, short color_count);
189-
190-static void build_shading_tables8(struct rgb_color_value *colors, short color_count, pixel8 *shading_tables);
191-static void build_shading_tables16(struct rgb_color_value *colors, short color_count, pixel16 *shading_tables, byte *remapping_table, bool is_opengl);
192-static void build_shading_tables32(struct rgb_color_value *colors, short color_count, pixel32 *shading_tables, byte *remapping_table, bool is_opengl);
193-static void build_global_shading_table16(void);
194-static void build_global_shading_table32(void);
195-
196-static bool get_next_color_run(struct rgb_color_value *colors, short color_count, short *start, short *count);
197-static bool new_color_run(struct rgb_color_value *_new, struct rgb_color_value *last);
198-
199-static int32 get_shading_table_size(short collection_code);
200-
201-static void build_collection_tinting_table(struct rgb_color_value *colors, short color_count, short collection_index, bool is_opengl);
202-static void build_tinting_table8(struct rgb_color_value *colors, short color_count, pixel8 *tint_table, short tint_start, short tint_count);
203-static void build_tinting_table16(struct rgb_color_value *colors, short color_count, pixel16 *tint_table, struct rgb_color *tint_color);
204-static void build_tinting_table32(struct rgb_color_value *colors, short color_count, pixel32 *tint_table, struct rgb_color *tint_color, bool is_opengl);
205-
206-static void precalculate_bit_depth_constants(void);
207-
208-static bool collection_loaded(struct collection_header *header);
209-static void unload_collection(struct collection_header *header);
210-static void unlock_collection(struct collection_header *header);
211-static void lock_collection(struct collection_header *header);
212-static bool load_collection(short collection_index, bool strip);
213-#ifdef mac
214-static byte *unpack_collection(byte *collection, int32 length, bool strip);
215-#endif
216-
217-static void shutdown_shape_handler(void);
218-static void close_shapes_file(void);
219-
220-#ifdef mac
221-static byte *read_object_from_file(OpenedFile& OFile, int32 offset, int32 length);
222-#endif
223-
224-// static byte *make_stripped_collection(byte *collection);
225-
226-/* --------- collection accessor prototypes */
227-
228-// Modified to return NULL for unloaded collections and out-of-range indices for collection contents.
229-// This is to allow for more graceful degradation.
230-
231-static struct collection_header *get_collection_header(short collection_index);
232-/*static*/ struct collection_definition *get_collection_definition(short collection_index);
233-static void *get_collection_shading_tables(short collection_index, short clut_index);
234-static void *get_collection_tint_tables(short collection_index, short tint_index);
235-static struct rgb_color_value *get_collection_colors(short collection_index, short clut_number);
236-static struct high_level_shape_definition *get_high_level_shape_definition(short collection_index, short high_level_shape_index);
237-static struct bitmap_definition *get_bitmap_definition(short collection_index, short bitmap_index);
238-
239-
240-#include <SDL_endian.h>
241-#include "byte_swapping.h"
242-
243-/*
244- * Initialize shapes handling
245- */
246-
247-static void initialize_pixmap_handler()
248-{
249- // nothing to do
250-}
251-
252-
253-/*
254- * Convert shape to surface
255- */
256-
257-// ZZZ extension: pass out (if non-NULL) a pointer to a block of pixel data -
258-// caller should free() that storage after freeing the returned surface.
259-// Only needed for RLE-encoded shapes.
260-// Note that default arguments are used to make this function
261-// source-code compatible with existing usage.
262-// Note also that inShrinkImage currently only applies to RLE shapes.
263-SDL_Surface *get_shape_surface(int shape, int inCollection, byte** outPointerToPixelData, float inIllumination, bool inShrinkImage)
264-{
265- // Get shape information
266- int collection_index = GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(shape));
267- int clut_index = GET_COLLECTION_CLUT(GET_DESCRIPTOR_COLLECTION(shape));
268- int low_level_shape_index = GET_DESCRIPTOR_SHAPE(shape);
269-
270- if(inCollection != NONE) {
271- collection_index = GET_COLLECTION(inCollection);
272- clut_index = GET_COLLECTION_CLUT(inCollection);
273- low_level_shape_index = shape;
274- }
275-
276- struct collection_definition *collection = get_collection_definition(collection_index);
277- struct low_level_shape_definition *low_level_shape = get_low_level_shape_definition(collection_index, low_level_shape_index);
278- if (!low_level_shape) return NULL;
279- struct bitmap_definition *bitmap;
280- SDL_Color colors[256];
281-
282- if(inIllumination >= 0) {
283- assert(inIllumination <= 1.0f);
284-
285- // ZZZ: get shading tables to use instead of CLUT, if requested
286- void* shading_tables_as_void;
287- extended_get_shape_bitmap_and_shading_table(BUILD_COLLECTION(collection_index, clut_index), low_level_shape_index,
288- &bitmap, &shading_tables_as_void, _shading_normal);
289- if (!bitmap) return NULL;
290-
291- switch(bit_depth) {
292- case 16:
293- {
294- uint16* shading_tables = (uint16*) shading_tables_as_void;
295- shading_tables += 256 * (int)(inIllumination * (number_of_shading_tables - 1));
296-
297- // Extract color table - ZZZ change to use shading table rather than CLUT. Hope it works.
298-
299- SDL_PixelFormat *fmt = &pixel_format_16;
300- for (int i = 0; i < 256; i++) {
301- SDL_GetRGB(shading_tables[i], fmt, &colors[i].r, &colors[i].g, &colors[i].b);
302- }
303- }
304- break;
305-
306- case 32:
307- {
308- uint32* shading_tables = (uint32*) shading_tables_as_void;
309- shading_tables += 256 * (int)(inIllumination * (number_of_shading_tables - 1));
310-
311- // Extract color table - ZZZ change to use shading table rather than CLUT. Hope it works.
312- for(int i = 0; i < 256; i++) {
313- colors[i].r = RED32(shading_tables[i]);
314- colors[i].g = GREEN32(shading_tables[i]);
315- colors[i].b = BLUE32(shading_tables[i]);
316- }
317- }
318- break;
319-
320- default:
321- vhalt("oops, bit_depth not supported for get_shape_surface with illumination\n");
322- break;
323- }
324-
325- } // inIllumination >= 0
326- else { // inIllumination < 0
327- bitmap = get_bitmap_definition(collection_index, low_level_shape->bitmap_index);
328- if(!bitmap) return NULL;
329-
330- // Extract color table
331- int num_colors = collection->color_count - NUMBER_OF_PRIVATE_COLORS;
332- rgb_color_value *src_colors = get_collection_colors(collection_index, clut_index) + NUMBER_OF_PRIVATE_COLORS;
333- for (int i=0; i<num_colors; i++) {
334- int idx = src_colors[i].value;
335- colors[idx].r = src_colors[i].red >> 8;
336- colors[idx].g = src_colors[i].green >> 8;
337- colors[idx].b = src_colors[i].blue >> 8;
338- }
339- } // inIllumination < 0
340-
341-
342- SDL_Surface *s = NULL;
343- if (bitmap->bytes_per_row == NONE) {
344-
345- // ZZZ: process RLE-encoded shape
346-
347- // Allocate storage for un-RLE'd pixels
348- uint32 theNumberOfStorageBytes = bitmap->width * bitmap->height * sizeof(byte);
349- byte* pixel_storage = (byte*) malloc(theNumberOfStorageBytes);
350- memset(pixel_storage, 0, theNumberOfStorageBytes);
351-
352- // Here, a "run" is a row or column. An "element" is a single pixel's data.
353- // We always go forward through the source data. Thus, the offsets for where the next run
354- // or element goes into the destination data area change depending on the circumstances.
355- int16 theNumRuns;
356- int16 theNumElementsPerRun;
357- int16 theDestDataNextRunOffset;
358- int16 theDestDataNextElementOffset;
359-
360- // Is this row-major or column-major?
361- if(bitmap->flags & _COLUMN_ORDER_BIT) {
362- theNumRuns = bitmap->width;
363- theNumElementsPerRun = bitmap->height;
364- theDestDataNextRunOffset = (low_level_shape->flags & _X_MIRRORED_BIT) ? -1 : 1;
365- theDestDataNextElementOffset = (low_level_shape->flags & _Y_MIRRORED_BIT) ? -bitmap->width : bitmap->width;
366- }
367- else {
368- theNumRuns = bitmap->height;
369- theNumElementsPerRun = bitmap->width;
370- theDestDataNextElementOffset = (low_level_shape->flags & _X_MIRRORED_BIT) ? -1 : 1;
371- theDestDataNextRunOffset = (low_level_shape->flags & _Y_MIRRORED_BIT) ? -bitmap->width : bitmap->width;
372- }
373-
374- // Figure out where our first byte will be written
375- byte* theDestDataStartAddress = pixel_storage;
376-
377- if(low_level_shape->flags & _X_MIRRORED_BIT)
378- theDestDataStartAddress += bitmap->width - 1;
379-
380- if(low_level_shape->flags & _Y_MIRRORED_BIT)
381- theDestDataStartAddress += bitmap->width * (bitmap->height - 1);
382-
383- // Walk through runs, un-RLE'ing as we go
384- for(int run = 0; run < theNumRuns; run++) {
385- uint16* theLengthData = (uint16*) bitmap->row_addresses[run];
386- uint16 theFirstOpaquePixelElement = SDL_SwapBE16(theLengthData[0]);
387- uint16 theFirstTransparentAfterOpaquePixelElement = SDL_SwapBE16(theLengthData[1]);
388- uint16 theNumberOfOpaquePixels = theFirstTransparentAfterOpaquePixelElement - theFirstOpaquePixelElement;
389-
390- byte* theOriginalPixelData = (byte*) &theLengthData[2];
391- byte* theUnpackedPixelData;
392-
393- theUnpackedPixelData = theDestDataStartAddress + run * theDestDataNextRunOffset
394- + theFirstOpaquePixelElement * theDestDataNextElementOffset;
395-
396- for(int i = 0; i < theNumberOfOpaquePixels; i++) {
397- assert(theUnpackedPixelData >= pixel_storage);
398- assert(theUnpackedPixelData < (pixel_storage + theNumberOfStorageBytes));
399- *theUnpackedPixelData = *theOriginalPixelData;
400- theUnpackedPixelData += theDestDataNextElementOffset;
401- theOriginalPixelData++;
402- }
403- }
404-
405- // Let's shrink the image if the user wants us to.
406- // We do this here by discarding every other pixel in each direction.
407- // Really, I guess there's probably a library out there that would do nice smoothing
408- // for us etc. that we should use here. I just want to hack something out now and run with it.
409- int image_width = bitmap->width;
410- int image_height = bitmap->height;
411-
412- if(inShrinkImage) {
413- int theLargerWidth = bitmap->width;
414- int theLargerHeight = bitmap->height;
415- byte* theLargerPixelStorage = pixel_storage;
416- int theSmallerWidth = theLargerWidth / 2 + theLargerWidth % 2;
417- int theSmallerHeight = theLargerHeight / 2 + theLargerHeight % 2;
418- byte* theSmallerPixelStorage = (byte*) malloc(theSmallerWidth * theSmallerHeight);
419-
420- for(int y = 0; y < theSmallerHeight; y++) {
421- for(int x = 0; x < theSmallerWidth; x++) {
422- theSmallerPixelStorage[y * theSmallerWidth + x] =
423- theLargerPixelStorage[(y * theLargerWidth + x) * 2];
424- }
425- }
426-
427- free(pixel_storage);
428-
429- pixel_storage = theSmallerPixelStorage;
430- image_width = theSmallerWidth;
431- image_height = theSmallerHeight;
432- }
433-
434- // Now we can create a surface from this new storage
435- s = SDL_CreateRGBSurfaceFrom(pixel_storage, image_width, image_height, 8, image_width, 0xff, 0xff, 0xff, 0xff);
436-
437- if(s != NULL) {
438- // If caller is not prepared to take this data, it's a coding error.
439- assert(outPointerToPixelData != NULL);
440- *outPointerToPixelData = pixel_storage;
441-
442- // Set color table
443- SDL_SetColors(s, colors, 0, 256);
444-
445- // Set transparent pixel (color #0)
446- SDL_SetColorKey(s, SDL_SRCCOLORKEY, 0);
447- }
448-
449- } else {
450- // Row-order shape, we can directly create a surface from it
451- if (collection->type == _wall_collection)
452- {
453- s = SDL_CreateRGBSurfaceFrom(bitmap->row_addresses[0], bitmap->height, bitmap->width, 8, bitmap->bytes_per_row, 0xff, 0xff, 0xff, 0xff);
454- }
455- else
456- {
457- s = SDL_CreateRGBSurfaceFrom(bitmap->row_addresses[0], bitmap->width, bitmap->height, 8, bitmap->bytes_per_row, 0xff, 0xff, 0xff, 0xff);
458- }
459- // ZZZ: caller should not dispose of any additional data - just free the surface.
460- if(outPointerToPixelData != NULL)
461- *outPointerToPixelData = NULL;
462-
463- if(s != NULL) {
464- // Set color table
465- SDL_SetColors(s, colors, 0, 256);
466- }
467- }
468-
469- return s;
470-}
471-
472-static void load_collection_definition(collection_definition* cd, SDL_RWops *p)
473-{
474- cd->version = SDL_ReadBE16(p);
475- cd->type = SDL_ReadBE16(p);
476- cd->flags = SDL_ReadBE16(p);
477- cd->color_count = SDL_ReadBE16(p);
478- cd->clut_count = SDL_ReadBE16(p);
479- cd->color_table_offset = SDL_ReadBE32(p);
480- cd->high_level_shape_count = SDL_ReadBE16(p);
481- cd->high_level_shape_offset_table_offset = SDL_ReadBE32(p);
482- cd->low_level_shape_count = SDL_ReadBE16(p);
483- cd->low_level_shape_offset_table_offset = SDL_ReadBE32(p);
484- cd->bitmap_count = SDL_ReadBE16(p);
485- cd->bitmap_offset_table_offset = SDL_ReadBE32(p);
486- cd->pixels_to_world = SDL_ReadBE16(p);
487- SDL_ReadBE32(p); // skip size
488- SDL_RWseek(p, 253 * sizeof(int16), SEEK_CUR); // unused
489-
490- // resize members
491- cd->color_tables.resize(cd->clut_count * cd->color_count);
492- cd->high_level_shapes.resize(cd->high_level_shape_count);
493- cd->low_level_shapes.resize(cd->low_level_shape_count);
494- cd->bitmaps.resize(cd->bitmap_count);
495-
496-}
497-
498-static void load_clut(rgb_color_value *r, int count, SDL_RWops *p)
499-{
500- for (int i = 0; i < count; i++, r++)
501- {
502- SDL_RWread(p, r, 1, 2);
503- r->red = SDL_ReadBE16(p);
504- r->green = SDL_ReadBE16(p);
505- r->blue = SDL_ReadBE16(p);
506- }
507-}
508-
509-static void load_high_level_shape(std::vector<uint8>& shape, SDL_RWops *p)
510-{
511- int16 type = SDL_ReadBE16(p);
512- int16 flags = SDL_ReadBE16(p);
513- char name[HIGH_LEVEL_SHAPE_NAME_LENGTH + 2];
514- SDL_RWread(p, name, 1, HIGH_LEVEL_SHAPE_NAME_LENGTH + 2);
515- int16 number_of_views = SDL_ReadBE16(p);
516- int16 frames_per_view = SDL_ReadBE16(p);
517-
518- // Convert low-level shape index list
519- int num_views;
520- switch (number_of_views) {
521- case _unanimated:
522- case _animated1:
523- num_views = 1;
524- break;
525- case _animated3to4:
526- case _animated4:
527- num_views = 4;
528- break;
529- case _animated3to5:
530- case _animated5:
531- num_views = 5;
532- break;
533- case _animated2to8:
534- case _animated5to8:
535- case _animated8:
536- num_views = 8;
537- break;
538- default:
539- num_views = number_of_views;
540- break;
541- }
542-
543- shape.resize(sizeof(high_level_shape_definition) + num_views * frames_per_view * sizeof(int16));
544-
545- high_level_shape_definition *d = (high_level_shape_definition *) &shape[0];
546-
547- d->type = type;
548- d->flags = flags;
549- memcpy(d->name, name, HIGH_LEVEL_SHAPE_NAME_LENGTH + 2);
550- d->number_of_views = number_of_views;
551- d->frames_per_view = frames_per_view;
552- d->ticks_per_frame = SDL_ReadBE16(p);
553- d->key_frame = SDL_ReadBE16(p);
554- d->transfer_mode = SDL_ReadBE16(p);
555- d->transfer_mode_period = SDL_ReadBE16(p);
556- d->first_frame_sound = SDL_ReadBE16(p);
557- d->key_frame_sound = SDL_ReadBE16(p);
558- d->last_frame_sound = SDL_ReadBE16(p);
559- d->pixels_to_world = SDL_ReadBE16(p);
560- d->loop_frame = SDL_ReadBE16(p);
561- SDL_RWseek(p, 14 * sizeof(int16), SEEK_CUR);
562-
563- // Convert low-level shape index list
564- for (int j = 0; j < num_views * d->frames_per_view; j++) {
565- d->low_level_shape_indexes[j] = SDL_ReadBE16(p);
566- }
567-}
568-
569-static void load_low_level_shape(low_level_shape_definition *d, SDL_RWops *p)
570-{
571- d->flags = SDL_ReadBE16(p);
572- d->minimum_light_intensity = SDL_ReadBE32(p);
573- d->bitmap_index = SDL_ReadBE16(p);
574- d->origin_x = SDL_ReadBE16(p);
575- d->origin_y = SDL_ReadBE16(p);
576- d->key_x = SDL_ReadBE16(p);
577- d->key_y = SDL_ReadBE16(p);
578- d->world_left = SDL_ReadBE16(p);
579- d->world_right = SDL_ReadBE16(p);
580- d->world_top = SDL_ReadBE16(p);
581- d->world_bottom = SDL_ReadBE16(p);
582- d->world_x0 = SDL_ReadBE16(p);
583- d->world_y0 = SDL_ReadBE16(p);
584- SDL_RWseek(p, 4 * sizeof(int16), SEEK_CUR);
585-}
586-
587-static void convert_m1_rle(std::vector<uint8>& bitmap, int scanlines, int scanline_length, SDL_RWops* p)
588-{
589-// std::vector<uint8> bitmap;
590- for (int scanline = 0; scanline < scanlines; ++scanline)
591- {
592- std::vector<uint8> scanline_data(scanline_length);
593- uint8* dst = &scanline_data[0];
594- uint8* sentry = &scanline_data[scanline_length];
595-
596- while (true)
597- {
598- int16 opcode = SDL_ReadBE16(p);
599- if (opcode > 0)
600- {
601- assert(dst + opcode <= sentry);
602- SDL_RWread(p, dst, opcode, 1);
603- dst += opcode;
604- }
605- else if (opcode < 0)
606- {
607- assert(dst - opcode <= sentry);
608- dst -= opcode;
609- }
610- else
611- break;
612- }
613-
614- assert (dst == sentry);
615-
616- // Find M2/oo-format RLE compression;
617- // it needs the first nonblank pixel and the last nonblank one + 1
618- int16 first = 0;
619- int16 last = 0;
620- for (int i = 0; i < scanline_length; ++i)
621- {
622- if (scanline_data[i] != 0)
623- {
624- first = i;
625- break;
626- }
627- }
628-
629- for (int i = scanline_length - 1; i >= 0; --i)
630- {
631- if (scanline_data[i] != 0)
632- {
633- last = i + 1;
634- break;
635- }
636- }
637-
638- if (last < first) last = first;
639-
640- bitmap.push_back(first >> 8);
641- bitmap.push_back(first & 0xff);
642- bitmap.push_back(last >> 8);
643- bitmap.push_back(last & 0xff);
644- bitmap.insert(bitmap.end(), &scanline_data[first], &scanline_data[last]);
645- }
646-}
647-
648-static void load_bitmap(std::vector<uint8>& bitmap, SDL_RWops *p)
649-{
650- bitmap_definition b;
651-
652- // Convert bitmap definition
653- b.width = SDL_ReadBE16(p);
654- b.height = SDL_ReadBE16(p);
655- b.bytes_per_row = SDL_ReadBE16(p);
656- b.flags = SDL_ReadBE16(p);
657- b.bit_depth = SDL_ReadBE16(p);
658-
659- // guess how big to make it
660- int rows = (b.flags & _COLUMN_ORDER_BIT) ? b.width : b.height;
661- int row_len = (b.flags & _COLUMN_ORDER_BIT) ? b.height : b.width;
662-
663- SDL_RWseek(p, 16, SEEK_CUR);
664-
665- // Skip row address pointers
666- SDL_RWseek(p, (rows + 1) * sizeof(uint32), SEEK_CUR);
667-
668- if (b.bytes_per_row == NONE)
669- {
670- if (m1_shapes)
671- {
672- // make enough room for the definition, then append as we convert RLE
673- bitmap.resize(sizeof(bitmap_definition) + rows * sizeof(pixel8*));
674- }
675- else
676- {
677- // ugly--figure out how big it's going to be
678-
679- int32 size = 0;
680- for (int j = 0; j < rows; j++) {
681- int16 first = SDL_ReadBE16(p);
682- int16 last = SDL_ReadBE16(p);
683- size += 4;
684- SDL_RWseek(p, last - first, SEEK_CUR);
685- size += last - first;
686- }
687-
688- bitmap.resize(sizeof(bitmap_definition) + rows * sizeof(pixel8*) + size);
689-
690- // Now, seek back
691- SDL_RWseek(p, -size, SEEK_CUR);
692- }
693- }
694- else
695- {
696- bitmap.resize(sizeof(bitmap_definition) + rows * sizeof(pixel8*) + rows * b.bytes_per_row);
697- }
698-
699-
700- uint8* c = &bitmap[0];
701- bitmap_definition *d = (bitmap_definition *) &bitmap[0];
702- d->width = b.width;
703- d->height = b.height;
704- d->bytes_per_row = b.bytes_per_row;
705- d->flags = b.flags;
706- d->flags &= ~_PATCHED_BIT; // Anvil sets unused flags :( we'll set it later
707- d->bit_depth = b.bit_depth;
708- c += sizeof(bitmap_definition);
709-
710- // Skip row address pointers
711- c += rows * sizeof(pixel8 *);
712-
713- // Copy bitmap data
714- if (d->bytes_per_row == NONE)
715- {
716- // RLE format
717-
718- if (m1_shapes)
719- {
720- convert_m1_rle(bitmap, rows, row_len, p);
721- }
722- else
723- {
724- for (int j = 0; j < rows; j++) {
725- int16 first = SDL_ReadBE16(p);
726- int16 last = SDL_ReadBE16(p);
727- *(c++) = (uint8)(first >> 8);
728- *(c++) = (uint8)(first);
729- *(c++) = (uint8)(last >> 8);
730- *(c++) = (uint8)(last);
731- SDL_RWread(p, c, 1, last - first);
732- c += last - first;
733- }
734- }
735- } else {
736- SDL_RWread(p, c, d->bytes_per_row, rows);
737- c += rows * d->bytes_per_row;
738- }
739-
740-}
741-
742-static void allocate_shading_tables(short collection_index, bool strip)
743-{
744- collection_header *header = get_collection_header(collection_index);
745- // Allocate enough space for this collection's shading tables
746- if (strip)
747- header->shading_tables = NULL;
748- else {
749- collection_definition *definition = get_collection_definition(collection_index);
750- header->shading_tables = (byte *)malloc(get_shading_table_size(collection_index) * definition->clut_count + shading_table_size * NUMBER_OF_TINT_TABLES);
751- }
752-}
753-
754-/*
755- * Load collection
756- */
757-
758-static bool load_collection(short collection_index, bool strip)
759-{
760- SDL_RWops* p;
761- boost::shared_ptr<SDL_RWops> m1_p; // automatic deallocation
762- LoadedResource r;
763- int32 src_offset;
764-
765- collection_header *header = get_collection_header(collection_index);
766-
767- if (m1_shapes)
768- {
769- // Collections are stored in .256 resources
770- if (!M1ShapesFile.Get('.', '2', '5', '6', 128 + collection_index, r))
771- {
772- return false;
773- }
774-
775- m1_p.reset(SDL_RWFromConstMem(r.GetPointer(), r.GetLength()), SDL_FreeRW);
776- p = m1_p.get();
777- src_offset = 0;
778- }
779- else
780- {
781- // Get offset and length of data in source file from header
782-
783- if (bit_depth == 8 || header->offset16 == -1) {
784- if (header->offset == -1)
785- {
786- return false;
787- }
788- src_offset = header->offset;
789- } else {
790- src_offset = header->offset16;
791- }
792-
793- p = ShapesFile.GetRWops();
794- ShapesFile.SetPosition(0);
795- src_offset += SDL_RWtell(p);
796- }
797-
798- // Read collection definition
799- std::auto_ptr<collection_definition> cd(new collection_definition);
800- SDL_RWseek(p, src_offset, RW_SEEK_SET);
801- load_collection_definition(cd.get(), p);
802- if (m1_shapes && cd->type == _interface_collection)
803- {
804- // don't know how to read M1 RLE shapes yet, so clear
805- // out and return true
806- cd->high_level_shapes.clear();
807- cd->low_level_shapes.clear();
808- cd->bitmaps.clear();
809- return true;
810- }
811- header->status &= ~markPATCHED;
812-
813- // Convert CLUTS
814- SDL_RWseek(p, src_offset + cd->color_table_offset, RW_SEEK_SET);
815- load_clut(&cd->color_tables[0], cd->clut_count * cd->color_count, p);
816-
817- // Convert high-level shape definitions
818- SDL_RWseek(p, src_offset + cd->high_level_shape_offset_table_offset, RW_SEEK_SET);
819-
820- std::vector<uint32> t(cd->high_level_shape_count);
821- SDL_RWread(p, &t[0], sizeof(uint32), cd->high_level_shape_count);
822- byte_swap_memory(&t[0], _4byte, cd->high_level_shape_count);
823- for (int i = 0; i < cd->high_level_shape_count; i++) {
824- SDL_RWseek(p, src_offset + t[i], RW_SEEK_SET);
825- load_high_level_shape(cd->high_level_shapes[i], p);
826- }
827-
828- // Convert low-level shape definitions
829- SDL_RWseek(p, src_offset + cd->low_level_shape_offset_table_offset, RW_SEEK_SET);
830- t.resize(cd->low_level_shape_count);
831- SDL_RWread(p, &t[0], sizeof(uint32), cd->low_level_shape_count);
832- byte_swap_memory(&t[0], _4byte, cd->low_level_shape_count);
833-
834- for (int i = 0; i < cd->low_level_shape_count; i++) {
835- SDL_RWseek(p, src_offset + t[i], RW_SEEK_SET);
836- load_low_level_shape(&cd->low_level_shapes[i], p);
837- }
838-
839- // Convert bitmap definitions
840- SDL_RWseek(p, src_offset + cd->bitmap_offset_table_offset, RW_SEEK_SET);
841- t.resize(cd->bitmap_count);
842- SDL_RWread(p, &t[0], sizeof(uint32), cd->bitmap_count);
843- byte_swap_memory(&t[0], _4byte, cd->bitmap_count);
844-
845- for (int i = 0; i < cd->bitmap_count; i++) {
846- SDL_RWseek(p, src_offset + t[i], RW_SEEK_SET);
847- load_bitmap(cd->bitmaps[i], p);
848- }
849-
850- header->collection = cd.release();
851-
852- if (strip) {
853- //!! don't know what to do
854- fprintf(stderr, "Stripped shapes not implemented\n");
855- abort();
856- }
857-
858- allocate_shading_tables(collection_index, strip);
859-
860- if (header->shading_tables == NULL) {
861- delete header->collection;
862- header->collection = NULL;
863- return false;
864- }
865-
866- // Everything OK
867- return true;
868-}
869-
870-
871-/*
872- * Unload collection
873- */
874-
875-static void unload_collection(struct collection_header *header)
876-{
877- assert(header->collection);
878- delete header->collection;
879- free(header->shading_tables);
880- header->collection = NULL;
881- header->shading_tables = NULL;
882-}
883-
884-#define ENDC_TAG FOUR_CHARS_TO_INT('e', 'n', 'd', 'c')
885-#define CLDF_TAG FOUR_CHARS_TO_INT('c', 'l', 'd', 'f')
886-#define HLSH_TAG FOUR_CHARS_TO_INT('h', 'l', 's', 'h')
887-#define LLSH_TAG FOUR_CHARS_TO_INT('l', 'l', 's', 'h')
888-#define BMAP_TAG FOUR_CHARS_TO_INT('b', 'm', 'a', 'p')
889-#define CTAB_TAG FOUR_CHARS_TO_INT('c', 't', 'a', 'b')
890-
891-std::vector<uint8> shapes_patch;
892-void set_shapes_patch_data(uint8 *data, size_t length)
893-{
894- if (!length)
895- {
896- shapes_patch.clear();
897- }
898- else
899- {
900- shapes_patch.resize(length);
901- memcpy(&shapes_patch[0], data, length);
902- }
903-}
904-
905-uint8* get_shapes_patch_data(size_t &length)
906-{
907- length = shapes_patch.size();
908- return length ? &shapes_patch[0] : 0;
909-}
910-
911-void load_shapes_patch(SDL_RWops *p, bool override_replacements)
912-{
913- std::vector<int16> color_counts(MAXIMUM_COLLECTIONS);
914- int32 start = SDL_RWtell(p);
915- SDL_RWseek(p, 0, SEEK_END);
916- int32 end = SDL_RWtell(p);
917-
918- SDL_RWseek(p, start, SEEK_SET);
919-
920- bool done = false;
921- while (!done)
922- {
923- // is there more data to read?
924- if (SDL_RWtell(p) < end)
925- {
926- int32 collection_index = SDL_ReadBE32(p);
927- int32 patch_bit_depth = SDL_ReadBE32(p);
928-
929- bool collection_end = false;
930- while (!collection_end)
931- {
932- // read a tag
933- int32 tag = SDL_ReadBE32(p);
934- if (tag == ENDC_TAG)
935- {
936- collection_end = true;
937- }
938- else if (tag == CLDF_TAG)
939- {
940- // a collection follows directly
941- collection_header *header = get_collection_header(collection_index);
942- if (collection_loaded(header) && patch_bit_depth == 8)
943- {
944- load_collection_definition(header->collection, p);
945- color_counts[collection_index] = header->collection->color_count;
946- allocate_shading_tables(collection_index, false);
947- header->status|=markPATCHED;
948-
949- } else {
950- // get the color count (it's the only way to skip the CTAB_TAG
951- SDL_RWseek(p, 6, SEEK_CUR);
952- color_counts[collection_index] = SDL_ReadBE16(p);
953- SDL_RWseek(p, 544 - 8, SEEK_CUR);
954- }
955- }
956- else if (tag == HLSH_TAG)
957- {
958- collection_definition *cd = get_collection_definition(collection_index);
959- int32 high_level_shape_index = SDL_ReadBE32(p);
960- int32 size = SDL_ReadBE32(p);
961- int32 pos = SDL_RWtell(p);
962- if (cd && patch_bit_depth == 8 && high_level_shape_index < cd->high_level_shapes.size())
963- {
964- load_high_level_shape(cd->high_level_shapes[high_level_shape_index], p);
965- SDL_RWseek(p, pos + size, SEEK_SET);
966-
967- }
968- else
969- {
970- SDL_RWseek(p, size, SEEK_CUR);
971- }
972- }
973- else if (tag == LLSH_TAG)
974- {
975- collection_definition *cd = get_collection_definition(collection_index);
976- int32 low_level_shape_index = SDL_ReadBE32(p);
977- if (cd && patch_bit_depth == 8 && low_level_shape_index < cd->low_level_shapes.size())
978- {
979- load_low_level_shape(&cd->low_level_shapes[low_level_shape_index], p);
980- }
981- else
982- {
983- SDL_RWseek(p, 36, SEEK_CUR);
984- }
985- }
986- else if (tag == BMAP_TAG)
987- {
988- collection_definition *cd = get_collection_definition(collection_index);
989- int32 bitmap_index = SDL_ReadBE32(p);
990- int32 size = SDL_ReadBE32(p);
991- if (cd && patch_bit_depth == 8 && bitmap_index < cd->bitmaps.size())
992- {
993- load_bitmap(cd->bitmaps[bitmap_index], p);
994- if (override_replacements)
995- {
996- get_bitmap_definition(collection_index, bitmap_index)->flags |= _PATCHED_BIT;
997- }
998- }
999- else
1000- {
1001- SDL_RWseek(p, size, SEEK_CUR);
1002- }
1003- }
1004- else if (tag == CTAB_TAG)
1005- {
1006- collection_definition *cd = get_collection_definition(collection_index);
1007- int32 color_table_index = SDL_ReadBE32(p);
1008- if (cd && patch_bit_depth == 8 && (color_table_index * cd->color_count < cd->color_tables.size()))
1009- {
1010- load_clut(&cd->color_tables[color_table_index], cd->color_count, p);
1011- }
1012- else
1013- {
1014- SDL_RWseek(p, color_counts[collection_index] * sizeof(rgb_color_value), SEEK_CUR);
1015- }
1016- }
1017- else
1018- {
1019- fprintf(stderr, "Unrecognized tag in patch file '%c%c%c%c'\n %x", tag >> 24, tag >> 16, tag >> 8, tag, tag);
1020- }
1021- }
1022-
1023-
1024- } else {
1025- done = true;
1026- }
1027- }
1028-
1029-
1030-}
1031-
1032-/* ---------- code */
1033-
1034-/* --------- private code */
1035-
1036-void initialize_shape_handler()
1037-{
1038- // M1 uses the resource fork, but M2 and Moo use the data fork
1039-
1040- FileSpecifier File;
1041- get_default_shapes_spec(File);
1042- open_shapes_file(File);
1043- if (!ShapesFile.IsOpen())
1044- alert_user(fatalError, strERRORS, badExtraFileLocations, ShapesFile.GetError());
1045- else
1046- atexit(shutdown_shape_handler);
1047-
1048- initialize_pixmap_handler();
1049-}
1050-
1051-void open_shapes_file(FileSpecifier& File)
1052-{
1053- if (File.Open(M1ShapesFile) && M1ShapesFile.Check('.','2','5','6',128))
1054- {
1055- m1_shapes = true;
1056- }
1057- else if (File.Open(ShapesFile))
1058- {
1059- m1_shapes = false;
1060- // Load the collection headers;
1061- // need a buffer for the packed data
1062- int Size = MAXIMUM_COLLECTIONS*SIZEOF_collection_header;
1063- byte *CollHdrStream = new byte[Size];
1064- if (!ShapesFile.Read(Size,CollHdrStream))
1065- {
1066- ShapesFile.Close();
1067- delete []CollHdrStream;
1068- return;
1069- }
1070-
1071- // Unpack them
1072- uint8 *S = CollHdrStream;
1073- int Count = MAXIMUM_COLLECTIONS;
1074- collection_header* ObjPtr = collection_headers;
1075-
1076- for (int k = 0; k < Count; k++, ObjPtr++)
1077- {
1078- StreamToValue(S,ObjPtr->status);
1079- StreamToValue(S,ObjPtr->flags);
1080-
1081- StreamToValue(S,ObjPtr->offset);
1082- StreamToValue(S,ObjPtr->length);
1083- StreamToValue(S,ObjPtr->offset16);
1084- StreamToValue(S,ObjPtr->length16);
1085-
1086- S += 6*2;
1087-
1088- ObjPtr->collection = NULL; // so unloading can work properly
1089- ObjPtr->shading_tables = NULL; // so unloading can work properly
1090- }
1091-
1092- assert((S - CollHdrStream) == Count*SIZEOF_collection_header);
1093-
1094- delete []CollHdrStream;
1095-
1096- // Load MML resources in file
1097- // Be sure to ignore not-found errors
1098-#if defined(mac)
1099- short SavedType, SavedError = get_game_error(&SavedType);
1100- XML_LoadFromResourceFork(File);
1101- set_game_error(SavedType,SavedError);
1102-#endif
1103- }
1104-}
1105-
1106-static void close_shapes_file(void)
1107-{
1108- if (m1_shapes)
1109- {
1110- M1ShapesFile.Close();
1111- }
1112- else
1113- {
1114- ShapesFile.Close();
1115- }
1116-}
1117-
1118-static void shutdown_shape_handler(void)
1119-{
1120- close_shapes_file();
1121-}
1122-
1123-#ifdef mac
1124-const int POINTER_SIZE = sizeof(void *);
1125-
1126-static int AdjustToPointerBoundary(int x)
1127-{
1128- return ((((x-1) / POINTER_SIZE) + 1) * POINTER_SIZE);
1129-}
1130-
1131-// Creates an unpacked collection and puts it into a long, flat stream like the original.
1132-byte *unpack_collection(byte *collection, int32 length, bool strip)
1133-{
1134-
1135- // Set up blank values of these quantities
1136- byte *NewCollection = NULL;
1137- int32 *OffsetTable = NULL;
1138-
1139- try
1140- {
1141- // First, unpack the header into a temporary area
1142- if (length < SIZEOF_collection_definition) throw 13666;
1143-
1144- collection_definition Definition;
1145- uint8 *SBase = collection;
1146- uint8 *S = collection;
1147-
1148- StreamToValue(S,Definition.version);
1149-
1150- StreamToValue(S,Definition.type);
1151- StreamToValue(S,Definition.flags);
1152-
1153- StreamToValue(S,Definition.color_count);
1154- StreamToValue(S,Definition.clut_count);
1155- StreamToValue(S,Definition.color_table_offset);
1156-
1157- StreamToValue(S,Definition.high_level_shape_count);
1158- StreamToValue(S,Definition.high_level_shape_offset_table_offset);
1159-
1160- StreamToValue(S,Definition.low_level_shape_count);
1161- StreamToValue(S,Definition.low_level_shape_offset_table_offset);
1162-
1163- StreamToValue(S,Definition.bitmap_count);
1164- StreamToValue(S,Definition.bitmap_offset_table_offset);
1165-
1166- StreamToValue(S,Definition.pixels_to_world);
1167-
1168- StreamToValue(S,Definition.size);
1169-
1170- S += 253*2;
1171- assert((S - SBase) == SIZEOF_collection_definition);
1172-
1173- // We have enough information to estimate the size of the unpack collection chunk!
1174- int32 NewSize = length;
1175-
1176- // The header:
1177- NewSize += (sizeof(collection_definition) - SIZEOF_collection_definition) + POINTER_SIZE;
1178-
1179- // The colors:
1180- if (!(Definition.color_count >= 0)) throw 13666;
1181- if (!(Definition.clut_count >= 0)) throw 13666;
1182- int TotalColors = Definition.color_count * Definition.clut_count;
1183- NewSize += TotalColors*(sizeof(rgb_color_value) - SIZEOF_rgb_color_value) + POINTER_SIZE;
1184-
1185- // The sequence-offset table:
1186- NewSize += POINTER_SIZE;
1187-
1188- // The sequence data:
1189- if (!(Definition.high_level_shape_count >= 0)) throw 13666;
1190- NewSize += Definition.high_level_shape_count*
1191- ((sizeof(high_level_shape_definition) - SIZEOF_high_level_shape_definition) + POINTER_SIZE);
1192-
1193- if (!strip)
1194- {
1195- // The frame-offset table:
1196- NewSize += POINTER_SIZE;
1197-
1198- // The frame data:
1199- if (!(Definition.low_level_shape_count >= 0)) throw 13666;
1200- NewSize += Definition.low_level_shape_count*
1201- ((sizeof(low_level_shape_definition) - SIZEOF_low_level_shape_definition) + POINTER_SIZE);
1202-
1203- // The bitmap-offset table:
1204- NewSize += POINTER_SIZE;
1205-
1206- // The bitmap data:
1207- if (!(Definition.bitmap_count >= 0)) throw 13666;
1208- NewSize += Definition.bitmap_count*
1209- ((sizeof(bitmap_definition) - SIZEOF_bitmap_definition) + POINTER_SIZE);
1210-
1211- // The bitmap pointers:
1212- if (!(Definition.bitmap_offset_table_offset >= 0)) throw 13666;
1213- if (!(Definition.bitmap_offset_table_offset +
1214- Definition.bitmap_count*sizeof(int32) <= uint32(length))) throw 13666;
1215- uint8 *OffsetStream = collection + Definition.bitmap_offset_table_offset;
1216- for (int k=0; k<Definition.bitmap_count; k++)
1217- {
1218- int32 Offset;
1219- StreamToValue(OffsetStream,Offset);
1220- if (!(Offset >= 0 && Offset < (length - SIZEOF_bitmap_definition))) throw 13666;
1221- uint8 *S = collection + Offset;
1222-
1223- bitmap_definition Bitmap;
1224-
1225- StreamToValue(S,Bitmap.width);
1226- StreamToValue(S,Bitmap.height);
1227- StreamToValue(S,Bitmap.bytes_per_row);
1228-
1229- StreamToValue(S,Bitmap.flags);
1230-
1231- short NumScanlines = (Bitmap.flags&_COLUMN_ORDER_BIT) ?
1232- Bitmap.width : Bitmap.height;
1233-
1234- NewSize += NumScanlines*(sizeof(pixel8 *) - sizeof(int32));
1235- }
1236- }
1237-
1238- // Blank out the new chunk and copy in the new header
1239- NewCollection = new byte[NewSize];
1240- memset(NewCollection,0,NewSize);
1241- int32 NewCollLocation = 0;
1242- memcpy(NewCollection, &Definition, sizeof(collection_definition));
1243- collection_definition& NewDefinition = *((collection_definition *)NewCollection);
1244- NewDefinition.size = NewSize;
1245- NewCollLocation += AdjustToPointerBoundary(sizeof(collection_definition));
1246-
1247- // Copy in the colors
1248- if (!(Definition.color_table_offset >= 0)) throw 13666;
1249- if (!(Definition.color_table_offset + TotalColors*SIZEOF_rgb_color_value <= length)) throw 13666;
1250- rgb_color_value *Colors = (rgb_color_value *)(NewCollection + NewCollLocation);
1251- SBase = S = collection + Definition.color_table_offset;
1252- for (int k = 0; k < TotalColors; k++, Colors++)
1253- {
1254- Colors->flags = *(S++);
1255- Colors->value = *(S++);
1256- StreamToValue(S,Colors->red);
1257- StreamToValue(S,Colors->green);
1258- StreamToValue(S,Colors->blue);
1259- }
1260- assert((S - SBase) == TotalColors*SIZEOF_rgb_color_value);
1261- NewDefinition.color_table_offset = NewCollLocation;
1262- NewCollLocation += AdjustToPointerBoundary(TotalColors*sizeof(rgb_color_value));
1263-
1264- // Copy in the sequence offsets
1265- if (!(Definition.high_level_shape_offset_table_offset >= 0)) throw 13666;
1266- if (!(Definition.high_level_shape_offset_table_offset +
1267- Definition.high_level_shape_count*sizeof(int32) <= uint32(length))) throw 13666;
1268- OffsetTable = new int32[Definition.high_level_shape_count + 1];
1269-
1270- S = collection + Definition.high_level_shape_offset_table_offset;
1271- StreamToList(S,OffsetTable,Definition.high_level_shape_count);
1272- OffsetTable[Definition.high_level_shape_count] =
1273- Definition.low_level_shape_offset_table_offset;
1274-
1275- if (!(OffsetTable[0] >= 0)) throw 13666;
1276- for (int k=0; k<Definition.high_level_shape_count; k++)
1277- if (!(OffsetTable[k+1] - OffsetTable[k] >= SIZEOF_high_level_shape_definition)) throw 13666;
1278- if (!(OffsetTable[Definition.high_level_shape_count] <= length)) throw 13666;
1279-
1280- NewDefinition.high_level_shape_offset_table_offset = NewCollLocation;
1281- int32 *NewOffsetPtr = (int32 *)(NewCollection + NewCollLocation);
1282- NewCollLocation += AdjustToPointerBoundary(sizeof(int32)*Definition.high_level_shape_count);
1283-
1284- // Copy in the sequences
1285- for (int k=0; k<Definition.high_level_shape_count; k++)
1286- {
1287- SBase = S = collection + OffsetTable[k];
1288- uint8 *SNext = collection + OffsetTable[k+1];
1289-
1290- high_level_shape_definition& Sequence =
1291- *((high_level_shape_definition *)(NewCollection + NewCollLocation));
1292-
1293- StreamToValue(S,Sequence.type);
1294- StreamToValue(S,Sequence.flags);
1295-
1296- StreamToBytes(S,Sequence.name,HIGH_LEVEL_SHAPE_NAME_LENGTH+2);
1297-
1298- StreamToValue(S,Sequence.number_of_views);
1299-
1300- StreamToValue(S,Sequence.frames_per_view);
1301- StreamToValue(S,Sequence.ticks_per_frame);
1302- StreamToValue(S,Sequence.key_frame);
1303-
1304- StreamToValue(S,Sequence.transfer_mode);
1305- StreamToValue(S,Sequence.transfer_mode_period);
1306-
1307- StreamToValue(S,Sequence.first_frame_sound);
1308- StreamToValue(S,Sequence.key_frame_sound);
1309- StreamToValue(S,Sequence.last_frame_sound);
1310-
1311- StreamToValue(S,Sequence.pixels_to_world);
1312-
1313- StreamToValue(S,Sequence.loop_frame);
1314-
1315- S += 14*2;
1316-
1317- StreamToValue(S,Sequence.low_level_shape_indexes[0]);
1318- assert((S - SBase) == SIZEOF_high_level_shape_definition);
1319-
1320- // Do the remaining frame indices
1321- size_t NumFrameIndxs = (SNext - S)/sizeof(int16);
1322- StreamToList(S,Sequence.low_level_shape_indexes+1,NumFrameIndxs);
1323-
1324- // Set the offset pointer appropriately:
1325- *(NewOffsetPtr++) = NewCollLocation;
1326- NewCollLocation +=
1327- AdjustToPointerBoundary(sizeof(high_level_shape_definition) + NumFrameIndxs*sizeof(int16));
1328- }
1329-
1330- delete []OffsetTable;
1331- OffsetTable = NULL;
1332-
1333- if (strip)
1334- {
1335- NewDefinition.low_level_shape_count = 0;
1336- NewDefinition.bitmap_count = 0;
1337- }
1338- else
1339- {
1340- // Copy in the frame offsets
1341- if (!(Definition.low_level_shape_count >= 0)) throw 13666;
1342- if (!(Definition.low_level_shape_offset_table_offset >= 0)) throw 13666;
1343- if (!(Definition.low_level_shape_offset_table_offset +
1344- Definition.low_level_shape_count*sizeof(int32) <= uint32(length))) throw 13666;
1345- int32 *OffsetTable = new int32[Definition.low_level_shape_count + 1];
1346-
1347- S = collection + Definition.low_level_shape_offset_table_offset;
1348- StreamToList(S,OffsetTable,Definition.low_level_shape_count);
1349- OffsetTable[Definition.low_level_shape_count] = Definition.bitmap_offset_table_offset;
1350-
1351- if (!(OffsetTable[0] >= 0)) throw 13666;
1352- for (int k=0; k<Definition.low_level_shape_count; k++)
1353- if (!(OffsetTable[k+1] - OffsetTable[k] >= SIZEOF_low_level_shape_definition)) throw 13666;
1354- if (!(OffsetTable[Definition.low_level_shape_count] <= length)) throw 13666;
1355-
1356- NewDefinition.low_level_shape_offset_table_offset = NewCollLocation;
1357- NewOffsetPtr = (int32 *)(NewCollection + NewCollLocation);
1358- NewCollLocation += AdjustToPointerBoundary(sizeof(int32)*Definition.low_level_shape_count);
1359-
1360- // Copy in the frames
1361- for (int k=0; k<Definition.low_level_shape_count; k++)
1362- {
1363- SBase = S = collection + OffsetTable[k];
1364-
1365- low_level_shape_definition& Frame =
1366- *((low_level_shape_definition *)(NewCollection + NewCollLocation));
1367-
1368- StreamToValue(S,Frame.flags);
1369-
1370- StreamToValue(S,Frame.minimum_light_intensity);
1371-
1372- StreamToValue(S,Frame.bitmap_index);
1373-
1374- StreamToValue(S,Frame.origin_x);
1375- StreamToValue(S,Frame.origin_y);
1376-
1377- StreamToValue(S,Frame.key_x);
1378- StreamToValue(S,Frame.key_y);
1379-
1380- StreamToValue(S,Frame.world_left);
1381- StreamToValue(S,Frame.world_right);
1382- StreamToValue(S,Frame.world_top);
1383- StreamToValue(S,Frame.world_bottom);
1384- StreamToValue(S,Frame.world_x0);
1385- StreamToValue(S,Frame.world_y0);
1386-
1387- S += 4*2;
1388-
1389- assert((S - SBase) == SIZEOF_low_level_shape_definition);
1390-
1391- // Set the offset pointer appropriately:
1392- *(NewOffsetPtr++) = NewCollLocation;
1393- NewCollLocation += AdjustToPointerBoundary(sizeof(low_level_shape_definition));
1394- }
1395-
1396- delete []OffsetTable;
1397- OffsetTable = NULL;
1398-
1399- // Copy in the the bitmap offsets
1400- if (!(Definition.bitmap_count >= 0)) throw 13666;
1401- if (!(Definition.bitmap_offset_table_offset >= 0)) throw 13666;
1402- if (!(Definition.bitmap_offset_table_offset +
1403- Definition.bitmap_count*sizeof(int32) <= uint32(length))) throw 13666;
1404- OffsetTable = new int32[Definition.bitmap_count + 1];
1405-
1406- S = collection + Definition.bitmap_offset_table_offset;
1407- StreamToList(S,OffsetTable,Definition.bitmap_count);
1408- OffsetTable[Definition.bitmap_count] = length;
1409-
1410- if (!(OffsetTable[0] >= 0)) throw 13666;
1411- for (int k=0; k<Definition.bitmap_count; k++)
1412- if (!(OffsetTable[k+1] - OffsetTable[k] >= SIZEOF_bitmap_definition)) throw 13666;
1413- if (!(OffsetTable[Definition.bitmap_count] <= length)) throw 13666;
1414-
1415- NewDefinition.bitmap_offset_table_offset = NewCollLocation;
1416- NewOffsetPtr = (int32 *)(NewCollection + NewCollLocation);
1417- NewCollLocation += AdjustToPointerBoundary(sizeof(int32)*Definition.bitmap_count);
1418-
1419- // Get the bitmaps
1420- for (int k=0; k<Definition.bitmap_count; k++)
1421- {
1422- SBase = S = collection + OffsetTable[k];
1423- uint8 *SNext = collection + OffsetTable[k+1];
1424-
1425- bitmap_definition& Bitmap =
1426- *((bitmap_definition *)(NewCollection + NewCollLocation));
1427-
1428- StreamToValue(S,Bitmap.width);
1429- StreamToValue(S,Bitmap.height);
1430- StreamToValue(S,Bitmap.bytes_per_row);
1431-
1432- StreamToValue(S,Bitmap.flags);
1433- StreamToValue(S,Bitmap.bit_depth);
1434-
1435- S += 8*2;
1436-
1437- // Code was originally designed for 32-bit pointers!
1438- S += sizeof(int32);
1439-
1440- assert((S - SBase) == SIZEOF_bitmap_definition);
1441-
1442- // Add in extra space for long pointers; offset the reading of the remaining stuff
1443- // by that quantity.
1444-
1445- short NumScanlines = (Bitmap.flags&_COLUMN_ORDER_BIT) ?
1446- Bitmap.width : Bitmap.height;
1447-
1448- int NumExtraPointerBytes = NumScanlines*(sizeof(pixel8 *) - sizeof(int32));
1449-
1450- // Do all the other stuff; don't bother to try to process it
1451- int32 RemainingBytes = (SNext - S);
1452- byte *RemainingDataPlacement = (byte *)(Bitmap.row_addresses+1) + NumExtraPointerBytes;
1453- StreamToBytes(S,RemainingDataPlacement,RemainingBytes);
1454-
1455- // Set the offset pointer appropriately:
1456- *(NewOffsetPtr++) = NewCollLocation;
1457- NewCollLocation +=
1458- AdjustToPointerBoundary(sizeof(bitmap_definition) + RemainingBytes);
1459- }
1460-
1461- delete []OffsetTable;
1462- OffsetTable = NULL;
1463-
1464- // Just in case I miscalculated...
1465- assert(NewCollLocation <= NewSize);
1466- }
1467- }
1468- catch(int n)
1469- {
1470- if (NewCollection) delete []NewCollection;
1471- }
1472- if (OffsetTable) delete []OffsetTable;
1473-
1474- return NewCollection;
1475-}
1476-#endif
1477-
1478-
1479-static bool collection_loaded(
1480- struct collection_header *header)
1481-{
1482- return header->collection ? true : false;
1483-}
1484-
1485-bool collection_loaded(short collection_index)
1486-{
1487- collection_header *header = get_collection_header(collection_index);
1488- return collection_loaded(header);
1489-}
1490-
1491-static void lock_collection(
1492- struct collection_header *header)
1493-{
1494- // nothing to do
1495-}
1496-
1497-static void unlock_collection(
1498- struct collection_header *header)
1499-{
1500- // nothing to do
1501-}
1502-
1503-#ifdef mac
1504-static byte *read_object_from_file(
1505- OpenedFile& OFile,
1506- int32 offset,
1507- int32 length)
1508-{
1509- if (!OFile.IsOpen()) return NULL;
1510-
1511- byte *data = NULL;
1512-
1513- if (length <= 0) return NULL;
1514- if (!(data = new byte[length])) return NULL;
1515-
1516- if (!OFile.SetPosition(offset))
1517- {
1518- delete []data;
1519- return NULL;
1520- }
1521- if (!OFile.Read(length,data))
1522- {
1523- delete []data;
1524- return NULL;
1525- }
1526-
1527- return data;
1528-}
1529-#endif
1530-
1531-
1532-void unload_all_collections(
1533- void)
1534-{
1535- struct collection_header *header;
1536- short collection_index;
1537-
1538- for (collection_index= 0, header= collection_headers; collection_index<MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1539- {
1540- if (collection_loaded(header))
1541- {
1542- unload_collection(header);
1543- }
1544- OGL_UnloadModelsImages(collection_index);
1545- }
1546-}
1547-
1548-void mark_collection(
1549- short collection_code,
1550- bool loading)
1551-{
1552- if (collection_code!=NONE)
1553- {
1554- short collection_index= GET_COLLECTION(collection_code);
1555-
1556- assert(collection_index>=0&&collection_index<MAXIMUM_COLLECTIONS);
1557- collection_headers[collection_index].status|= loading ? markLOAD : markUNLOAD;
1558- }
1559-}
1560-
1561-void strip_collection(
1562- short collection_code)
1563-{
1564- if (collection_code!=NONE)
1565- {
1566- short collection_index= GET_COLLECTION(collection_code);
1567-
1568- assert(collection_index>=0&&collection_index<MAXIMUM_COLLECTIONS);
1569- collection_headers[collection_index].status|= markSTRIP;
1570- }
1571-}
1572-
1573-/* returns count, doesnユt fill NULL buffer */
1574-short get_shape_descriptors(
1575- short shape_type,
1576- shape_descriptor *buffer)
1577-{
1578- short collection_index, low_level_shape_index;
1579- short appropriate_type;
1580- short count;
1581-
1582- switch (shape_type)
1583- {
1584- case _wall_shape: appropriate_type= _wall_collection; break;
1585- case _floor_or_ceiling_shape: appropriate_type= _wall_collection; break;
1586- default:
1587- assert(false);
1588- break;
1589- }
1590-
1591- count= 0;
1592- for (collection_index=0;collection_index<MAXIMUM_COLLECTIONS;++collection_index)
1593- {
1594- struct collection_definition *collection= get_collection_definition(collection_index);
1595- // Skip over nonexistent collections, frames, and bitmaps.
1596- if (!collection) continue;
1597-
1598- if (collection&&collection->type==appropriate_type)
1599- {
1600- for (low_level_shape_index=0;low_level_shape_index<collection->low_level_shape_count;++low_level_shape_index)
1601- {
1602- struct low_level_shape_definition *low_level_shape= get_low_level_shape_definition(collection_index, low_level_shape_index);
1603- if (!low_level_shape) continue;
1604- struct bitmap_definition *bitmap= get_bitmap_definition(collection_index, low_level_shape->bitmap_index);
1605- if (!bitmap) continue;
1606-
1607- count+= collection->clut_count;
1608- if (buffer)
1609- {
1610- short clut;
1611-
1612- for (clut=0;clut<collection->clut_count;++clut)
1613- {
1614- *buffer++= BUILD_DESCRIPTOR(BUILD_COLLECTION(collection_index, clut), low_level_shape_index);
1615- }
1616- }
1617- }
1618- }
1619- }
1620-
1621- return count;
1622-}
1623-
1624-void extended_get_shape_bitmap_and_shading_table(
1625- short collection_code,
1626- short low_level_shape_index,
1627- struct bitmap_definition **bitmap,
1628- void **shading_tables,
1629- short shading_mode)
1630-{
1631-// if (collection_code==_collection_marathon_control_panels) collection_code= 30, low_level_shape_index= 0;
1632- short collection_index= GET_COLLECTION(collection_code);
1633- short clut_index= GET_COLLECTION_CLUT(collection_code);
1634-
1635- // Forget about it if some one managed to call us with the NONE value
1636- assert(!(clut_index+1 == MAXIMUM_CLUTS_PER_COLLECTION &&
1637- collection_index+1 == MAXIMUM_COLLECTIONS &&
1638- low_level_shape_index+1 == MAXIMUM_SHAPES_PER_COLLECTION));
1639-
1640- struct low_level_shape_definition *low_level_shape= get_low_level_shape_definition(collection_index, low_level_shape_index);
1641- // Return NULL pointers for bitmap and shading table if the frame does not exist
1642- if (!low_level_shape)
1643- {
1644- *bitmap = NULL;
1645- if (shading_tables) *shading_tables = NULL;
1646- return;
1647- }
1648-
1649- if (bitmap) *bitmap= get_bitmap_definition(collection_index, low_level_shape->bitmap_index);
1650- if (shading_tables)
1651- {
1652- switch (shading_mode)
1653- {
1654- case _shading_normal:
1655- *shading_tables= get_collection_shading_tables(collection_index, clut_index);
1656- break;
1657- case _shading_infravision:
1658- *shading_tables= get_collection_tint_tables(collection_index, 0);
1659- break;
1660-
1661- default:
1662- assert(false);
1663- break;
1664- }
1665- }
1666-}
1667-
1668-// Because this object has to continue to exist after exiting the next function
1669-static low_level_shape_definition AdjustedFrame;
1670-
1671-struct shape_information_data *extended_get_shape_information(
1672- short collection_code,
1673- short low_level_shape_index)
1674-{
1675-if((GET_COLLECTION(collection_code) < 0) || (GET_COLLECTION(collection_code) >= NUMBER_OF_COLLECTIONS)) return NULL; if(low_level_shape_index < 0) return NULL;
1676- short collection_index= GET_COLLECTION(collection_code);
1677- struct low_level_shape_definition *low_level_shape;
1678-
1679- low_level_shape= get_low_level_shape_definition(collection_index, low_level_shape_index);
1680-
1681-#ifdef HAVE_OPENGL
1682- if (!low_level_shape) return NULL;
1683- // Try to get the texture options to use for a substituted image;
1684- // a scale of <= 0 will be assumed to be "don't do the adjustment".
1685- if (!OGL_IsActive()) return (struct shape_information_data *) low_level_shape;
1686- else
1687- {
1688- short clut_index= GET_COLLECTION_CLUT(collection_code);
1689- short bitmap_index = low_level_shape->bitmap_index;
1690- OGL_TextureOptions *TxtrOpts = OGL_GetTextureOptions(collection_index,clut_index,bitmap_index);
1691-
1692- if (!TxtrOpts->NormalImg.IsPresent() ||
1693- (TxtrOpts->offset_x == 0 && TxtrOpts->offset_y == 0 &&
1694- TxtrOpts->shape_width <= 0 && TxtrOpts->shape_height <= 0))
1695- return (struct shape_information_data *) low_level_shape;
1696-
1697- // find scale factor used in shape data
1698- bitmap_definition *bitmap = get_bitmap_definition(collection_index, bitmap_index);
1699- short scale_factor = (low_level_shape->world_right - low_level_shape->world_left) / bitmap->width;
1700-
1701- // Prepare the adjusted frame data; no need for mirroring here
1702- AdjustedFrame = *low_level_shape;
1703-
1704- if (TxtrOpts->shape_width > 0)
1705- AdjustedFrame.world_right = AdjustedFrame.world_left + (TxtrOpts->shape_width * scale_factor);
1706- if (TxtrOpts->shape_height > 0)
1707- AdjustedFrame.world_bottom = AdjustedFrame.world_top - (TxtrOpts->shape_height * scale_factor);
1708- if (TxtrOpts->offset_x != 0)
1709- {
1710- short offx = TxtrOpts->offset_x * scale_factor;
1711- AdjustedFrame.world_left -= offx;
1712- AdjustedFrame.world_right -= offx;
1713- }
1714- if (TxtrOpts->offset_y != 0)
1715- {
1716- short offy = TxtrOpts->offset_y * scale_factor;
1717- AdjustedFrame.world_top += offy;
1718- AdjustedFrame.world_bottom += offy;
1719- }
1720-
1721- return (struct shape_information_data *) &AdjustedFrame;
1722- }
1723-#endif
1724- return (struct shape_information_data *) low_level_shape;
1725-}
1726-
1727-void process_collection_sounds(
1728- short collection_code,
1729- void (*process_sound)(short sound_index))
1730-{
1731- short collection_index= GET_COLLECTION(collection_code);
1732- struct collection_definition *collection= get_collection_definition(collection_index);
1733- // Skip over processing unloaded collections and sequences
1734- if (!collection) return;
1735-
1736- short high_level_shape_index;
1737-
1738- for (high_level_shape_index= 0; high_level_shape_index<collection->high_level_shape_count; ++high_level_shape_index)
1739- {
1740- struct high_level_shape_definition *high_level_shape= get_high_level_shape_definition(collection_index, high_level_shape_index);
1741- if (!high_level_shape) return;
1742-
1743- process_sound(high_level_shape->first_frame_sound);
1744- process_sound(high_level_shape->key_frame_sound);
1745- process_sound(high_level_shape->last_frame_sound);
1746- }
1747-}
1748-
1749-struct shape_animation_data *get_shape_animation_data(
1750- shape_descriptor shape)
1751-{
1752- short collection_index, high_level_shape_index;
1753- struct high_level_shape_definition *high_level_shape;
1754-
1755- collection_index= GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(shape));
1756- high_level_shape_index= GET_DESCRIPTOR_SHAPE(shape);
1757- high_level_shape= get_high_level_shape_definition(collection_index, high_level_shape_index);
1758- if (!high_level_shape) return NULL;
1759-
1760- return (struct shape_animation_data *) &high_level_shape->number_of_views;
1761-}
1762-
1763-void *get_global_shading_table(
1764- void)
1765-{
1766- void *shading_table= (void *) NULL;
1767-
1768- switch (bit_depth)
1769- {
1770- case 8:
1771- {
1772- /* return the last shading_table calculated */
1773- short collection_index;
1774-
1775- for (collection_index=MAXIMUM_COLLECTIONS-1;collection_index>=0;--collection_index)
1776- {
1777- struct collection_definition *collection= get_collection_definition(collection_index);
1778-
1779- if (collection)
1780- {
1781- shading_table= get_collection_shading_tables(collection_index, 0);
1782- break;
1783- }
1784- }
1785-
1786- break;
1787- }
1788-
1789- case 16:
1790- build_global_shading_table16();
1791- shading_table= global_shading_table16;
1792- break;
1793-
1794- case 32:
1795- build_global_shading_table32();
1796- shading_table= global_shading_table32;
1797- break;
1798-
1799- default:
1800- assert(false);
1801- break;
1802- }
1803- assert(shading_table);
1804-
1805- return shading_table;
1806-}
1807-
1808-void load_collections(
1809- bool with_progress_bar,
1810- bool is_opengl)
1811-{
1812- struct collection_header *header;
1813- short collection_index;
1814-
1815- if (with_progress_bar)
1816- {
1817-// open_progress_dialog(_loading_collections);
1818-// draw_progress_bar(0, 2*MAXIMUM_COLLECTIONS);
1819- }
1820- precalculate_bit_depth_constants();
1821-
1822- free_and_unlock_memory(); /* do our best to get a big, unfragmented heap */
1823-
1824- /* first go through our list of shape collections and dispose of any collections which
1825- were marked for unloading. at the same time, unlock all those collections which
1826- will be staying (so the heap can move around) */
1827- for (collection_index= 0, header= collection_headers; collection_index<MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1828- {
1829-// if (with_progress_bar)
1830-// draw_progress_bar(collection_index, 2*MAXIMUM_COLLECTIONS);
1831- if (((header->status&markUNLOAD) && !(header->status&markLOAD)) || header->status&markPATCHED)
1832- {
1833- if (collection_loaded(header))
1834- {
1835- unload_collection(header);
1836- }
1837- OGL_UnloadModelsImages(collection_index);
1838- SW_Texture_Extras::instance()->Unload(collection_index);
1839- }
1840- else
1841- {
1842- /* if this collection is already loaded, unlock it to tenderize the heap */
1843- if (collection_loaded(header))
1844- {
1845- unlock_collection(header);
1846- }
1847- }
1848- }
1849-
1850- /* ... then go back through the list of collections and load any that we were asked to */
1851- for (collection_index= 0, header= collection_headers; collection_index<MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1852- {
1853-// if (with_progress_bar)
1854-// draw_progress_bar(MAXIMUM_COLLECTIONS+collection_index, 2*MAXIMUM_COLLECTIONS);
1855- /* donユt reload collections which are already in memory, but do lock them */
1856- if (collection_loaded(header))
1857- {
1858- // In case the substitute images had been changed by some level-specific MML...
1859-// OGL_LoadModelsImages(collection_index);
1860- lock_collection(header);
1861- }
1862- else
1863- {
1864- if (header->status&markLOAD)
1865- {
1866- /* load and decompress collection */
1867- if (!load_collection(collection_index, (header->status&markSTRIP) ? true : false))
1868- {
1869- if (!m1_shapes)
1870- {
1871- alert_user(fatalError, strERRORS, outOfMemory, -1);
1872- }
1873- }
1874-// OGL_LoadModelsImages(collection_index);
1875- }
1876- }
1877-
1878- /* clear action flags */
1879- header->status= markNONE;
1880- header->flags= 0;
1881- }
1882-
1883- Plugins::instance()->load_shapes_patches(is_opengl);
1884-
1885- if (shapes_patch.size())
1886- {
1887- SDL_RWops *f = SDL_RWFromMem(&shapes_patch[0], shapes_patch.size());
1888- load_shapes_patch(f, true);
1889- SDL_RWclose(f);
1890- }
1891-
1892- /* remap the shapes, recalculate row base addresses, build our new world color table and
1893- (finally) update the screen to reflect our changes */
1894- update_color_environment(is_opengl);
1895-
1896- // load software enhancements
1897- if (!is_opengl) {
1898- for (collection_index= 0, header= collection_headers; collection_index < MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1899- {
1900- if (collection_loaded(header))
1901- {
1902- SW_Texture_Extras::instance()->Load(collection_index);
1903- }
1904- }
1905- }
1906-// if (with_progress_bar)
1907-// close_progress_dialog();
1908-}
1909-
1910-#ifdef HAVE_OPENGL
1911-
1912-int count_replacement_collections()
1913-{
1914- int total_replacements = 0;
1915- short collection_index;
1916- struct collection_header *header;
1917- for (collection_index = 0, header = collection_headers; collection_index < MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1918- {
1919- if (collection_loaded(header))
1920- {
1921- total_replacements += OGL_CountModelsImages(collection_index);
1922- }
1923- }
1924-
1925- return total_replacements;
1926-}
1927-
1928-void load_replacement_collections()
1929-{
1930- struct collection_header *header;
1931- short collection_index;
1932-
1933- for (collection_index= 0, header= collection_headers; collection_index < MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1934- {
1935- if (collection_loaded(header))
1936- {
1937- OGL_LoadModelsImages(collection_index);
1938- }
1939- }
1940-}
1941-
1942-#endif
1943-
1944-/* ---------- private code */
1945-
1946-static void precalculate_bit_depth_constants(
1947- void)
1948-{
1949- switch (bit_depth)
1950- {
1951- case 8:
1952- number_of_shading_tables= 32;
1953- shading_table_fractional_bits= 5;
1954-// next_shading_table_shift= 8;
1955- shading_table_size= PIXEL8_MAXIMUM_COLORS*sizeof(pixel8);
1956- break;
1957- case 16:
1958- number_of_shading_tables= 64;
1959- shading_table_fractional_bits= 6;
1960-// next_shading_table_shift= 9;
1961- shading_table_size= PIXEL8_MAXIMUM_COLORS*sizeof(pixel16);
1962- break;
1963- case 32:
1964- number_of_shading_tables= 256;
1965- shading_table_fractional_bits= 8;
1966-// next_shading_table_shift= 10;
1967- shading_table_size= PIXEL8_MAXIMUM_COLORS*sizeof(pixel32);
1968- break;
1969- }
1970-}
1971-
1972-/* given a list of RGBColors, find out which one, if any, match the given color. if there
1973- arenユt any matches, add a new entry and return that index. */
1974-static short find_or_add_color(
1975- struct rgb_color_value *color,
1976- register struct rgb_color_value *colors,
1977- short *color_count,
1978- bool update_flags = true)
1979-{
1980- short i;
1981-
1982- // LP addition: save initial color-table pointer, just in case we overflow
1983- register struct rgb_color_value *colors_saved = colors;
1984-
1985- // = 1 to skip the transparent color
1986- for (i= 1, colors+= 1; i<*color_count; ++i, ++colors)
1987- {
1988- if (colors->red==color->red && colors->green==color->green && colors->blue==color->blue)
1989- {
1990- if (update_flags) colors->flags= color->flags;
1991- return i;
1992- }
1993- }
1994-
1995- // LP change: added a fallback strategy; if there were too many colors,
1996- // then find the closest one
1997- if (*color_count >= PIXEL8_MAXIMUM_COLORS)
1998- {
1999- // Set up minimum distance, its index
2000- // Strictly speaking, the distance squared, since that will be
2001- // what we will be calculating.
2002- // The color values are data type "word", which is unsigned short;
2003- // this explains the initial choice of minimum value --
2004- // as greater than any possible such value.
2005- double MinDiffSq = 3*double(65536)*double(65536);
2006- short MinIndx = 0;
2007-
2008- // Rescan
2009- colors = colors_saved;
2010- for (i= 1, colors+= 1; i<*color_count; ++i, ++colors)
2011- {
2012- double RedDiff = double(color->red) - double(colors->red);
2013- double GreenDiff = double(color->green) - double(colors->green);
2014- double BlueDiff = double(color->blue) - double(colors->blue);
2015- double DiffSq = RedDiff*RedDiff + GreenDiff*GreenDiff + BlueDiff*BlueDiff;
2016- if (DiffSq < MinDiffSq)
2017- {
2018- MinIndx = i;
2019- MinDiffSq = DiffSq;
2020- }
2021- }
2022- return MinIndx;
2023- }
2024-
2025- // assert(*color_count<PIXEL8_MAXIMUM_COLORS);
2026- *colors= *color;
2027-
2028- return (*color_count)++;
2029-}
2030-
2031-static void update_color_environment(
2032- bool is_opengl)
2033-{
2034- short color_count;
2035- short collection_index;
2036- short bitmap_index;
2037-
2038- pixel8 remapping_table[PIXEL8_MAXIMUM_COLORS];
2039- struct rgb_color_value colors[PIXEL8_MAXIMUM_COLORS];
2040-
2041- memset(remapping_table, 0, PIXEL8_MAXIMUM_COLORS*sizeof(pixel8));
2042-
2043- // dummy color to hold the first index (zero) for transparent pixels
2044- colors[0].red= colors[0].green= colors[0].blue= 65535;
2045- colors[0].flags= colors[0].value= 0;
2046- color_count= 1;
2047-
2048- /* loop through all collections, only paying attention to the loaded ones. weユre
2049- depending on finding the gray run (white to black) first; so itユs the responsibility
2050- of the lowest numbered loaded collection to give us this */
2051- for (collection_index=0;collection_index<MAXIMUM_COLLECTIONS;++collection_index)
2052- {
2053- struct collection_definition *collection= get_collection_definition(collection_index);
2054-
2055-// dprintf("collection #%d", collection_index);
2056-
2057- if (collection && collection->bitmap_count)
2058- {
2059- struct rgb_color_value *primary_colors= get_collection_colors(collection_index, 0)+NUMBER_OF_PRIVATE_COLORS;
2060- assert(primary_colors);
2061- short color_index, clut_index;
2062-
2063-// if (collection_index==15) dprintf("primary clut %p", primary_colors);
2064-// dprintf("primary clut %d entries;dm #%d #%d", collection->color_count, primary_colors, collection->color_count*sizeof(ColorSpec));
2065-
2066- /* add the colors from this collectionユs primary color table to the aggregate color
2067- table and build the remapping table */
2068- for (color_index=0;color_index<collection->color_count-NUMBER_OF_PRIVATE_COLORS;++color_index)
2069- {
2070- primary_colors[color_index].value= remapping_table[primary_colors[color_index].value]=
2071- find_or_add_color(&primary_colors[color_index], colors, &color_count);
2072- }
2073-
2074- /* then remap the collection and recalculate the base addresses of each bitmap */
2075- for (bitmap_index= 0; bitmap_index<collection->bitmap_count; ++bitmap_index)
2076- {
2077- struct bitmap_definition *bitmap= get_bitmap_definition(collection_index, bitmap_index);
2078- assert(bitmap);
2079-
2080- /* calculate row base addresses ... */
2081- bitmap->row_addresses[0]= calculate_bitmap_origin(bitmap);
2082- precalculate_bitmap_row_addresses(bitmap);
2083-
2084- /* ... and remap it */
2085- remap_bitmap(bitmap, remapping_table);
2086- }
2087-
2088- /* build a shading table for each clut in this collection */
2089- for (clut_index= 0; clut_index<collection->clut_count; ++clut_index)
2090- {
2091- void *primary_shading_table= get_collection_shading_tables(collection_index, 0);
2092- short collection_bit_depth= collection->type==_interface_collection ? 8 : bit_depth;
2093-
2094- if (clut_index)
2095- {
2096- struct rgb_color_value *alternate_colors= get_collection_colors(collection_index, clut_index)+NUMBER_OF_PRIVATE_COLORS;
2097- assert(alternate_colors);
2098- void *alternate_shading_table= get_collection_shading_tables(collection_index, clut_index);
2099- pixel8 shading_remapping_table[PIXEL8_MAXIMUM_COLORS];
2100-
2101- memset(shading_remapping_table, 0, PIXEL8_MAXIMUM_COLORS*sizeof(pixel8));
2102-
2103-// dprintf("alternate clut %d entries;dm #%d #%d", collection->color_count, alternate_colors, collection->color_count*sizeof(ColorSpec));
2104-
2105- /* build a remapping table for the primary shading table which we can use to
2106- calculate this alternate shading table */
2107- for (color_index= 0; color_index<PIXEL8_MAXIMUM_COLORS; ++color_index) shading_remapping_table[color_index]= static_cast<pixel8>(color_index);
2108- for (color_index= 0; color_index<collection->color_count-NUMBER_OF_PRIVATE_COLORS; ++color_index)
2109- {
2110- shading_remapping_table[find_or_add_color(&primary_colors[color_index], colors, &color_count, false)]=
2111- find_or_add_color(&alternate_colors[color_index], colors, &color_count);
2112- }
2113-// shading_remapping_table[iBLACK]= iBLACK; /* make iBLACK==>iBLACK remapping explicit */
2114-
2115- switch (collection_bit_depth)
2116- {
2117- case 8:
2118- /* duplicate the primary shading table and remap it */
2119- memcpy(alternate_shading_table, primary_shading_table, get_shading_table_size(collection_index));
2120- map_bytes((unsigned char *)alternate_shading_table, shading_remapping_table, get_shading_table_size(collection_index));
2121- break;
2122-
2123- case 16:
2124- build_shading_tables16(colors, color_count, (pixel16 *)alternate_shading_table, shading_remapping_table, is_opengl); break;
2125- break;
2126-
2127- case 32:
2128- build_shading_tables32(colors, color_count, (pixel32 *)alternate_shading_table, shading_remapping_table, is_opengl); break;
2129- break;
2130-
2131- default:
2132- assert(false);
2133- break;
2134- }
2135- }
2136- else
2137- {
2138- /* build the primary shading table */
2139- switch (collection_bit_depth)
2140- {
2141- case 8: build_shading_tables8(colors, color_count, (unsigned char *)primary_shading_table); break;
2142- case 16: build_shading_tables16(colors, color_count, (pixel16 *)primary_shading_table, (byte *) NULL, is_opengl); break;
2143- case 32: build_shading_tables32(colors, color_count, (pixel32 *)primary_shading_table, (byte *) NULL, is_opengl); break;
2144- default:
2145- assert(false);
2146- break;
2147- }
2148- }
2149- }
2150-
2151- build_collection_tinting_table(colors, color_count, collection_index, is_opengl);
2152-
2153- /* 8-bit interface, non-8-bit main window; remember interface CLUT separately */
2154- if (collection_index==_collection_interface && interface_bit_depth==8 && bit_depth!=interface_bit_depth) _change_clut(change_interface_clut, colors, color_count);
2155-
2156- /* if weユre not in 8-bit, we donユt have to carry our colors over into the next collection */
2157- if (bit_depth!=8) color_count= 1;
2158- }
2159- }
2160-
2161-#ifdef DEBUG
2162-// dump_colors(colors, color_count);
2163-#endif
2164-
2165- /* change the screen clut and rebuild our shading tables */
2166- _change_clut(change_screen_clut, colors, color_count);
2167-}
2168-
2169-static void _change_clut(
2170- void (*change_clut_proc)(struct color_table *color_table),
2171- struct rgb_color_value *colors,
2172- short color_count)
2173-{
2174- struct color_table color_table;
2175- struct rgb_color *color;
2176- short i;
2177-
2178- color= color_table.colors;
2179- color_table.color_count= PIXEL8_MAXIMUM_COLORS;
2180- for (i= 0; i<color_count; ++i, ++color, ++colors)
2181- {
2182- *color= *((struct rgb_color *)&colors->red);
2183- }
2184- for (i= color_count; i<PIXEL8_MAXIMUM_COLORS; ++i, ++color)
2185- {
2186- color->red= color->green= color->blue= 0;
2187- }
2188- change_clut_proc(&color_table);
2189-}
2190-
2191-#ifndef SCREAMING_METAL
2192-static void build_shading_tables8(
2193- struct rgb_color_value *colors,
2194- short color_count,
2195- pixel8 *shading_tables)
2196-{
2197- short i;
2198- short start, count, level, value;
2199-
2200- objlist_set(shading_tables, iBLACK, PIXEL8_MAXIMUM_COLORS);
2201-
2202- start= 0, count= 0;
2203- while (get_next_color_run(colors, color_count, &start, &count))
2204- {
2205- for (i= 0; i<count; ++i)
2206- {
2207- short adjust= start ? 1 : 0;
2208-
2209- for (level= 0; level<number_of_shading_tables; ++level)
2210- {
2211- struct rgb_color_value *color= colors + start + i;
2212- short multiplier= (color->flags&SELF_LUMINESCENT_COLOR_FLAG) ? (level>>1) : level;
2213-
2214- value= i + (multiplier*(count+adjust-i))/(number_of_shading_tables-1);
2215- if (value>=count) value= iBLACK; else value= start+value;
2216- shading_tables[PIXEL8_MAXIMUM_COLORS*(number_of_shading_tables-level-1)+start+i]= value;
2217- }
2218- }
2219- }
2220-}
2221-#else
2222-short find_closest_color(
2223- struct rgb_color_value *color,
2224- register struct rgb_color_value *colors,
2225- short color_count)
2226-{
2227- short i;
2228- int32 closest_delta= INT32_MAX;
2229- short closest_index= 0;
2230-
2231- // = 1 to skip the transparent color
2232- for (i= 1, colors+= 1; i<color_count; ++i, ++colors)
2233- {
2234- int32 delta= (int32)ABS(colors->red-color->red) +
2235- (int32)ABS(colors->green-color->green) +
2236- (int32)ABS(colors->blue-color->blue);
2237-
2238- if (delta<closest_delta) closest_index= i, closest_delta= delta;
2239- }
2240-
2241- return closest_index;
2242-}
2243-
2244-static void build_shading_tables8(
2245- struct rgb_color_value *colors,
2246- short color_count,
2247- pixel8 *shading_tables)
2248-{
2249- short i;
2250- short start, count, level;
2251-
2252- objlist_set(shading_tables, iBLACK, PIXEL8_MAXIMUM_COLORS);
2253-
2254- start= 0, count= 0;
2255- while (get_next_color_run(colors, color_count, &start, &count))
2256- {
2257- for (i= 0; i<count; ++i)
2258- {
2259- for (level= 0; level<number_of_shading_tables; ++level)
2260- {
2261- struct rgb_color_value *color= colors + start + i;
2262- rgb_color_value result;
2263-
2264- result.red= (color->red*level)/(number_of_shading_tables-1);
2265- result.green= (color->green*level)/(number_of_shading_tables-1);
2266- result.blue= (color->blue*level)/(number_of_shading_tables-1);
2267- shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2268- find_closest_color(&result, colors, color_count);
2269- }
2270- }
2271- }
2272-}
2273-#endif
2274-
2275-static void build_shading_tables16(
2276- struct rgb_color_value *colors,
2277- short color_count,
2278- pixel16 *shading_tables,
2279- byte *remapping_table,
2280- bool is_opengl)
2281-{
2282- short i;
2283- short start, count, level;
2284-
2285- objlist_set(shading_tables, 0, PIXEL8_MAXIMUM_COLORS);
2286-
2287-#ifdef SDL
2288- SDL_PixelFormat *fmt = &pixel_format_16;
2289-#endif
2290-
2291- start= 0, count= 0;
2292- while (get_next_color_run(colors, color_count, &start, &count))
2293- {
2294- for (i=0;i<count;++i)
2295- {
2296- for (level= 0; level<number_of_shading_tables; ++level)
2297- {
2298- struct rgb_color_value *color= colors + (remapping_table ? remapping_table[start+i] : (start+i));
2299- short multiplier= (color->flags&SELF_LUMINESCENT_COLOR_FLAG) ? ((number_of_shading_tables>>1)+(level>>1)) : level;
2300-#ifdef SDL
2301- if (!is_opengl)
2302- // Find optimal pixel value for video display
2303- shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2304- SDL_MapRGB(fmt,
2305- ((color->red * multiplier) / (number_of_shading_tables-1)) >> 8,
2306- ((color->green * multiplier) / (number_of_shading_tables-1)) >> 8,
2307- ((color->blue * multiplier) / (number_of_shading_tables-1)) >> 8);
2308- else
2309-#endif
2310- // Mac xRGB 1555 pixel format
2311- shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2312- RGBCOLOR_TO_PIXEL16((color->red*multiplier)/(number_of_shading_tables-1),
2313- (color->green*multiplier)/(number_of_shading_tables-1),
2314- (color->blue*multiplier)/(number_of_shading_tables-1));
2315- }
2316- }
2317- }
2318-}
2319-
2320-static void build_shading_tables32(
2321- struct rgb_color_value *colors,
2322- short color_count,
2323- pixel32 *shading_tables,
2324- byte *remapping_table,
2325- bool is_opengl)
2326-{
2327- short i;
2328- short start, count, level;
2329-
2330- objlist_set(shading_tables, 0, PIXEL8_MAXIMUM_COLORS);
2331-
2332-#ifdef SDL
2333- SDL_PixelFormat *fmt = &pixel_format_32;
2334-#endif
2335-
2336- start= 0, count= 0;
2337- while (get_next_color_run(colors, color_count, &start, &count))
2338- {
2339- for (i= 0; i<count; ++i)
2340- {
2341- for (level= 0; level<number_of_shading_tables; ++level)
2342- {
2343- struct rgb_color_value *color= colors + (remapping_table ? remapping_table[start+i] : (start+i));
2344- short multiplier= (color->flags&SELF_LUMINESCENT_COLOR_FLAG) ? ((number_of_shading_tables>>1)+(level>>1)) : level;
2345-
2346-#ifdef SDL
2347- if (!is_opengl)
2348- // Find optimal pixel value for video display
2349- shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2350- SDL_MapRGB(fmt,
2351- ((color->red * multiplier) / (number_of_shading_tables-1)) >> 8,
2352- ((color->green * multiplier) / (number_of_shading_tables-1)) >> 8,
2353- ((color->blue * multiplier) / (number_of_shading_tables-1)) >> 8);
2354- else
2355-#endif
2356- // Mac xRGB 8888 pixel format
2357- shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2358- RGBCOLOR_TO_PIXEL32((color->red*multiplier)/(number_of_shading_tables-1),
2359- (color->green*multiplier)/(number_of_shading_tables-1),
2360- (color->blue*multiplier)/(number_of_shading_tables-1));
2361- }
2362- }
2363- }
2364-}
2365-
2366-static void build_global_shading_table16(
2367- void)
2368-{
2369- if (!global_shading_table16)
2370- {
2371- short value, shading_table;
2372- pixel16 *write;
2373-
2374-#ifdef SDL
2375- SDL_PixelFormat *fmt = &pixel_format_16;
2376-#endif
2377-
2378- global_shading_table16= (pixel16 *) malloc(sizeof(pixel16)*number_of_shading_tables*NUMBER_OF_COLOR_COMPONENTS*(PIXEL16_MAXIMUM_COMPONENT+1));
2379- assert(global_shading_table16);
2380-
2381- write= global_shading_table16;
2382- for (shading_table= 0; shading_table<number_of_shading_tables; ++shading_table)
2383- {
2384-#ifdef SDL
2385- // Under SDL, the components may have different widths and different shifts
2386- int shift = fmt->Rshift + (3 - fmt->Rloss);
2387- for (value=0;value<=PIXEL16_MAXIMUM_COMPONENT;++value)
2388- *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2389- shift = fmt->Gshift + (3 - fmt->Gloss);
2390- for (value=0;value<=PIXEL16_MAXIMUM_COMPONENT;++value)
2391- *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2392- shift = fmt->Bshift + (3 - fmt->Bloss);
2393- for (value=0;value<=PIXEL16_MAXIMUM_COMPONENT;++value)
2394- *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2395-#else
2396- // Under MacOS, every component has the same width
2397- for (short component=0;component<NUMBER_OF_COLOR_COMPONENTS;++component)
2398- {
2399- short shift= 5*(NUMBER_OF_COLOR_COMPONENTS-component-1);
2400-
2401- for (value=0;value<=PIXEL16_MAXIMUM_COMPONENT;++value)
2402- {
2403- *write++= ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2404- }
2405- }
2406-#endif
2407- }
2408- }
2409-}
2410-
2411-static void build_global_shading_table32(
2412- void)
2413-{
2414- if (!global_shading_table32)
2415- {
2416- short value, shading_table;
2417- pixel32 *write;
2418-
2419-#ifdef SDL
2420- SDL_PixelFormat *fmt = &pixel_format_32;
2421-#endif
2422-
2423- global_shading_table32= (pixel32 *) malloc(sizeof(pixel32)*number_of_shading_tables*NUMBER_OF_COLOR_COMPONENTS*(PIXEL32_MAXIMUM_COMPONENT+1));
2424- assert(global_shading_table32);
2425-
2426- write= global_shading_table32;
2427- for (shading_table= 0; shading_table<number_of_shading_tables; ++shading_table)
2428- {
2429-#ifdef SDL
2430- // Under SDL, the components may have different widths and different shifts
2431- int shift = fmt->Rshift - fmt->Rloss;
2432- for (value=0;value<=PIXEL32_MAXIMUM_COMPONENT;++value)
2433- *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2434- shift = fmt->Gshift - fmt->Gloss;
2435- for (value=0;value<=PIXEL32_MAXIMUM_COMPONENT;++value)
2436- *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2437- shift = fmt->Bshift - fmt->Bloss;
2438- for (value=0;value<=PIXEL32_MAXIMUM_COMPONENT;++value)
2439- *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2440-#else
2441- // Under MacOS, every component has the same width
2442- for (short component= 0; component<NUMBER_OF_COLOR_COMPONENTS; ++component)
2443- {
2444- short shift= 8*(NUMBER_OF_COLOR_COMPONENTS-component-1);
2445-
2446- for (value= 0; value<=PIXEL32_MAXIMUM_COMPONENT; ++value)
2447- {
2448- *write++= ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2449- }
2450- }
2451-#endif
2452- }
2453- }
2454-}
2455-
2456-static bool get_next_color_run(
2457- struct rgb_color_value *colors,
2458- short color_count,
2459- short *start,
2460- short *count)
2461-{
2462- bool not_done= false;
2463- struct rgb_color_value last_color;
2464-
2465- if (*start+*count<color_count)
2466- {
2467- *start+= *count;
2468- for (*count=0;*start+*count<color_count;*count+= 1)
2469- {
2470- if (*count)
2471- {
2472- if (new_color_run(colors+*start+*count, &last_color))
2473- {
2474- break;
2475- }
2476- }
2477- last_color= colors[*start+*count];
2478- }
2479-
2480- not_done= true;
2481- }
2482-
2483- return not_done;
2484-}
2485-
2486-static bool new_color_run(
2487- struct rgb_color_value *_new,
2488- struct rgb_color_value *last)
2489-{
2490- if ((int32)last->red+(int32)last->green+(int32)last->blue<(int32)_new->red+(int32)_new->green+(int32)_new->blue)
2491- {
2492- return true;
2493- }
2494- else
2495- {
2496- return false;
2497- }
2498-}
2499-
2500-static int32 get_shading_table_size(
2501- short collection_code)
2502-{
2503- int32 size;
2504-
2505- switch (bit_depth)
2506- {
2507- case 8: size= number_of_shading_tables*shading_table_size; break;
2508- case 16: size= number_of_shading_tables*shading_table_size; break;
2509- case 32: size= number_of_shading_tables*shading_table_size; break;
2510- default:
2511- assert(false);
2512- break;
2513- }
2514-
2515- return size;
2516-}
2517-
2518-/* --------- light enhancement goggles */
2519-
2520-enum /* collection tint colors */
2521-{
2522- _tint_collection_red,
2523- _tint_collection_green,
2524- _tint_collection_blue,
2525- _tint_collection_yellow,
2526- NUMBER_OF_TINT_COLORS
2527-};
2528-
2529-struct tint_color8_data
2530-{
2531- short start, count;
2532-};
2533-
2534-static struct rgb_color tint_colors16[NUMBER_OF_TINT_COLORS]=
2535-{
2536- {65535, 0, 0},
2537- {0, 65535, 0},
2538- {0, 0, 65535},
2539- {65535, 65535, 0},
2540-};
2541-
2542-static struct tint_color8_data tint_colors8[NUMBER_OF_TINT_COLORS]=
2543-{
2544- {45, 13},
2545- {32, 13},
2546- {96, 13},
2547- {83, 13},
2548-};
2549-
2550-
2551-// LP addition to make it more generic;
2552-// the ultimate in this would be to make every collection
2553-// have its own infravision tint.
2554-static short CollectionTints[NUMBER_OF_COLLECTIONS] =
2555-{
2556- // Interface
2557- NONE,
2558- // Weapons in hand
2559- _tint_collection_yellow,
2560- // Juggernaut, tick
2561- _tint_collection_red,
2562- _tint_collection_red,
2563- // Explosion effects
2564- _tint_collection_yellow,
2565- // Hunter
2566- _tint_collection_red,
2567- // Player
2568- _tint_collection_yellow,
2569- // Items
2570- _tint_collection_green,
2571- // Trooper, Pfhor, S'pht'Kr, F'lickta
2572- _tint_collection_red,
2573- _tint_collection_red,
2574- _tint_collection_red,
2575- _tint_collection_red,
2576- // Bob and VacBobs
2577- _tint_collection_yellow,
2578- _tint_collection_yellow,
2579- // Enforcer, Drone
2580- _tint_collection_red,
2581- _tint_collection_red,
2582- // S'pht
2583- _tint_collection_blue,
2584- // Walls
2585- _tint_collection_blue,
2586- _tint_collection_blue,
2587- _tint_collection_blue,
2588- _tint_collection_blue,
2589- _tint_collection_blue,
2590- // Scenery
2591- _tint_collection_blue,
2592- _tint_collection_blue,
2593- _tint_collection_blue,
2594- _tint_collection_blue,
2595- _tint_collection_blue,
2596- // Landscape
2597- _tint_collection_blue,
2598- _tint_collection_blue,
2599- _tint_collection_blue,
2600- _tint_collection_blue,
2601- // Cyborg
2602- _tint_collection_red
2603-};
2604-
2605-
2606-static void build_collection_tinting_table(
2607- struct rgb_color_value *colors,
2608- short color_count,
2609- short collection_index,
2610- bool is_opengl)
2611-{
2612- struct collection_definition *collection= get_collection_definition(collection_index);
2613- if (!collection) return;
2614-
2615- void *tint_table= get_collection_tint_tables(collection_index, 0);
2616- short tint_color;
2617-
2618- /* get the tint color */
2619- // LP change: look up a table
2620- tint_color = CollectionTints[collection_index];
2621- // Idiot-proofing:
2622- if (tint_color >= NUMBER_OF_TINT_COLORS)
2623- tint_color = NONE;
2624- else
2625- tint_color = MAX(tint_color,NONE);
2626-
2627- /* build the tint table */
2628- if (tint_color!=NONE)
2629- {
2630- // LP addition: OpenGL support
2631- rgb_color &Color = tint_colors16[tint_color];
2632-#ifdef HAVE_OPENGL
2633- OGL_SetInfravisionTint(collection_index,true,Color.red/65535.0F,Color.green/65535.0F,Color.blue/65535.0F);
2634-#endif
2635- switch (bit_depth)
2636- {
2637- case 8:
2638- build_tinting_table8(colors, color_count, (unsigned char *)tint_table, tint_colors8[tint_color].start, tint_colors8[tint_color].count);
2639- break;
2640- case 16:
2641- build_tinting_table16(colors, color_count, (pixel16 *)tint_table, tint_colors16+tint_color);
2642- break;
2643- case 32:
2644- build_tinting_table32(colors, color_count, (pixel32 *)tint_table, tint_colors16+tint_color, is_opengl);
2645- break;
2646- }
2647- }
2648- else
2649- {
2650- // LP addition: OpenGL support
2651-#ifdef HAVE_OPENGL
2652- OGL_SetInfravisionTint(collection_index,false,1,1,1);
2653-#endif
2654- }
2655-}
2656-
2657-static void build_tinting_table8(
2658- struct rgb_color_value *colors,
2659- short color_count,
2660- pixel8 *tint_table,
2661- short tint_start,
2662- short tint_count)
2663-{
2664- short start, count;
2665-
2666- start= count= 0;
2667- while (get_next_color_run(colors, color_count, &start, &count))
2668- {
2669- short i;
2670-
2671- for (i=0; i<count; ++i)
2672- {
2673- short adjust= start ? 0 : 1;
2674- short value= (i*(tint_count+adjust))/count;
2675-
2676- value= (value>=tint_count) ? iBLACK : tint_start + value;
2677- tint_table[start+i]= value;
2678- }
2679- }
2680-}
2681-
2682-static void build_tinting_table16(
2683- struct rgb_color_value *colors,
2684- short color_count,
2685- pixel16 *tint_table,
2686- struct rgb_color *tint_color)
2687-{
2688- short i;
2689-
2690-#ifdef SDL
2691- SDL_PixelFormat *fmt = &pixel_format_16;
2692-#endif
2693-
2694- for (i= 0; i<color_count; ++i, ++colors)
2695- {
2696- int32 magnitude= ((int32)colors->red + (int32)colors->green + (int32)colors->blue)/(short)3;
2697-
2698-#ifdef SDL
2699- // Find optimal pixel value for video display
2700- *tint_table++= SDL_MapRGB(fmt,
2701- ((magnitude * tint_color->red) / 0xFFFF) >> 8,
2702- ((magnitude * tint_color->green) / 0xFFFF) >> 8,
2703- ((magnitude * tint_color->blue) / 0xFFFF) >> 8);
2704-#else
2705- // Mac xRGB 1555 pixel format
2706- *tint_table++= RGBCOLOR_TO_PIXEL16((magnitude*tint_color->red)/0xFFFF,
2707- (magnitude*tint_color->green)/0xFFFF, (magnitude*tint_color->blue)/0xFFFF);
2708-#endif
2709- }
2710-}
2711-
2712-static void build_tinting_table32(
2713- struct rgb_color_value *colors,
2714- short color_count,
2715- pixel32 *tint_table,
2716- struct rgb_color *tint_color,
2717- bool is_opengl)
2718-{
2719- short i;
2720-
2721-#ifdef SDL
2722- SDL_PixelFormat *fmt = &pixel_format_32;
2723-#endif
2724-
2725- for (i= 0; i<color_count; ++i, ++colors)
2726- {
2727- int32 magnitude= ((int32)colors->red + (int32)colors->green + (int32)colors->blue)/(short)3;
2728-
2729-#ifdef SDL
2730- // Find optimal pixel value for video display
2731- if (!is_opengl)
2732- *tint_table++= SDL_MapRGB(fmt,
2733- ((magnitude * tint_color->red) / 65535) >> 8,
2734- ((magnitude * tint_color->green) / 65535) >> 8,
2735- ((magnitude * tint_color->blue) / 65535) >> 8);
2736- else
2737-#endif
2738- // Mac xRGB 8888 pixel format
2739- *tint_table++= RGBCOLOR_TO_PIXEL32((magnitude*tint_color->red)/65535,
2740- (magnitude*tint_color->green)/65535, (magnitude*tint_color->blue)/65535);
2741- }
2742-}
2743-
2744-
2745-/* ---------- collection accessors */
2746-// Some originally from shapes_macintosh.c
2747-
2748-static struct collection_header *get_collection_header(
2749- short collection_index)
2750-{
2751- // This one is intended to bomb because collection indices can only be from 1 to 31,
2752- // short of drastic changes in how collection indices are specified (a bigger structure
2753- // than shape_descriptor, for example).
2754- collection_header *header = GetMemberWithBounds(collection_headers,collection_index,MAXIMUM_COLLECTIONS);
2755- vassert(header,csprintf(temporary,"Collection index out of range: %d",collection_index));
2756-
2757- return header;
2758-
2759- /*
2760- assert(collection_index>=0 && collection_index<MAXIMUM_COLLECTIONS);
2761-
2762- return collection_headers + collection_index;
2763- */
2764-}
2765-
2766-/*static*/ struct collection_definition *get_collection_definition(
2767- short collection_index)
2768-{
2769- return get_collection_header(collection_index)->collection;
2770-}
2771-
2772-static struct rgb_color_value *get_collection_colors(
2773- short collection_index,
2774- short clut_number)
2775-{
2776- collection_definition *definition = get_collection_definition(collection_index);
2777- if (!definition) return NULL;
2778- if (!(clut_number >= 0 && clut_number < definition->clut_count))
2779- return NULL;
2780-
2781- return &definition->color_tables[clut_number * definition->color_count];
2782-}
2783-
2784-struct rgb_color_value *get_collection_colors(
2785- short collection_index,
2786- short clut_number,
2787- int &num_colors)
2788-{
2789- collection_definition *definition = get_collection_definition(collection_index);
2790- if (!definition) return NULL;
2791- if (!(clut_number >=0 && clut_number < definition->clut_count)) return NULL;
2792- num_colors = definition->color_count;
2793- return &definition->color_tables[clut_number * definition->color_count];
2794-}
2795-
2796-static struct high_level_shape_definition *get_high_level_shape_definition(
2797- short collection_index,
2798- short high_level_shape_index)
2799-{
2800- struct collection_definition *definition = get_collection_definition(collection_index);
2801- if (!definition) return NULL;
2802-
2803- if (!(high_level_shape_index >= 0 && high_level_shape_index<definition->high_level_shapes.size()))
2804- return NULL;
2805-
2806- return (high_level_shape_definition *) &definition->high_level_shapes[high_level_shape_index][0];
2807-}
2808-
2809-struct low_level_shape_definition *get_low_level_shape_definition(
2810- short collection_index,
2811- short low_level_shape_index)
2812-{
2813- collection_definition *definition = get_collection_definition(collection_index);
2814- if (!definition) return NULL;
2815- if (low_level_shape_index >= 0 && low_level_shape_index < definition->low_level_shapes.size())
2816- {
2817- return &definition->low_level_shapes[low_level_shape_index];
2818- }
2819- else
2820- return NULL;
2821-}
2822-
2823-static struct bitmap_definition *get_bitmap_definition(
2824- short collection_index,
2825- short bitmap_index)
2826-{
2827- collection_definition *definition = get_collection_definition(collection_index);
2828- if (!definition) return NULL;
2829- if (!(bitmap_index >= 0 && bitmap_index < definition->bitmaps.size()))
2830- return NULL;
2831-
2832- return (bitmap_definition *) &definition->bitmaps[bitmap_index][0];
2833-}
2834-
2835-static void *get_collection_shading_tables(
2836- short collection_index,
2837- short clut_index)
2838-{
2839- void *shading_tables= get_collection_header(collection_index)->shading_tables;
2840-
2841- shading_tables = (uint8 *)shading_tables + clut_index*get_shading_table_size(collection_index);
2842-
2843- return shading_tables;
2844-}
2845-
2846-static void *get_collection_tint_tables(
2847- short collection_index,
2848- short tint_index)
2849-{
2850- struct collection_definition *definition= get_collection_definition(collection_index);
2851- if (!definition) return NULL;
2852-
2853- void *tint_table= get_collection_header(collection_index)->shading_tables;
2854-
2855- tint_table = (uint8 *)tint_table + get_shading_table_size(collection_index)*definition->clut_count + shading_table_size*tint_index;
2856-
2857- return tint_table;
2858-}
2859-
2860-// LP additions:
2861-
2862-// Whether or not collection is present
2863-bool is_collection_present(short collection_index)
2864-{
2865- collection_header *CollHeader = get_collection_header(collection_index);
2866- if (!CollHeader) return false;
2867- return collection_loaded(CollHeader);
2868-}
2869-
2870-// Number of texture frames in a collection (good for wall-texture error checking)
2871-short get_number_of_collection_frames(short collection_index)
2872-{
2873- struct collection_definition *Collection = get_collection_definition(collection_index);
2874- if (!Collection) return 0;
2875- return Collection->low_level_shape_count;
2876-}
2877-
2878-// Number of bitmaps in a collection (good for allocating texture information for OpenGL)
2879-short get_number_of_collection_bitmaps(short collection_index)
2880-{
2881- struct collection_definition *Collection = get_collection_definition(collection_index);
2882- if (!Collection) return 0;
2883- return Collection->bitmap_count;
2884-}
2885-
2886-// Which bitmap index for a frame (good for OpenGL texture rendering)
2887-short get_bitmap_index(short collection_index, short low_level_shape_index)
2888-{
2889- struct low_level_shape_definition *low_level_shape= get_low_level_shape_definition(collection_index, low_level_shape_index);
2890- if (!low_level_shape) return NONE;
2891- return low_level_shape->bitmap_index;
2892-}
2893-
2894-
2895-// XML elements for parsing infravision specification;
2896-// this is a specification of a set of infravision colors
2897-// and which collections are to get them
2898-
2899-short *OriginalCollectionTints = NULL;
2900-// This assigns an infravision color to a collection
2901-class XML_InfravisionAssignParser: public XML_ElementParser
2902-{
2903- bool IsPresent[2];
2904- short Coll, Color;
2905-
2906-public:
2907- bool Start();
2908- bool HandleAttribute(const char *Tag, const char *Value);
2909- bool AttributesDone();
2910- bool ResetValues();
2911-
2912- XML_InfravisionAssignParser(): XML_ElementParser("assign") {}
2913-};
2914-
2915-bool XML_InfravisionAssignParser::Start()
2916-{
2917- // back up old values first
2918- if (!OriginalCollectionTints) {
2919- OriginalCollectionTints = (short *) malloc(sizeof(short) * NUMBER_OF_COLLECTIONS);
2920- assert(OriginalCollectionTints);
2921- for (int i = 0; i < NUMBER_OF_COLLECTIONS; i++)
2922- OriginalCollectionTints[i] = CollectionTints[i];
2923- }
2924-
2925- for (int k=0; k<2; k++)
2926- IsPresent[k] = false;
2927- return true;
2928-}
2929-
2930-bool XML_InfravisionAssignParser::HandleAttribute(const char *Tag, const char *Value)
2931-{
2932- if (StringsEqual(Tag,"coll"))
2933- {
2934- if (ReadBoundedInt16Value(Value,Coll,0,NUMBER_OF_COLLECTIONS-1))
2935- {
2936- IsPresent[0] = true;
2937- return true;
2938- }
2939- else return false;
2940- }
2941- else if (StringsEqual(Tag,"color"))
2942- {
2943- if (ReadBoundedInt16Value(Value,Color,0,NUMBER_OF_TINT_COLORS-1))
2944- {
2945- IsPresent[1] = true;
2946- return true;
2947- }
2948- else return false;
2949- }
2950- UnrecognizedTag();
2951- return false;
2952-}
2953-
2954-bool XML_InfravisionAssignParser::AttributesDone()
2955-{
2956- // Verify...
2957- bool AllPresent = true;
2958- for (int k=0; k<2; k++)
2959- if (!IsPresent[k]) AllPresent = false;
2960-
2961- if (!AllPresent)
2962- {
2963- AttribsMissing();
2964- return false;
2965- }
2966-
2967- // Put into place
2968- CollectionTints[Coll] = Color;
2969- return true;
2970-}
2971-
2972-bool XML_InfravisionAssignParser::ResetValues()
2973-{
2974- if (OriginalCollectionTints) {
2975- for (int i = 0; i < NUMBER_OF_COLLECTIONS; i++)
2976- CollectionTints[i] = OriginalCollectionTints[i];
2977- free(OriginalCollectionTints);
2978- OriginalCollectionTints = NULL;
2979- }
2980- return true;
2981-}
2982-
2983-static XML_InfravisionAssignParser InfravisionAssignParser;
2984-
2985-
2986-struct rgb_color *original_tint_colors16 = NULL;
2987-// Subclassed to set the color objects appropriately
2988-class XML_InfravisionParser: public XML_ElementParser
2989-{
2990-public:
2991- bool Start()
2992- {
2993- // back up old values first
2994- if (!original_tint_colors16) {
2995- original_tint_colors16 = (struct rgb_color *) malloc(sizeof(struct rgb_color) * NUMBER_OF_TINT_COLORS);
2996- assert(original_tint_colors16);
2997- for (int i = 0; i < NUMBER_OF_TINT_COLORS; i++)
2998- original_tint_colors16[i] = tint_colors16[i];
2999- }
3000- Color_SetArray(tint_colors16,NUMBER_OF_TINT_COLORS);
3001- return true;
3002- }
3003- bool HandleAttribute(const char *Tag, const char *Value)
3004- {
3005- UnrecognizedTag();
3006- return false;
3007- }
3008- bool ResetValues()
3009- {
3010- if (original_tint_colors16) {
3011- for (int i = 0; i < NUMBER_OF_TINT_COLORS; i++)
3012- tint_colors16[i] = original_tint_colors16[i];
3013- free(original_tint_colors16);
3014- original_tint_colors16 = NULL;
3015- }
3016- return true;
3017- }
3018-
3019- XML_InfravisionParser(): XML_ElementParser("infravision") {}
3020-};
3021-
3022-static XML_InfravisionParser InfravisionParser;
3023-
3024-// LP change: added infravision-parser export
3025-XML_ElementParser *Infravision_GetParser()
3026-{
3027- InfravisionParser.AddChild(&InfravisionAssignParser);
3028- InfravisionParser.AddChild(Color_GetParser());
3029-
3030- return &InfravisionParser;
3031-}
1+/*
2+SHAPES.C
3+
4+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5+ and the "Aleph One" developers.
6+
7+ This program is free software; you can redistribute it and/or modify
8+ it under the terms of the GNU General Public License as published by
9+ the Free Software Foundation; either version 3 of the License, or
10+ (at your option) any later version.
11+
12+ This program is distributed in the hope that it will be useful,
13+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+ GNU General Public License for more details.
16+
17+ This license is contained in the file "COPYING",
18+ which is included with this source code; it is available online at
19+ http://www.gnu.org/licenses/gpl.html
20+
21+Saturday, September 4, 1993 9:26:41 AM
22+
23+Thursday, May 19, 1994 9:06:28 AM
24+ unification of wall and object shapes complete, new shading table builder.
25+Wednesday, June 22, 1994 11:55:07 PM
26+ we now read data from alainユs shape extractor.
27+Saturday, July 9, 1994 3:22:11 PM
28+ lightening_table removed; we now build darkening tables on a collection-by-collection basis
29+ (one 8k darkening table per clut permutation of the given collection)
30+Monday, October 3, 1994 4:17:15 PM (Jason)
31+ compressed or uncompressed collection resources
32+Friday, June 16, 1995 11:34:08 AM (Jason)
33+ self-luminescent colors
34+
35+Jan 30, 2000 (Loren Petrich):
36+ Changed "new" to "_new" to make data structures more C++-friendly
37+ Did some typecasts
38+
39+Feb 3, 2000 (Loren Petrich):
40+ Changed _collection_madd to _collection_vacbob (later changed all "vacbob"'s to "civilian_fusion"'s)
41+
42+Feb 4, 2000 (Loren Petrich):
43+ Changed halt() to assert(false) for better debugging
44+
45+Feb 12, 2000 (Loren Petrich):
46+ Set up a fallback strategy for the colors;
47+ when there are more colors in all the tables than there are in the general color table,
48+ then look for the nearest one.
49+
50+Feb 24, 2000 (Loren Petrich):
51+ Added get_number_of_collection_frames(), so as to assist in wall-texture error checking
52+
53+Mar 14, 2000 (Loren Petrich):
54+ Added accessors for number of bitmaps and which bitmap index for a frame index;
55+ these will be useful for OpenGL rendering
56+
57+Mar 23, 2000 (Loren Petrich):
58+ Made infravision tinting more generic and reassignable
59+
60+Aug 12, 2000 (Loren Petrich):
61+ Using object-oriented file handler
62+
63+Aug 14, 2000 (Loren Petrich):
64+ Turned collection and shading-table handles into pointers,
65+ because handles are needlessly MacOS-specific,
66+ and because these are variable-format objects.
67+
68+Aug 26, 2000 (Loren Petrich):
69+ Moved get_default_shapes_spec() to preprocess_map_mac.c
70+
71+Sept 2, 2000 (Loren Petrich):
72+ Added shapes-file unpacking.
73+
74+Jan 17, 2001 (Loren Petrich):
75+ Added support for offsets for OpenGL-rendered substitute textures
76+*/
77+
78+/*
79+//gracefully handle out-of-memory conditions when loading shapes. it will happen.
80+//get_shape_descriptors() needs to look at high-level instead of low-level shapes when fetching scenery instead of walls/ceilings/floors
81+//get_shape_information() is called often, and is quite slow
82+//it is possible to have more than 255 low-level shapes in a collection, which means the existing shape_descriptor is too small
83+//must build different shading tables for each collection (even in 8-bit, for alternate color tables)
84+*/
85+
86+#include "cseries.h"
87+
88+#include <stdio.h>
89+#include <stdlib.h>
90+#include <string.h>
91+
92+#include "shell.h"
93+#include "render.h"
94+#include "interface.h"
95+#include "collection_definition.h"
96+#include "screen.h"
97+#include "game_errors.h"
98+#include "FileHandler.h"
99+#include "progress.h"
100+
101+#include "map.h"
102+
103+// LP addition: OpenGL support
104+#include "OGL_Render.h"
105+#include "OGL_LoadScreen.h"
106+
107+// LP addition: infravision XML setup needs colors
108+#include "ColorParser.h"
109+
110+#include "Packing.h"
111+#include "SW_Texture_Extras.h"
112+
113+#include <SDL_rwops.h>
114+#include <memory>
115+
116+#include <boost/shared_ptr.hpp>
117+
118+#include "Plugins.h"
119+
120+#ifdef env68k
121+#pragma segment shell
122+#endif
123+
124+/* ---------- constants */
125+
126+#define iWHITE 1
127+#ifdef SCREAMING_METAL
128+#define iBLACK 255
129+#else
130+#define iBLACK 18
131+#endif
132+
133+/* each collection has a tint table which (fully) tints the clut of that collection to whatever it
134+ looks like through the light enhancement goggles */
135+#define NUMBER_OF_TINT_TABLES 1
136+
137+// Moved from shapes_macintosh.c:
138+
139+// Possibly of historical interest:
140+// #define COLLECTIONS_RESOURCE_BASE 128
141+// #define COLLECTIONS_RESOURCE_BASE16 1128
142+
143+enum /* collection status */
144+{
145+ markNONE,
146+ markLOAD= 1,
147+ markUNLOAD= 2,
148+ markSTRIP= 4 /* we donユt want bitmaps, just high/low-level shape data */,
149+ markPATCHED = 8 /* force re-load */
150+};
151+
152+enum /* flags */
153+{
154+ _collection_is_stripped= 0x0001
155+};
156+
157+/* ---------- macros */
158+
159+// LP: fake portable-files stuff
160+#ifdef mac
161+inline short memory_error() {return MemError();}
162+#else
163+inline short memory_error() {return 0;}
164+#endif
165+
166+/* ---------- structures */
167+
168+/* ---------- globals */
169+
170+extern SDL_Surface* world_pixels;
171+
172+#include "shape_definitions.h"
173+
174+static pixel16 *global_shading_table16= (pixel16 *) NULL;
175+static pixel32 *global_shading_table32= (pixel32 *) NULL;
176+
177+short number_of_shading_tables, shading_table_fractional_bits, shading_table_size;
178+
179+// LP addition: opened-shapes-file object
180+static OpenedFile ShapesFile;
181+static OpenedResourceFile M1ShapesFile;
182+static bool m1_shapes;
183+
184+/* ---------- private prototypes */
185+
186+static void update_color_environment(bool is_opengl);
187+static short find_or_add_color(struct rgb_color_value *color, struct rgb_color_value *colors, short *color_count, bool update_flags);
188+static void _change_clut(void (*change_clut_proc)(struct color_table *color_table), struct rgb_color_value *colors, short color_count);
189+
190+static void build_shading_tables8(struct rgb_color_value *colors, short color_count, pixel8 *shading_tables);
191+static void build_shading_tables16(struct rgb_color_value *colors, short color_count, pixel16 *shading_tables, byte *remapping_table, bool is_opengl);
192+static void build_shading_tables32(struct rgb_color_value *colors, short color_count, pixel32 *shading_tables, byte *remapping_table, bool is_opengl);
193+static void build_global_shading_table16(void);
194+static void build_global_shading_table32(void);
195+
196+static bool get_next_color_run(struct rgb_color_value *colors, short color_count, short *start, short *count);
197+static bool new_color_run(struct rgb_color_value *_new, struct rgb_color_value *last);
198+
199+static int32 get_shading_table_size(short collection_code);
200+
201+static void build_collection_tinting_table(struct rgb_color_value *colors, short color_count, short collection_index, bool is_opengl);
202+static void build_tinting_table8(struct rgb_color_value *colors, short color_count, pixel8 *tint_table, short tint_start, short tint_count);
203+static void build_tinting_table16(struct rgb_color_value *colors, short color_count, pixel16 *tint_table, struct rgb_color *tint_color);
204+static void build_tinting_table32(struct rgb_color_value *colors, short color_count, pixel32 *tint_table, struct rgb_color *tint_color, bool is_opengl);
205+
206+static void precalculate_bit_depth_constants(void);
207+
208+static bool collection_loaded(struct collection_header *header);
209+static void unload_collection(struct collection_header *header);
210+static void unlock_collection(struct collection_header *header);
211+static void lock_collection(struct collection_header *header);
212+static bool load_collection(short collection_index, bool strip);
213+#ifdef mac
214+static byte *unpack_collection(byte *collection, int32 length, bool strip);
215+#endif
216+
217+static void shutdown_shape_handler(void);
218+static void close_shapes_file(void);
219+
220+#ifdef mac
221+static byte *read_object_from_file(OpenedFile& OFile, int32 offset, int32 length);
222+#endif
223+
224+// static byte *make_stripped_collection(byte *collection);
225+
226+/* --------- collection accessor prototypes */
227+
228+// Modified to return NULL for unloaded collections and out-of-range indices for collection contents.
229+// This is to allow for more graceful degradation.
230+
231+static struct collection_header *get_collection_header(short collection_index);
232+/*static*/ struct collection_definition *get_collection_definition(short collection_index);
233+static void *get_collection_shading_tables(short collection_index, short clut_index);
234+static void *get_collection_tint_tables(short collection_index, short tint_index);
235+static struct rgb_color_value *get_collection_colors(short collection_index, short clut_number);
236+static struct high_level_shape_definition *get_high_level_shape_definition(short collection_index, short high_level_shape_index);
237+static struct bitmap_definition *get_bitmap_definition(short collection_index, short bitmap_index);
238+
239+
240+#include <SDL_endian.h>
241+#include "byte_swapping.h"
242+
243+/*
244+ * Initialize shapes handling
245+ */
246+
247+static void initialize_pixmap_handler()
248+{
249+ // nothing to do
250+}
251+
252+
253+/*
254+ * Convert shape to surface
255+ */
256+
257+// ZZZ extension: pass out (if non-NULL) a pointer to a block of pixel data -
258+// caller should free() that storage after freeing the returned surface.
259+// Only needed for RLE-encoded shapes.
260+// Note that default arguments are used to make this function
261+// source-code compatible with existing usage.
262+// Note also that inShrinkImage currently only applies to RLE shapes.
263+SDL_Surface *get_shape_surface(int shape, int inCollection, byte** outPointerToPixelData, float inIllumination, bool inShrinkImage)
264+{
265+ // Get shape information
266+ int collection_index = GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(shape));
267+ int clut_index = GET_COLLECTION_CLUT(GET_DESCRIPTOR_COLLECTION(shape));
268+ int low_level_shape_index = GET_DESCRIPTOR_SHAPE(shape);
269+
270+ if(inCollection != NONE) {
271+ collection_index = GET_COLLECTION(inCollection);
272+ clut_index = GET_COLLECTION_CLUT(inCollection);
273+ low_level_shape_index = shape;
274+ }
275+
276+ struct collection_definition *collection = get_collection_definition(collection_index);
277+ struct low_level_shape_definition *low_level_shape = get_low_level_shape_definition(collection_index, low_level_shape_index);
278+ if (!low_level_shape) return NULL;
279+ struct bitmap_definition *bitmap;
280+ SDL_Color colors[256];
281+
282+ if(inIllumination >= 0) {
283+ assert(inIllumination <= 1.0f);
284+
285+ // ZZZ: get shading tables to use instead of CLUT, if requested
286+ void* shading_tables_as_void;
287+ extended_get_shape_bitmap_and_shading_table(BUILD_COLLECTION(collection_index, clut_index), low_level_shape_index,
288+ &bitmap, &shading_tables_as_void, _shading_normal);
289+ if (!bitmap) return NULL;
290+
291+ switch(bit_depth) {
292+ case 16:
293+ {
294+ uint16* shading_tables = (uint16*) shading_tables_as_void;
295+ shading_tables += 256 * (int)(inIllumination * (number_of_shading_tables - 1));
296+
297+ // Extract color table - ZZZ change to use shading table rather than CLUT. Hope it works.
298+
299+ SDL_PixelFormat *fmt = &pixel_format_16;
300+ for (int i = 0; i < 256; i++) {
301+ SDL_GetRGB(shading_tables[i], fmt, &colors[i].r, &colors[i].g, &colors[i].b);
302+ }
303+ }
304+ break;
305+
306+ case 32:
307+ {
308+ uint32* shading_tables = (uint32*) shading_tables_as_void;
309+ shading_tables += 256 * (int)(inIllumination * (number_of_shading_tables - 1));
310+
311+ // Extract color table - ZZZ change to use shading table rather than CLUT. Hope it works.
312+ for(int i = 0; i < 256; i++) {
313+ colors[i].r = RED32(shading_tables[i]);
314+ colors[i].g = GREEN32(shading_tables[i]);
315+ colors[i].b = BLUE32(shading_tables[i]);
316+ }
317+ }
318+ break;
319+
320+ default:
321+ vhalt("oops, bit_depth not supported for get_shape_surface with illumination\n");
322+ break;
323+ }
324+
325+ } // inIllumination >= 0
326+ else { // inIllumination < 0
327+ bitmap = get_bitmap_definition(collection_index, low_level_shape->bitmap_index);
328+ if(!bitmap) return NULL;
329+
330+ // Extract color table
331+ int num_colors = collection->color_count - NUMBER_OF_PRIVATE_COLORS;
332+ rgb_color_value *src_colors = get_collection_colors(collection_index, clut_index) + NUMBER_OF_PRIVATE_COLORS;
333+ for (int i=0; i<num_colors; i++) {
334+ int idx = src_colors[i].value;
335+ colors[idx].r = src_colors[i].red >> 8;
336+ colors[idx].g = src_colors[i].green >> 8;
337+ colors[idx].b = src_colors[i].blue >> 8;
338+ }
339+ } // inIllumination < 0
340+
341+
342+ SDL_Surface *s = NULL;
343+ if (bitmap->bytes_per_row == NONE) {
344+
345+ // ZZZ: process RLE-encoded shape
346+
347+ // Allocate storage for un-RLE'd pixels
348+ uint32 theNumberOfStorageBytes = bitmap->width * bitmap->height * sizeof(byte);
349+ byte* pixel_storage = (byte*) malloc(theNumberOfStorageBytes);
350+ memset(pixel_storage, 0, theNumberOfStorageBytes);
351+
352+ // Here, a "run" is a row or column. An "element" is a single pixel's data.
353+ // We always go forward through the source data. Thus, the offsets for where the next run
354+ // or element goes into the destination data area change depending on the circumstances.
355+ int16 theNumRuns;
356+ int16 theNumElementsPerRun;
357+ int16 theDestDataNextRunOffset;
358+ int16 theDestDataNextElementOffset;
359+
360+ // Is this row-major or column-major?
361+ if(bitmap->flags & _COLUMN_ORDER_BIT) {
362+ theNumRuns = bitmap->width;
363+ theNumElementsPerRun = bitmap->height;
364+ theDestDataNextRunOffset = (low_level_shape->flags & _X_MIRRORED_BIT) ? -1 : 1;
365+ theDestDataNextElementOffset = (low_level_shape->flags & _Y_MIRRORED_BIT) ? -bitmap->width : bitmap->width;
366+ }
367+ else {
368+ theNumRuns = bitmap->height;
369+ theNumElementsPerRun = bitmap->width;
370+ theDestDataNextElementOffset = (low_level_shape->flags & _X_MIRRORED_BIT) ? -1 : 1;
371+ theDestDataNextRunOffset = (low_level_shape->flags & _Y_MIRRORED_BIT) ? -bitmap->width : bitmap->width;
372+ }
373+
374+ // Figure out where our first byte will be written
375+ byte* theDestDataStartAddress = pixel_storage;
376+
377+ if(low_level_shape->flags & _X_MIRRORED_BIT)
378+ theDestDataStartAddress += bitmap->width - 1;
379+
380+ if(low_level_shape->flags & _Y_MIRRORED_BIT)
381+ theDestDataStartAddress += bitmap->width * (bitmap->height - 1);
382+
383+ // Walk through runs, un-RLE'ing as we go
384+ for(int run = 0; run < theNumRuns; run++) {
385+ uint16* theLengthData = (uint16*) bitmap->row_addresses[run];
386+ uint16 theFirstOpaquePixelElement = SDL_SwapBE16(theLengthData[0]);
387+ uint16 theFirstTransparentAfterOpaquePixelElement = SDL_SwapBE16(theLengthData[1]);
388+ uint16 theNumberOfOpaquePixels = theFirstTransparentAfterOpaquePixelElement - theFirstOpaquePixelElement;
389+
390+ byte* theOriginalPixelData = (byte*) &theLengthData[2];
391+ byte* theUnpackedPixelData;
392+
393+ theUnpackedPixelData = theDestDataStartAddress + run * theDestDataNextRunOffset
394+ + theFirstOpaquePixelElement * theDestDataNextElementOffset;
395+
396+ for(int i = 0; i < theNumberOfOpaquePixels; i++) {
397+ assert(theUnpackedPixelData >= pixel_storage);
398+ assert(theUnpackedPixelData < (pixel_storage + theNumberOfStorageBytes));
399+ *theUnpackedPixelData = *theOriginalPixelData;
400+ theUnpackedPixelData += theDestDataNextElementOffset;
401+ theOriginalPixelData++;
402+ }
403+ }
404+
405+ // Let's shrink the image if the user wants us to.
406+ // We do this here by discarding every other pixel in each direction.
407+ // Really, I guess there's probably a library out there that would do nice smoothing
408+ // for us etc. that we should use here. I just want to hack something out now and run with it.
409+ int image_width = bitmap->width;
410+ int image_height = bitmap->height;
411+
412+ if(inShrinkImage) {
413+ int theLargerWidth = bitmap->width;
414+ int theLargerHeight = bitmap->height;
415+ byte* theLargerPixelStorage = pixel_storage;
416+ int theSmallerWidth = theLargerWidth / 2 + theLargerWidth % 2;
417+ int theSmallerHeight = theLargerHeight / 2 + theLargerHeight % 2;
418+ byte* theSmallerPixelStorage = (byte*) malloc(theSmallerWidth * theSmallerHeight);
419+
420+ for(int y = 0; y < theSmallerHeight; y++) {
421+ for(int x = 0; x < theSmallerWidth; x++) {
422+ theSmallerPixelStorage[y * theSmallerWidth + x] =
423+ theLargerPixelStorage[(y * theLargerWidth + x) * 2];
424+ }
425+ }
426+
427+ free(pixel_storage);
428+
429+ pixel_storage = theSmallerPixelStorage;
430+ image_width = theSmallerWidth;
431+ image_height = theSmallerHeight;
432+ }
433+
434+ // Now we can create a surface from this new storage
435+ s = SDL_CreateRGBSurfaceFrom(pixel_storage, image_width, image_height, 8, image_width, 0xff, 0xff, 0xff, 0xff);
436+
437+ if(s != NULL) {
438+ // If caller is not prepared to take this data, it's a coding error.
439+ assert(outPointerToPixelData != NULL);
440+ *outPointerToPixelData = pixel_storage;
441+
442+ // Set color table
443+ SDL_SetColors(s, colors, 0, 256);
444+
445+ // Set transparent pixel (color #0)
446+ SDL_SetColorKey(s, SDL_SRCCOLORKEY, 0);
447+ }
448+
449+ } else {
450+ // Row-order shape, we can directly create a surface from it
451+ if (collection->type == _wall_collection)
452+ {
453+ s = SDL_CreateRGBSurfaceFrom(bitmap->row_addresses[0], bitmap->height, bitmap->width, 8, bitmap->bytes_per_row, 0xff, 0xff, 0xff, 0xff);
454+ }
455+ else
456+ {
457+ s = SDL_CreateRGBSurfaceFrom(bitmap->row_addresses[0], bitmap->width, bitmap->height, 8, bitmap->bytes_per_row, 0xff, 0xff, 0xff, 0xff);
458+ }
459+ // ZZZ: caller should not dispose of any additional data - just free the surface.
460+ if(outPointerToPixelData != NULL)
461+ *outPointerToPixelData = NULL;
462+
463+ if(s != NULL) {
464+ // Set color table
465+ SDL_SetColors(s, colors, 0, 256);
466+ }
467+ }
468+
469+ return s;
470+}
471+
472+static void load_collection_definition(collection_definition* cd, SDL_RWops *p)
473+{
474+ cd->version = SDL_ReadBE16(p);
475+ cd->type = SDL_ReadBE16(p);
476+ cd->flags = SDL_ReadBE16(p);
477+ cd->color_count = SDL_ReadBE16(p);
478+ cd->clut_count = SDL_ReadBE16(p);
479+ cd->color_table_offset = SDL_ReadBE32(p);
480+ cd->high_level_shape_count = SDL_ReadBE16(p);
481+ cd->high_level_shape_offset_table_offset = SDL_ReadBE32(p);
482+ cd->low_level_shape_count = SDL_ReadBE16(p);
483+ cd->low_level_shape_offset_table_offset = SDL_ReadBE32(p);
484+ cd->bitmap_count = SDL_ReadBE16(p);
485+ cd->bitmap_offset_table_offset = SDL_ReadBE32(p);
486+ cd->pixels_to_world = SDL_ReadBE16(p);
487+ SDL_ReadBE32(p); // skip size
488+ SDL_RWseek(p, 253 * sizeof(int16), SEEK_CUR); // unused
489+
490+ // resize members
491+ cd->color_tables.resize(cd->clut_count * cd->color_count);
492+ cd->high_level_shapes.resize(cd->high_level_shape_count);
493+ cd->low_level_shapes.resize(cd->low_level_shape_count);
494+ cd->bitmaps.resize(cd->bitmap_count);
495+
496+}
497+
498+static void load_clut(rgb_color_value *r, int count, SDL_RWops *p)
499+{
500+ for (int i = 0; i < count; i++, r++)
501+ {
502+ SDL_RWread(p, r, 1, 2);
503+ r->red = SDL_ReadBE16(p);
504+ r->green = SDL_ReadBE16(p);
505+ r->blue = SDL_ReadBE16(p);
506+ }
507+}
508+
509+static void load_high_level_shape(std::vector<uint8>& shape, SDL_RWops *p)
510+{
511+ int16 type = SDL_ReadBE16(p);
512+ int16 flags = SDL_ReadBE16(p);
513+ char name[HIGH_LEVEL_SHAPE_NAME_LENGTH + 2];
514+ SDL_RWread(p, name, 1, HIGH_LEVEL_SHAPE_NAME_LENGTH + 2);
515+ int16 number_of_views = SDL_ReadBE16(p);
516+ int16 frames_per_view = SDL_ReadBE16(p);
517+
518+ // Convert low-level shape index list
519+ int num_views;
520+ switch (number_of_views) {
521+ case _unanimated:
522+ case _animated1:
523+ num_views = 1;
524+ break;
525+ case _animated3to4:
526+ case _animated4:
527+ num_views = 4;
528+ break;
529+ case _animated3to5:
530+ case _animated5:
531+ num_views = 5;
532+ break;
533+ case _animated2to8:
534+ case _animated5to8:
535+ case _animated8:
536+ num_views = 8;
537+ break;
538+ default:
539+ num_views = number_of_views;
540+ break;
541+ }
542+
543+ shape.resize(sizeof(high_level_shape_definition) + num_views * frames_per_view * sizeof(int16));
544+
545+ high_level_shape_definition *d = (high_level_shape_definition *) &shape[0];
546+
547+ d->type = type;
548+ d->flags = flags;
549+ memcpy(d->name, name, HIGH_LEVEL_SHAPE_NAME_LENGTH + 2);
550+ d->number_of_views = number_of_views;
551+ d->frames_per_view = frames_per_view;
552+ d->ticks_per_frame = SDL_ReadBE16(p);
553+ d->key_frame = SDL_ReadBE16(p);
554+ d->transfer_mode = SDL_ReadBE16(p);
555+ d->transfer_mode_period = SDL_ReadBE16(p);
556+ d->first_frame_sound = SDL_ReadBE16(p);
557+ d->key_frame_sound = SDL_ReadBE16(p);
558+ d->last_frame_sound = SDL_ReadBE16(p);
559+ d->pixels_to_world = SDL_ReadBE16(p);
560+ d->loop_frame = SDL_ReadBE16(p);
561+ SDL_RWseek(p, 14 * sizeof(int16), SEEK_CUR);
562+
563+ // Convert low-level shape index list
564+ for (int j = 0; j < num_views * d->frames_per_view; j++) {
565+ d->low_level_shape_indexes[j] = SDL_ReadBE16(p);
566+ }
567+}
568+
569+static void load_low_level_shape(low_level_shape_definition *d, SDL_RWops *p)
570+{
571+ d->flags = SDL_ReadBE16(p);
572+ d->minimum_light_intensity = SDL_ReadBE32(p);
573+ d->bitmap_index = SDL_ReadBE16(p);
574+ d->origin_x = SDL_ReadBE16(p);
575+ d->origin_y = SDL_ReadBE16(p);
576+ d->key_x = SDL_ReadBE16(p);
577+ d->key_y = SDL_ReadBE16(p);
578+ d->world_left = SDL_ReadBE16(p);
579+ d->world_right = SDL_ReadBE16(p);
580+ d->world_top = SDL_ReadBE16(p);
581+ d->world_bottom = SDL_ReadBE16(p);
582+ d->world_x0 = SDL_ReadBE16(p);
583+ d->world_y0 = SDL_ReadBE16(p);
584+ SDL_RWseek(p, 4 * sizeof(int16), SEEK_CUR);
585+}
586+
587+static void convert_m1_rle(std::vector<uint8>& bitmap, int scanlines, int scanline_length, SDL_RWops* p)
588+{
589+// std::vector<uint8> bitmap;
590+ for (int scanline = 0; scanline < scanlines; ++scanline)
591+ {
592+ std::vector<uint8> scanline_data(scanline_length);
593+ uint8* dst = &scanline_data[0];
594+ uint8* sentry = &scanline_data[scanline_length];
595+
596+ while (true)
597+ {
598+ int16 opcode = SDL_ReadBE16(p);
599+ if (opcode > 0)
600+ {
601+ assert(dst + opcode <= sentry);
602+ SDL_RWread(p, dst, opcode, 1);
603+ dst += opcode;
604+ }
605+ else if (opcode < 0)
606+ {
607+ assert(dst - opcode <= sentry);
608+ dst -= opcode;
609+ }
610+ else
611+ break;
612+ }
613+
614+ assert (dst == sentry);
615+
616+ // Find M2/oo-format RLE compression;
617+ // it needs the first nonblank pixel and the last nonblank one + 1
618+ int16 first = 0;
619+ int16 last = 0;
620+ for (int i = 0; i < scanline_length; ++i)
621+ {
622+ if (scanline_data[i] != 0)
623+ {
624+ first = i;
625+ break;
626+ }
627+ }
628+
629+ for (int i = scanline_length - 1; i >= 0; --i)
630+ {
631+ if (scanline_data[i] != 0)
632+ {
633+ last = i + 1;
634+ break;
635+ }
636+ }
637+
638+ if (last < first) last = first;
639+
640+ bitmap.push_back(first >> 8);
641+ bitmap.push_back(first & 0xff);
642+ bitmap.push_back(last >> 8);
643+ bitmap.push_back(last & 0xff);
644+ bitmap.insert(bitmap.end(), &scanline_data[first], &scanline_data[last]);
645+ }
646+}
647+
648+static void load_bitmap(std::vector<uint8>& bitmap, SDL_RWops *p)
649+{
650+ bitmap_definition b;
651+
652+ // Convert bitmap definition
653+ b.width = SDL_ReadBE16(p);
654+ b.height = SDL_ReadBE16(p);
655+ b.bytes_per_row = SDL_ReadBE16(p);
656+ b.flags = SDL_ReadBE16(p);
657+ b.bit_depth = SDL_ReadBE16(p);
658+
659+ // guess how big to make it
660+ int rows = (b.flags & _COLUMN_ORDER_BIT) ? b.width : b.height;
661+ int row_len = (b.flags & _COLUMN_ORDER_BIT) ? b.height : b.width;
662+
663+ SDL_RWseek(p, 16, SEEK_CUR);
664+
665+ // Skip row address pointers
666+ SDL_RWseek(p, (rows + 1) * sizeof(uint32), SEEK_CUR);
667+
668+ if (b.bytes_per_row == NONE)
669+ {
670+ if (m1_shapes)
671+ {
672+ // make enough room for the definition, then append as we convert RLE
673+ bitmap.resize(sizeof(bitmap_definition) + rows * sizeof(pixel8*));
674+ }
675+ else
676+ {
677+ // ugly--figure out how big it's going to be
678+
679+ int32 size = 0;
680+ for (int j = 0; j < rows; j++) {
681+ int16 first = SDL_ReadBE16(p);
682+ int16 last = SDL_ReadBE16(p);
683+ size += 4;
684+ SDL_RWseek(p, last - first, SEEK_CUR);
685+ size += last - first;
686+ }
687+
688+ bitmap.resize(sizeof(bitmap_definition) + rows * sizeof(pixel8*) + size);
689+
690+ // Now, seek back
691+ SDL_RWseek(p, -size, SEEK_CUR);
692+ }
693+ }
694+ else
695+ {
696+ bitmap.resize(sizeof(bitmap_definition) + rows * sizeof(pixel8*) + rows * b.bytes_per_row);
697+ }
698+
699+
700+ uint8* c = &bitmap[0];
701+ bitmap_definition *d = (bitmap_definition *) &bitmap[0];
702+ d->width = b.width;
703+ d->height = b.height;
704+ d->bytes_per_row = b.bytes_per_row;
705+ d->flags = b.flags;
706+ d->flags &= ~_PATCHED_BIT; // Anvil sets unused flags :( we'll set it later
707+ d->bit_depth = b.bit_depth;
708+ c += sizeof(bitmap_definition);
709+
710+ // Skip row address pointers
711+ c += rows * sizeof(pixel8 *);
712+
713+ // Copy bitmap data
714+ if (d->bytes_per_row == NONE)
715+ {
716+ // RLE format
717+
718+ if (m1_shapes)
719+ {
720+ convert_m1_rle(bitmap, rows, row_len, p);
721+ }
722+ else
723+ {
724+ for (int j = 0; j < rows; j++) {
725+ int16 first = SDL_ReadBE16(p);
726+ int16 last = SDL_ReadBE16(p);
727+ *(c++) = (uint8)(first >> 8);
728+ *(c++) = (uint8)(first);
729+ *(c++) = (uint8)(last >> 8);
730+ *(c++) = (uint8)(last);
731+ SDL_RWread(p, c, 1, last - first);
732+ c += last - first;
733+ }
734+ }
735+ } else {
736+ SDL_RWread(p, c, d->bytes_per_row, rows);
737+ c += rows * d->bytes_per_row;
738+ }
739+
740+}
741+
742+static void allocate_shading_tables(short collection_index, bool strip)
743+{
744+ collection_header *header = get_collection_header(collection_index);
745+ // Allocate enough space for this collection's shading tables
746+ if (strip)
747+ header->shading_tables = NULL;
748+ else {
749+ collection_definition *definition = get_collection_definition(collection_index);
750+ header->shading_tables = (byte *)malloc(get_shading_table_size(collection_index) * definition->clut_count + shading_table_size * NUMBER_OF_TINT_TABLES);
751+ }
752+}
753+
754+/*
755+ * Load collection
756+ */
757+
758+static bool load_collection(short collection_index, bool strip)
759+{
760+ SDL_RWops* p;
761+ boost::shared_ptr<SDL_RWops> m1_p; // automatic deallocation
762+ LoadedResource r;
763+ int32 src_offset;
764+
765+ collection_header *header = get_collection_header(collection_index);
766+
767+ if (m1_shapes)
768+ {
769+ // Collections are stored in .256 resources
770+ if (!M1ShapesFile.Get('.', '2', '5', '6', 128 + collection_index, r))
771+ {
772+ return false;
773+ }
774+
775+ m1_p.reset(SDL_RWFromConstMem(r.GetPointer(), r.GetLength()), SDL_FreeRW);
776+ p = m1_p.get();
777+ src_offset = 0;
778+ }
779+ else
780+ {
781+ // Get offset and length of data in source file from header
782+
783+ if (bit_depth == 8 || header->offset16 == -1) {
784+ if (header->offset == -1)
785+ {
786+ return false;
787+ }
788+ src_offset = header->offset;
789+ } else {
790+ src_offset = header->offset16;
791+ }
792+
793+ p = ShapesFile.GetRWops();
794+ ShapesFile.SetPosition(0);
795+ src_offset += SDL_RWtell(p);
796+ }
797+
798+ // Read collection definition
799+ std::auto_ptr<collection_definition> cd(new collection_definition);
800+ SDL_RWseek(p, src_offset, RW_SEEK_SET);
801+ load_collection_definition(cd.get(), p);
802+ if (m1_shapes && cd->type == _interface_collection)
803+ {
804+ // don't know how to read M1 RLE shapes yet, so clear
805+ // out and return true
806+ cd->high_level_shapes.clear();
807+ cd->low_level_shapes.clear();
808+ cd->bitmaps.clear();
809+ return true;
810+ }
811+ header->status &= ~markPATCHED;
812+
813+ // Convert CLUTS
814+ SDL_RWseek(p, src_offset + cd->color_table_offset, RW_SEEK_SET);
815+ load_clut(&cd->color_tables[0], cd->clut_count * cd->color_count, p);
816+
817+ // Convert high-level shape definitions
818+ SDL_RWseek(p, src_offset + cd->high_level_shape_offset_table_offset, RW_SEEK_SET);
819+
820+ std::vector<uint32> t(cd->high_level_shape_count);
821+ SDL_RWread(p, &t[0], sizeof(uint32), cd->high_level_shape_count);
822+ byte_swap_memory(&t[0], _4byte, cd->high_level_shape_count);
823+ for (int i = 0; i < cd->high_level_shape_count; i++) {
824+ SDL_RWseek(p, src_offset + t[i], RW_SEEK_SET);
825+ load_high_level_shape(cd->high_level_shapes[i], p);
826+ }
827+
828+ // Convert low-level shape definitions
829+ SDL_RWseek(p, src_offset + cd->low_level_shape_offset_table_offset, RW_SEEK_SET);
830+ t.resize(cd->low_level_shape_count);
831+ SDL_RWread(p, &t[0], sizeof(uint32), cd->low_level_shape_count);
832+ byte_swap_memory(&t[0], _4byte, cd->low_level_shape_count);
833+
834+ for (int i = 0; i < cd->low_level_shape_count; i++) {
835+ SDL_RWseek(p, src_offset + t[i], RW_SEEK_SET);
836+ load_low_level_shape(&cd->low_level_shapes[i], p);
837+ }
838+
839+ // Convert bitmap definitions
840+ SDL_RWseek(p, src_offset + cd->bitmap_offset_table_offset, RW_SEEK_SET);
841+ t.resize(cd->bitmap_count);
842+ SDL_RWread(p, &t[0], sizeof(uint32), cd->bitmap_count);
843+ byte_swap_memory(&t[0], _4byte, cd->bitmap_count);
844+
845+ for (int i = 0; i < cd->bitmap_count; i++) {
846+ SDL_RWseek(p, src_offset + t[i], RW_SEEK_SET);
847+ load_bitmap(cd->bitmaps[i], p);
848+ }
849+
850+ header->collection = cd.release();
851+
852+ if (strip) {
853+ //!! don't know what to do
854+ fprintf(stderr, "Stripped shapes not implemented\n");
855+ abort();
856+ }
857+
858+ allocate_shading_tables(collection_index, strip);
859+
860+ if (header->shading_tables == NULL) {
861+ delete header->collection;
862+ header->collection = NULL;
863+ return false;
864+ }
865+
866+ // Everything OK
867+ return true;
868+}
869+
870+
871+/*
872+ * Unload collection
873+ */
874+
875+static void unload_collection(struct collection_header *header)
876+{
877+ assert(header->collection);
878+ delete header->collection;
879+ free(header->shading_tables);
880+ header->collection = NULL;
881+ header->shading_tables = NULL;
882+}
883+
884+#define ENDC_TAG FOUR_CHARS_TO_INT('e', 'n', 'd', 'c')
885+#define CLDF_TAG FOUR_CHARS_TO_INT('c', 'l', 'd', 'f')
886+#define HLSH_TAG FOUR_CHARS_TO_INT('h', 'l', 's', 'h')
887+#define LLSH_TAG FOUR_CHARS_TO_INT('l', 'l', 's', 'h')
888+#define BMAP_TAG FOUR_CHARS_TO_INT('b', 'm', 'a', 'p')
889+#define CTAB_TAG FOUR_CHARS_TO_INT('c', 't', 'a', 'b')
890+
891+std::vector<uint8> shapes_patch;
892+void set_shapes_patch_data(uint8 *data, size_t length)
893+{
894+ if (!length)
895+ {
896+ shapes_patch.clear();
897+ }
898+ else
899+ {
900+ shapes_patch.resize(length);
901+ memcpy(&shapes_patch[0], data, length);
902+ }
903+}
904+
905+uint8* get_shapes_patch_data(size_t &length)
906+{
907+ length = shapes_patch.size();
908+ return length ? &shapes_patch[0] : 0;
909+}
910+
911+void load_shapes_patch(SDL_RWops *p, bool override_replacements)
912+{
913+ std::vector<int16> color_counts(MAXIMUM_COLLECTIONS);
914+ int32 start = SDL_RWtell(p);
915+ SDL_RWseek(p, 0, SEEK_END);
916+ int32 end = SDL_RWtell(p);
917+
918+ SDL_RWseek(p, start, SEEK_SET);
919+
920+ bool done = false;
921+ while (!done)
922+ {
923+ // is there more data to read?
924+ if (SDL_RWtell(p) < end)
925+ {
926+ int32 collection_index = SDL_ReadBE32(p);
927+ int32 patch_bit_depth = SDL_ReadBE32(p);
928+
929+ bool collection_end = false;
930+ while (!collection_end)
931+ {
932+ // read a tag
933+ int32 tag = SDL_ReadBE32(p);
934+ if (tag == ENDC_TAG)
935+ {
936+ collection_end = true;
937+ }
938+ else if (tag == CLDF_TAG)
939+ {
940+ // a collection follows directly
941+ collection_header *header = get_collection_header(collection_index);
942+ if (collection_loaded(header) && patch_bit_depth == 8)
943+ {
944+ load_collection_definition(header->collection, p);
945+ color_counts[collection_index] = header->collection->color_count;
946+ allocate_shading_tables(collection_index, false);
947+ header->status|=markPATCHED;
948+
949+ } else {
950+ // get the color count (it's the only way to skip the CTAB_TAG
951+ SDL_RWseek(p, 6, SEEK_CUR);
952+ color_counts[collection_index] = SDL_ReadBE16(p);
953+ SDL_RWseek(p, 544 - 8, SEEK_CUR);
954+ }
955+ }
956+ else if (tag == HLSH_TAG)
957+ {
958+ collection_definition *cd = get_collection_definition(collection_index);
959+ int32 high_level_shape_index = SDL_ReadBE32(p);
960+ int32 size = SDL_ReadBE32(p);
961+ int32 pos = SDL_RWtell(p);
962+ if (cd && patch_bit_depth == 8 && high_level_shape_index < cd->high_level_shapes.size())
963+ {
964+ load_high_level_shape(cd->high_level_shapes[high_level_shape_index], p);
965+ SDL_RWseek(p, pos + size, SEEK_SET);
966+
967+ }
968+ else
969+ {
970+ SDL_RWseek(p, size, SEEK_CUR);
971+ }
972+ }
973+ else if (tag == LLSH_TAG)
974+ {
975+ collection_definition *cd = get_collection_definition(collection_index);
976+ int32 low_level_shape_index = SDL_ReadBE32(p);
977+ if (cd && patch_bit_depth == 8 && low_level_shape_index < cd->low_level_shapes.size())
978+ {
979+ load_low_level_shape(&cd->low_level_shapes[low_level_shape_index], p);
980+ }
981+ else
982+ {
983+ SDL_RWseek(p, 36, SEEK_CUR);
984+ }
985+ }
986+ else if (tag == BMAP_TAG)
987+ {
988+ collection_definition *cd = get_collection_definition(collection_index);
989+ int32 bitmap_index = SDL_ReadBE32(p);
990+ int32 size = SDL_ReadBE32(p);
991+ if (cd && patch_bit_depth == 8 && bitmap_index < cd->bitmaps.size())
992+ {
993+ load_bitmap(cd->bitmaps[bitmap_index], p);
994+ if (override_replacements)
995+ {
996+ get_bitmap_definition(collection_index, bitmap_index)->flags |= _PATCHED_BIT;
997+ }
998+ }
999+ else
1000+ {
1001+ SDL_RWseek(p, size, SEEK_CUR);
1002+ }
1003+ }
1004+ else if (tag == CTAB_TAG)
1005+ {
1006+ collection_definition *cd = get_collection_definition(collection_index);
1007+ int32 color_table_index = SDL_ReadBE32(p);
1008+ if (cd && patch_bit_depth == 8 && (color_table_index * cd->color_count < cd->color_tables.size()))
1009+ {
1010+ load_clut(&cd->color_tables[color_table_index], cd->color_count, p);
1011+ }
1012+ else
1013+ {
1014+ SDL_RWseek(p, color_counts[collection_index] * sizeof(rgb_color_value), SEEK_CUR);
1015+ }
1016+ }
1017+ else
1018+ {
1019+ fprintf(stderr, "Unrecognized tag in patch file '%c%c%c%c'\n %x", tag >> 24, tag >> 16, tag >> 8, tag, tag);
1020+ }
1021+ }
1022+
1023+
1024+ } else {
1025+ done = true;
1026+ }
1027+ }
1028+
1029+
1030+}
1031+
1032+/* ---------- code */
1033+
1034+/* --------- private code */
1035+
1036+void initialize_shape_handler()
1037+{
1038+ // M1 uses the resource fork, but M2 and Moo use the data fork
1039+
1040+ FileSpecifier File;
1041+ get_default_shapes_spec(File);
1042+ open_shapes_file(File);
1043+ if (!ShapesFile.IsOpen())
1044+ alert_user(fatalError, strERRORS, badExtraFileLocations, ShapesFile.GetError());
1045+ else
1046+ atexit(shutdown_shape_handler);
1047+
1048+ initialize_pixmap_handler();
1049+}
1050+
1051+void open_shapes_file(FileSpecifier& File)
1052+{
1053+ if (File.Open(M1ShapesFile) && M1ShapesFile.Check('.','2','5','6',128))
1054+ {
1055+ m1_shapes = true;
1056+ }
1057+ else if (File.Open(ShapesFile))
1058+ {
1059+ m1_shapes = false;
1060+ // Load the collection headers;
1061+ // need a buffer for the packed data
1062+ int Size = MAXIMUM_COLLECTIONS*SIZEOF_collection_header;
1063+ byte *CollHdrStream = new byte[Size];
1064+ if (!ShapesFile.Read(Size,CollHdrStream))
1065+ {
1066+ ShapesFile.Close();
1067+ delete []CollHdrStream;
1068+ return;
1069+ }
1070+
1071+ // Unpack them
1072+ uint8 *S = CollHdrStream;
1073+ int Count = MAXIMUM_COLLECTIONS;
1074+ collection_header* ObjPtr = collection_headers;
1075+
1076+ for (int k = 0; k < Count; k++, ObjPtr++)
1077+ {
1078+ StreamToValue(S,ObjPtr->status);
1079+ StreamToValue(S,ObjPtr->flags);
1080+
1081+ StreamToValue(S,ObjPtr->offset);
1082+ StreamToValue(S,ObjPtr->length);
1083+ StreamToValue(S,ObjPtr->offset16);
1084+ StreamToValue(S,ObjPtr->length16);
1085+
1086+ S += 6*2;
1087+
1088+ ObjPtr->collection = NULL; // so unloading can work properly
1089+ ObjPtr->shading_tables = NULL; // so unloading can work properly
1090+ }
1091+
1092+ assert((S - CollHdrStream) == Count*SIZEOF_collection_header);
1093+
1094+ delete []CollHdrStream;
1095+
1096+ // Load MML resources in file
1097+ // Be sure to ignore not-found errors
1098+#if defined(mac)
1099+ short SavedType, SavedError = get_game_error(&SavedType);
1100+ XML_LoadFromResourceFork(File);
1101+ set_game_error(SavedType,SavedError);
1102+#endif
1103+ }
1104+}
1105+
1106+static void close_shapes_file(void)
1107+{
1108+ if (m1_shapes)
1109+ {
1110+ M1ShapesFile.Close();
1111+ }
1112+ else
1113+ {
1114+ ShapesFile.Close();
1115+ }
1116+}
1117+
1118+static void shutdown_shape_handler(void)
1119+{
1120+ close_shapes_file();
1121+}
1122+
1123+#ifdef mac
1124+const int POINTER_SIZE = sizeof(void *);
1125+
1126+static int AdjustToPointerBoundary(int x)
1127+{
1128+ return ((((x-1) / POINTER_SIZE) + 1) * POINTER_SIZE);
1129+}
1130+
1131+// Creates an unpacked collection and puts it into a long, flat stream like the original.
1132+byte *unpack_collection(byte *collection, int32 length, bool strip)
1133+{
1134+
1135+ // Set up blank values of these quantities
1136+ byte *NewCollection = NULL;
1137+ int32 *OffsetTable = NULL;
1138+
1139+ try
1140+ {
1141+ // First, unpack the header into a temporary area
1142+ if (length < SIZEOF_collection_definition) throw 13666;
1143+
1144+ collection_definition Definition;
1145+ uint8 *SBase = collection;
1146+ uint8 *S = collection;
1147+
1148+ StreamToValue(S,Definition.version);
1149+
1150+ StreamToValue(S,Definition.type);
1151+ StreamToValue(S,Definition.flags);
1152+
1153+ StreamToValue(S,Definition.color_count);
1154+ StreamToValue(S,Definition.clut_count);
1155+ StreamToValue(S,Definition.color_table_offset);
1156+
1157+ StreamToValue(S,Definition.high_level_shape_count);
1158+ StreamToValue(S,Definition.high_level_shape_offset_table_offset);
1159+
1160+ StreamToValue(S,Definition.low_level_shape_count);
1161+ StreamToValue(S,Definition.low_level_shape_offset_table_offset);
1162+
1163+ StreamToValue(S,Definition.bitmap_count);
1164+ StreamToValue(S,Definition.bitmap_offset_table_offset);
1165+
1166+ StreamToValue(S,Definition.pixels_to_world);
1167+
1168+ StreamToValue(S,Definition.size);
1169+
1170+ S += 253*2;
1171+ assert((S - SBase) == SIZEOF_collection_definition);
1172+
1173+ // We have enough information to estimate the size of the unpack collection chunk!
1174+ int32 NewSize = length;
1175+
1176+ // The header:
1177+ NewSize += (sizeof(collection_definition) - SIZEOF_collection_definition) + POINTER_SIZE;
1178+
1179+ // The colors:
1180+ if (!(Definition.color_count >= 0)) throw 13666;
1181+ if (!(Definition.clut_count >= 0)) throw 13666;
1182+ int TotalColors = Definition.color_count * Definition.clut_count;
1183+ NewSize += TotalColors*(sizeof(rgb_color_value) - SIZEOF_rgb_color_value) + POINTER_SIZE;
1184+
1185+ // The sequence-offset table:
1186+ NewSize += POINTER_SIZE;
1187+
1188+ // The sequence data:
1189+ if (!(Definition.high_level_shape_count >= 0)) throw 13666;
1190+ NewSize += Definition.high_level_shape_count*
1191+ ((sizeof(high_level_shape_definition) - SIZEOF_high_level_shape_definition) + POINTER_SIZE);
1192+
1193+ if (!strip)
1194+ {
1195+ // The frame-offset table:
1196+ NewSize += POINTER_SIZE;
1197+
1198+ // The frame data:
1199+ if (!(Definition.low_level_shape_count >= 0)) throw 13666;
1200+ NewSize += Definition.low_level_shape_count*
1201+ ((sizeof(low_level_shape_definition) - SIZEOF_low_level_shape_definition) + POINTER_SIZE);
1202+
1203+ // The bitmap-offset table:
1204+ NewSize += POINTER_SIZE;
1205+
1206+ // The bitmap data:
1207+ if (!(Definition.bitmap_count >= 0)) throw 13666;
1208+ NewSize += Definition.bitmap_count*
1209+ ((sizeof(bitmap_definition) - SIZEOF_bitmap_definition) + POINTER_SIZE);
1210+
1211+ // The bitmap pointers:
1212+ if (!(Definition.bitmap_offset_table_offset >= 0)) throw 13666;
1213+ if (!(Definition.bitmap_offset_table_offset +
1214+ Definition.bitmap_count*sizeof(int32) <= uint32(length))) throw 13666;
1215+ uint8 *OffsetStream = collection + Definition.bitmap_offset_table_offset;
1216+ for (int k=0; k<Definition.bitmap_count; k++)
1217+ {
1218+ int32 Offset;
1219+ StreamToValue(OffsetStream,Offset);
1220+ if (!(Offset >= 0 && Offset < (length - SIZEOF_bitmap_definition))) throw 13666;
1221+ uint8 *S = collection + Offset;
1222+
1223+ bitmap_definition Bitmap;
1224+
1225+ StreamToValue(S,Bitmap.width);
1226+ StreamToValue(S,Bitmap.height);
1227+ StreamToValue(S,Bitmap.bytes_per_row);
1228+
1229+ StreamToValue(S,Bitmap.flags);
1230+
1231+ short NumScanlines = (Bitmap.flags&_COLUMN_ORDER_BIT) ?
1232+ Bitmap.width : Bitmap.height;
1233+
1234+ NewSize += NumScanlines*(sizeof(pixel8 *) - sizeof(int32));
1235+ }
1236+ }
1237+
1238+ // Blank out the new chunk and copy in the new header
1239+ NewCollection = new byte[NewSize];
1240+ memset(NewCollection,0,NewSize);
1241+ int32 NewCollLocation = 0;
1242+ memcpy(NewCollection, &Definition, sizeof(collection_definition));
1243+ collection_definition& NewDefinition = *((collection_definition *)NewCollection);
1244+ NewDefinition.size = NewSize;
1245+ NewCollLocation += AdjustToPointerBoundary(sizeof(collection_definition));
1246+
1247+ // Copy in the colors
1248+ if (!(Definition.color_table_offset >= 0)) throw 13666;
1249+ if (!(Definition.color_table_offset + TotalColors*SIZEOF_rgb_color_value <= length)) throw 13666;
1250+ rgb_color_value *Colors = (rgb_color_value *)(NewCollection + NewCollLocation);
1251+ SBase = S = collection + Definition.color_table_offset;
1252+ for (int k = 0; k < TotalColors; k++, Colors++)
1253+ {
1254+ Colors->flags = *(S++);
1255+ Colors->value = *(S++);
1256+ StreamToValue(S,Colors->red);
1257+ StreamToValue(S,Colors->green);
1258+ StreamToValue(S,Colors->blue);
1259+ }
1260+ assert((S - SBase) == TotalColors*SIZEOF_rgb_color_value);
1261+ NewDefinition.color_table_offset = NewCollLocation;
1262+ NewCollLocation += AdjustToPointerBoundary(TotalColors*sizeof(rgb_color_value));
1263+
1264+ // Copy in the sequence offsets
1265+ if (!(Definition.high_level_shape_offset_table_offset >= 0)) throw 13666;
1266+ if (!(Definition.high_level_shape_offset_table_offset +
1267+ Definition.high_level_shape_count*sizeof(int32) <= uint32(length))) throw 13666;
1268+ OffsetTable = new int32[Definition.high_level_shape_count + 1];
1269+
1270+ S = collection + Definition.high_level_shape_offset_table_offset;
1271+ StreamToList(S,OffsetTable,Definition.high_level_shape_count);
1272+ OffsetTable[Definition.high_level_shape_count] =
1273+ Definition.low_level_shape_offset_table_offset;
1274+
1275+ if (!(OffsetTable[0] >= 0)) throw 13666;
1276+ for (int k=0; k<Definition.high_level_shape_count; k++)
1277+ if (!(OffsetTable[k+1] - OffsetTable[k] >= SIZEOF_high_level_shape_definition)) throw 13666;
1278+ if (!(OffsetTable[Definition.high_level_shape_count] <= length)) throw 13666;
1279+
1280+ NewDefinition.high_level_shape_offset_table_offset = NewCollLocation;
1281+ int32 *NewOffsetPtr = (int32 *)(NewCollection + NewCollLocation);
1282+ NewCollLocation += AdjustToPointerBoundary(sizeof(int32)*Definition.high_level_shape_count);
1283+
1284+ // Copy in the sequences
1285+ for (int k=0; k<Definition.high_level_shape_count; k++)
1286+ {
1287+ SBase = S = collection + OffsetTable[k];
1288+ uint8 *SNext = collection + OffsetTable[k+1];
1289+
1290+ high_level_shape_definition& Sequence =
1291+ *((high_level_shape_definition *)(NewCollection + NewCollLocation));
1292+
1293+ StreamToValue(S,Sequence.type);
1294+ StreamToValue(S,Sequence.flags);
1295+
1296+ StreamToBytes(S,Sequence.name,HIGH_LEVEL_SHAPE_NAME_LENGTH+2);
1297+
1298+ StreamToValue(S,Sequence.number_of_views);
1299+
1300+ StreamToValue(S,Sequence.frames_per_view);
1301+ StreamToValue(S,Sequence.ticks_per_frame);
1302+ StreamToValue(S,Sequence.key_frame);
1303+
1304+ StreamToValue(S,Sequence.transfer_mode);
1305+ StreamToValue(S,Sequence.transfer_mode_period);
1306+
1307+ StreamToValue(S,Sequence.first_frame_sound);
1308+ StreamToValue(S,Sequence.key_frame_sound);
1309+ StreamToValue(S,Sequence.last_frame_sound);
1310+
1311+ StreamToValue(S,Sequence.pixels_to_world);
1312+
1313+ StreamToValue(S,Sequence.loop_frame);
1314+
1315+ S += 14*2;
1316+
1317+ StreamToValue(S,Sequence.low_level_shape_indexes[0]);
1318+ assert((S - SBase) == SIZEOF_high_level_shape_definition);
1319+
1320+ // Do the remaining frame indices
1321+ size_t NumFrameIndxs = (SNext - S)/sizeof(int16);
1322+ StreamToList(S,Sequence.low_level_shape_indexes+1,NumFrameIndxs);
1323+
1324+ // Set the offset pointer appropriately:
1325+ *(NewOffsetPtr++) = NewCollLocation;
1326+ NewCollLocation +=
1327+ AdjustToPointerBoundary(sizeof(high_level_shape_definition) + NumFrameIndxs*sizeof(int16));
1328+ }
1329+
1330+ delete []OffsetTable;
1331+ OffsetTable = NULL;
1332+
1333+ if (strip)
1334+ {
1335+ NewDefinition.low_level_shape_count = 0;
1336+ NewDefinition.bitmap_count = 0;
1337+ }
1338+ else
1339+ {
1340+ // Copy in the frame offsets
1341+ if (!(Definition.low_level_shape_count >= 0)) throw 13666;
1342+ if (!(Definition.low_level_shape_offset_table_offset >= 0)) throw 13666;
1343+ if (!(Definition.low_level_shape_offset_table_offset +
1344+ Definition.low_level_shape_count*sizeof(int32) <= uint32(length))) throw 13666;
1345+ int32 *OffsetTable = new int32[Definition.low_level_shape_count + 1];
1346+
1347+ S = collection + Definition.low_level_shape_offset_table_offset;
1348+ StreamToList(S,OffsetTable,Definition.low_level_shape_count);
1349+ OffsetTable[Definition.low_level_shape_count] = Definition.bitmap_offset_table_offset;
1350+
1351+ if (!(OffsetTable[0] >= 0)) throw 13666;
1352+ for (int k=0; k<Definition.low_level_shape_count; k++)
1353+ if (!(OffsetTable[k+1] - OffsetTable[k] >= SIZEOF_low_level_shape_definition)) throw 13666;
1354+ if (!(OffsetTable[Definition.low_level_shape_count] <= length)) throw 13666;
1355+
1356+ NewDefinition.low_level_shape_offset_table_offset = NewCollLocation;
1357+ NewOffsetPtr = (int32 *)(NewCollection + NewCollLocation);
1358+ NewCollLocation += AdjustToPointerBoundary(sizeof(int32)*Definition.low_level_shape_count);
1359+
1360+ // Copy in the frames
1361+ for (int k=0; k<Definition.low_level_shape_count; k++)
1362+ {
1363+ SBase = S = collection + OffsetTable[k];
1364+
1365+ low_level_shape_definition& Frame =
1366+ *((low_level_shape_definition *)(NewCollection + NewCollLocation));
1367+
1368+ StreamToValue(S,Frame.flags);
1369+
1370+ StreamToValue(S,Frame.minimum_light_intensity);
1371+
1372+ StreamToValue(S,Frame.bitmap_index);
1373+
1374+ StreamToValue(S,Frame.origin_x);
1375+ StreamToValue(S,Frame.origin_y);
1376+
1377+ StreamToValue(S,Frame.key_x);
1378+ StreamToValue(S,Frame.key_y);
1379+
1380+ StreamToValue(S,Frame.world_left);
1381+ StreamToValue(S,Frame.world_right);
1382+ StreamToValue(S,Frame.world_top);
1383+ StreamToValue(S,Frame.world_bottom);
1384+ StreamToValue(S,Frame.world_x0);
1385+ StreamToValue(S,Frame.world_y0);
1386+
1387+ S += 4*2;
1388+
1389+ assert((S - SBase) == SIZEOF_low_level_shape_definition);
1390+
1391+ // Set the offset pointer appropriately:
1392+ *(NewOffsetPtr++) = NewCollLocation;
1393+ NewCollLocation += AdjustToPointerBoundary(sizeof(low_level_shape_definition));
1394+ }
1395+
1396+ delete []OffsetTable;
1397+ OffsetTable = NULL;
1398+
1399+ // Copy in the the bitmap offsets
1400+ if (!(Definition.bitmap_count >= 0)) throw 13666;
1401+ if (!(Definition.bitmap_offset_table_offset >= 0)) throw 13666;
1402+ if (!(Definition.bitmap_offset_table_offset +
1403+ Definition.bitmap_count*sizeof(int32) <= uint32(length))) throw 13666;
1404+ OffsetTable = new int32[Definition.bitmap_count + 1];
1405+
1406+ S = collection + Definition.bitmap_offset_table_offset;
1407+ StreamToList(S,OffsetTable,Definition.bitmap_count);
1408+ OffsetTable[Definition.bitmap_count] = length;
1409+
1410+ if (!(OffsetTable[0] >= 0)) throw 13666;
1411+ for (int k=0; k<Definition.bitmap_count; k++)
1412+ if (!(OffsetTable[k+1] - OffsetTable[k] >= SIZEOF_bitmap_definition)) throw 13666;
1413+ if (!(OffsetTable[Definition.bitmap_count] <= length)) throw 13666;
1414+
1415+ NewDefinition.bitmap_offset_table_offset = NewCollLocation;
1416+ NewOffsetPtr = (int32 *)(NewCollection + NewCollLocation);
1417+ NewCollLocation += AdjustToPointerBoundary(sizeof(int32)*Definition.bitmap_count);
1418+
1419+ // Get the bitmaps
1420+ for (int k=0; k<Definition.bitmap_count; k++)
1421+ {
1422+ SBase = S = collection + OffsetTable[k];
1423+ uint8 *SNext = collection + OffsetTable[k+1];
1424+
1425+ bitmap_definition& Bitmap =
1426+ *((bitmap_definition *)(NewCollection + NewCollLocation));
1427+
1428+ StreamToValue(S,Bitmap.width);
1429+ StreamToValue(S,Bitmap.height);
1430+ StreamToValue(S,Bitmap.bytes_per_row);
1431+
1432+ StreamToValue(S,Bitmap.flags);
1433+ StreamToValue(S,Bitmap.bit_depth);
1434+
1435+ S += 8*2;
1436+
1437+ // Code was originally designed for 32-bit pointers!
1438+ S += sizeof(int32);
1439+
1440+ assert((S - SBase) == SIZEOF_bitmap_definition);
1441+
1442+ // Add in extra space for long pointers; offset the reading of the remaining stuff
1443+ // by that quantity.
1444+
1445+ short NumScanlines = (Bitmap.flags&_COLUMN_ORDER_BIT) ?
1446+ Bitmap.width : Bitmap.height;
1447+
1448+ int NumExtraPointerBytes = NumScanlines*(sizeof(pixel8 *) - sizeof(int32));
1449+
1450+ // Do all the other stuff; don't bother to try to process it
1451+ int32 RemainingBytes = (SNext - S);
1452+ byte *RemainingDataPlacement = (byte *)(Bitmap.row_addresses+1) + NumExtraPointerBytes;
1453+ StreamToBytes(S,RemainingDataPlacement,RemainingBytes);
1454+
1455+ // Set the offset pointer appropriately:
1456+ *(NewOffsetPtr++) = NewCollLocation;
1457+ NewCollLocation +=
1458+ AdjustToPointerBoundary(sizeof(bitmap_definition) + RemainingBytes);
1459+ }
1460+
1461+ delete []OffsetTable;
1462+ OffsetTable = NULL;
1463+
1464+ // Just in case I miscalculated...
1465+ assert(NewCollLocation <= NewSize);
1466+ }
1467+ }
1468+ catch(int n)
1469+ {
1470+ if (NewCollection) delete []NewCollection;
1471+ }
1472+ if (OffsetTable) delete []OffsetTable;
1473+
1474+ return NewCollection;
1475+}
1476+#endif
1477+
1478+
1479+static bool collection_loaded(
1480+ struct collection_header *header)
1481+{
1482+ return header->collection ? true : false;
1483+}
1484+
1485+bool collection_loaded(short collection_index)
1486+{
1487+ collection_header *header = get_collection_header(collection_index);
1488+ return collection_loaded(header);
1489+}
1490+
1491+static void lock_collection(
1492+ struct collection_header *header)
1493+{
1494+ // nothing to do
1495+}
1496+
1497+static void unlock_collection(
1498+ struct collection_header *header)
1499+{
1500+ // nothing to do
1501+}
1502+
1503+#ifdef mac
1504+static byte *read_object_from_file(
1505+ OpenedFile& OFile,
1506+ int32 offset,
1507+ int32 length)
1508+{
1509+ if (!OFile.IsOpen()) return NULL;
1510+
1511+ byte *data = NULL;
1512+
1513+ if (length <= 0) return NULL;
1514+ if (!(data = new byte[length])) return NULL;
1515+
1516+ if (!OFile.SetPosition(offset))
1517+ {
1518+ delete []data;
1519+ return NULL;
1520+ }
1521+ if (!OFile.Read(length,data))
1522+ {
1523+ delete []data;
1524+ return NULL;
1525+ }
1526+
1527+ return data;
1528+}
1529+#endif
1530+
1531+
1532+void unload_all_collections(
1533+ void)
1534+{
1535+ struct collection_header *header;
1536+ short collection_index;
1537+
1538+ for (collection_index= 0, header= collection_headers; collection_index<MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1539+ {
1540+ if (collection_loaded(header))
1541+ {
1542+ unload_collection(header);
1543+ }
1544+ OGL_UnloadModelsImages(collection_index);
1545+ }
1546+}
1547+
1548+void mark_collection(
1549+ short collection_code,
1550+ bool loading)
1551+{
1552+ if (collection_code!=NONE)
1553+ {
1554+ short collection_index= GET_COLLECTION(collection_code);
1555+
1556+ assert(collection_index>=0&&collection_index<MAXIMUM_COLLECTIONS);
1557+ collection_headers[collection_index].status|= loading ? markLOAD : markUNLOAD;
1558+ }
1559+}
1560+
1561+void strip_collection(
1562+ short collection_code)
1563+{
1564+ if (collection_code!=NONE)
1565+ {
1566+ short collection_index= GET_COLLECTION(collection_code);
1567+
1568+ assert(collection_index>=0&&collection_index<MAXIMUM_COLLECTIONS);
1569+ collection_headers[collection_index].status|= markSTRIP;
1570+ }
1571+}
1572+
1573+/* returns count, doesnユt fill NULL buffer */
1574+short get_shape_descriptors(
1575+ short shape_type,
1576+ shape_descriptor *buffer)
1577+{
1578+ short collection_index, low_level_shape_index;
1579+ short appropriate_type;
1580+ short count;
1581+
1582+ switch (shape_type)
1583+ {
1584+ case _wall_shape: appropriate_type= _wall_collection; break;
1585+ case _floor_or_ceiling_shape: appropriate_type= _wall_collection; break;
1586+ default:
1587+ assert(false);
1588+ break;
1589+ }
1590+
1591+ count= 0;
1592+ for (collection_index=0;collection_index<MAXIMUM_COLLECTIONS;++collection_index)
1593+ {
1594+ struct collection_definition *collection= get_collection_definition(collection_index);
1595+ // Skip over nonexistent collections, frames, and bitmaps.
1596+ if (!collection) continue;
1597+
1598+ if (collection&&collection->type==appropriate_type)
1599+ {
1600+ for (low_level_shape_index=0;low_level_shape_index<collection->low_level_shape_count;++low_level_shape_index)
1601+ {
1602+ struct low_level_shape_definition *low_level_shape= get_low_level_shape_definition(collection_index, low_level_shape_index);
1603+ if (!low_level_shape) continue;
1604+ struct bitmap_definition *bitmap= get_bitmap_definition(collection_index, low_level_shape->bitmap_index);
1605+ if (!bitmap) continue;
1606+
1607+ count+= collection->clut_count;
1608+ if (buffer)
1609+ {
1610+ short clut;
1611+
1612+ for (clut=0;clut<collection->clut_count;++clut)
1613+ {
1614+ *buffer++= BUILD_DESCRIPTOR(BUILD_COLLECTION(collection_index, clut), low_level_shape_index);
1615+ }
1616+ }
1617+ }
1618+ }
1619+ }
1620+
1621+ return count;
1622+}
1623+
1624+void extended_get_shape_bitmap_and_shading_table(
1625+ short collection_code,
1626+ short low_level_shape_index,
1627+ struct bitmap_definition **bitmap,
1628+ void **shading_tables,
1629+ short shading_mode)
1630+{
1631+// if (collection_code==_collection_marathon_control_panels) collection_code= 30, low_level_shape_index= 0;
1632+ short collection_index= GET_COLLECTION(collection_code);
1633+ short clut_index= GET_COLLECTION_CLUT(collection_code);
1634+
1635+ // Forget about it if some one managed to call us with the NONE value
1636+ assert(!(clut_index+1 == MAXIMUM_CLUTS_PER_COLLECTION &&
1637+ collection_index+1 == MAXIMUM_COLLECTIONS &&
1638+ low_level_shape_index+1 == MAXIMUM_SHAPES_PER_COLLECTION));
1639+
1640+ struct low_level_shape_definition *low_level_shape= get_low_level_shape_definition(collection_index, low_level_shape_index);
1641+ // Return NULL pointers for bitmap and shading table if the frame does not exist
1642+ if (!low_level_shape)
1643+ {
1644+ *bitmap = NULL;
1645+ if (shading_tables) *shading_tables = NULL;
1646+ return;
1647+ }
1648+
1649+ if (bitmap) *bitmap= get_bitmap_definition(collection_index, low_level_shape->bitmap_index);
1650+ if (shading_tables)
1651+ {
1652+ switch (shading_mode)
1653+ {
1654+ case _shading_normal:
1655+ *shading_tables= get_collection_shading_tables(collection_index, clut_index);
1656+ break;
1657+ case _shading_infravision:
1658+ *shading_tables= get_collection_tint_tables(collection_index, 0);
1659+ break;
1660+
1661+ default:
1662+ assert(false);
1663+ break;
1664+ }
1665+ }
1666+}
1667+
1668+// Because this object has to continue to exist after exiting the next function
1669+static low_level_shape_definition AdjustedFrame;
1670+
1671+struct shape_information_data *extended_get_shape_information(
1672+ short collection_code,
1673+ short low_level_shape_index)
1674+{
1675+if((GET_COLLECTION(collection_code) < 0) || (GET_COLLECTION(collection_code) >= NUMBER_OF_COLLECTIONS)) return NULL; if(low_level_shape_index < 0) return NULL;
1676+ short collection_index= GET_COLLECTION(collection_code);
1677+ struct low_level_shape_definition *low_level_shape;
1678+
1679+ low_level_shape= get_low_level_shape_definition(collection_index, low_level_shape_index);
1680+ return (struct shape_information_data *) low_level_shape;
1681+}
1682+
1683+void process_collection_sounds(
1684+ short collection_code,
1685+ void (*process_sound)(short sound_index))
1686+{
1687+ short collection_index= GET_COLLECTION(collection_code);
1688+ struct collection_definition *collection= get_collection_definition(collection_index);
1689+ // Skip over processing unloaded collections and sequences
1690+ if (!collection) return;
1691+
1692+ short high_level_shape_index;
1693+
1694+ for (high_level_shape_index= 0; high_level_shape_index<collection->high_level_shape_count; ++high_level_shape_index)
1695+ {
1696+ struct high_level_shape_definition *high_level_shape= get_high_level_shape_definition(collection_index, high_level_shape_index);
1697+ if (!high_level_shape) return;
1698+
1699+ process_sound(high_level_shape->first_frame_sound);
1700+ process_sound(high_level_shape->key_frame_sound);
1701+ process_sound(high_level_shape->last_frame_sound);
1702+ }
1703+}
1704+
1705+struct shape_animation_data *get_shape_animation_data(
1706+ shape_descriptor shape)
1707+{
1708+ short collection_index, high_level_shape_index;
1709+ struct high_level_shape_definition *high_level_shape;
1710+
1711+ collection_index= GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(shape));
1712+ high_level_shape_index= GET_DESCRIPTOR_SHAPE(shape);
1713+ high_level_shape= get_high_level_shape_definition(collection_index, high_level_shape_index);
1714+ if (!high_level_shape) return NULL;
1715+
1716+ return (struct shape_animation_data *) &high_level_shape->number_of_views;
1717+}
1718+
1719+void *get_global_shading_table(
1720+ void)
1721+{
1722+ void *shading_table= (void *) NULL;
1723+
1724+ switch (bit_depth)
1725+ {
1726+ case 8:
1727+ {
1728+ /* return the last shading_table calculated */
1729+ short collection_index;
1730+
1731+ for (collection_index=MAXIMUM_COLLECTIONS-1;collection_index>=0;--collection_index)
1732+ {
1733+ struct collection_definition *collection= get_collection_definition(collection_index);
1734+
1735+ if (collection)
1736+ {
1737+ shading_table= get_collection_shading_tables(collection_index, 0);
1738+ break;
1739+ }
1740+ }
1741+
1742+ break;
1743+ }
1744+
1745+ case 16:
1746+ build_global_shading_table16();
1747+ shading_table= global_shading_table16;
1748+ break;
1749+
1750+ case 32:
1751+ build_global_shading_table32();
1752+ shading_table= global_shading_table32;
1753+ break;
1754+
1755+ default:
1756+ assert(false);
1757+ break;
1758+ }
1759+ assert(shading_table);
1760+
1761+ return shading_table;
1762+}
1763+
1764+void load_collections(
1765+ bool with_progress_bar,
1766+ bool is_opengl)
1767+{
1768+ struct collection_header *header;
1769+ short collection_index;
1770+
1771+ if (with_progress_bar)
1772+ {
1773+// open_progress_dialog(_loading_collections);
1774+// draw_progress_bar(0, 2*MAXIMUM_COLLECTIONS);
1775+ }
1776+ precalculate_bit_depth_constants();
1777+
1778+ free_and_unlock_memory(); /* do our best to get a big, unfragmented heap */
1779+
1780+ /* first go through our list of shape collections and dispose of any collections which
1781+ were marked for unloading. at the same time, unlock all those collections which
1782+ will be staying (so the heap can move around) */
1783+ for (collection_index= 0, header= collection_headers; collection_index<MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1784+ {
1785+// if (with_progress_bar)
1786+// draw_progress_bar(collection_index, 2*MAXIMUM_COLLECTIONS);
1787+ if (((header->status&markUNLOAD) && !(header->status&markLOAD)) || header->status&markPATCHED)
1788+ {
1789+ if (collection_loaded(header))
1790+ {
1791+ unload_collection(header);
1792+ }
1793+ OGL_UnloadModelsImages(collection_index);
1794+ SW_Texture_Extras::instance()->Unload(collection_index);
1795+ }
1796+ else
1797+ {
1798+ /* if this collection is already loaded, unlock it to tenderize the heap */
1799+ if (collection_loaded(header))
1800+ {
1801+ unlock_collection(header);
1802+ }
1803+ }
1804+ }
1805+
1806+ /* ... then go back through the list of collections and load any that we were asked to */
1807+ for (collection_index= 0, header= collection_headers; collection_index<MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1808+ {
1809+// if (with_progress_bar)
1810+// draw_progress_bar(MAXIMUM_COLLECTIONS+collection_index, 2*MAXIMUM_COLLECTIONS);
1811+ /* donユt reload collections which are already in memory, but do lock them */
1812+ if (collection_loaded(header))
1813+ {
1814+ // In case the substitute images had been changed by some level-specific MML...
1815+// OGL_LoadModelsImages(collection_index);
1816+ lock_collection(header);
1817+ }
1818+ else
1819+ {
1820+ if (header->status&markLOAD)
1821+ {
1822+ /* load and decompress collection */
1823+ if (!load_collection(collection_index, (header->status&markSTRIP) ? true : false))
1824+ {
1825+ if (!m1_shapes)
1826+ {
1827+ alert_user(fatalError, strERRORS, outOfMemory, -1);
1828+ }
1829+ }
1830+// OGL_LoadModelsImages(collection_index);
1831+ }
1832+ }
1833+
1834+ /* clear action flags */
1835+ header->status= markNONE;
1836+ header->flags= 0;
1837+ }
1838+
1839+ Plugins::instance()->load_shapes_patches(is_opengl);
1840+
1841+ if (shapes_patch.size())
1842+ {
1843+ SDL_RWops *f = SDL_RWFromMem(&shapes_patch[0], shapes_patch.size());
1844+ load_shapes_patch(f, true);
1845+ SDL_RWclose(f);
1846+ }
1847+
1848+ /* remap the shapes, recalculate row base addresses, build our new world color table and
1849+ (finally) update the screen to reflect our changes */
1850+ update_color_environment(is_opengl);
1851+
1852+ // load software enhancements
1853+ if (!is_opengl) {
1854+ for (collection_index= 0, header= collection_headers; collection_index < MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1855+ {
1856+ if (collection_loaded(header))
1857+ {
1858+ SW_Texture_Extras::instance()->Load(collection_index);
1859+ }
1860+ }
1861+ }
1862+// if (with_progress_bar)
1863+// close_progress_dialog();
1864+}
1865+
1866+#ifdef HAVE_OPENGL
1867+
1868+int count_replacement_collections()
1869+{
1870+ int total_replacements = 0;
1871+ short collection_index;
1872+ struct collection_header *header;
1873+ for (collection_index = 0, header = collection_headers; collection_index < MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1874+ {
1875+ if (collection_loaded(header))
1876+ {
1877+ total_replacements += OGL_CountModelsImages(collection_index);
1878+ }
1879+ }
1880+
1881+ return total_replacements;
1882+}
1883+
1884+void load_replacement_collections()
1885+{
1886+ struct collection_header *header;
1887+ short collection_index;
1888+
1889+ for (collection_index= 0, header= collection_headers; collection_index < MAXIMUM_COLLECTIONS; ++collection_index, ++header)
1890+ {
1891+ if (collection_loaded(header))
1892+ {
1893+ OGL_LoadModelsImages(collection_index);
1894+ }
1895+ }
1896+}
1897+
1898+#endif
1899+
1900+/* ---------- private code */
1901+
1902+static void precalculate_bit_depth_constants(
1903+ void)
1904+{
1905+ switch (bit_depth)
1906+ {
1907+ case 8:
1908+ number_of_shading_tables= 32;
1909+ shading_table_fractional_bits= 5;
1910+// next_shading_table_shift= 8;
1911+ shading_table_size= PIXEL8_MAXIMUM_COLORS*sizeof(pixel8);
1912+ break;
1913+ case 16:
1914+ number_of_shading_tables= 64;
1915+ shading_table_fractional_bits= 6;
1916+// next_shading_table_shift= 9;
1917+ shading_table_size= PIXEL8_MAXIMUM_COLORS*sizeof(pixel16);
1918+ break;
1919+ case 32:
1920+ number_of_shading_tables= 256;
1921+ shading_table_fractional_bits= 8;
1922+// next_shading_table_shift= 10;
1923+ shading_table_size= PIXEL8_MAXIMUM_COLORS*sizeof(pixel32);
1924+ break;
1925+ }
1926+}
1927+
1928+/* given a list of RGBColors, find out which one, if any, match the given color. if there
1929+ arenユt any matches, add a new entry and return that index. */
1930+static short find_or_add_color(
1931+ struct rgb_color_value *color,
1932+ register struct rgb_color_value *colors,
1933+ short *color_count,
1934+ bool update_flags = true)
1935+{
1936+ short i;
1937+
1938+ // LP addition: save initial color-table pointer, just in case we overflow
1939+ register struct rgb_color_value *colors_saved = colors;
1940+
1941+ // = 1 to skip the transparent color
1942+ for (i= 1, colors+= 1; i<*color_count; ++i, ++colors)
1943+ {
1944+ if (colors->red==color->red && colors->green==color->green && colors->blue==color->blue)
1945+ {
1946+ if (update_flags) colors->flags= color->flags;
1947+ return i;
1948+ }
1949+ }
1950+
1951+ // LP change: added a fallback strategy; if there were too many colors,
1952+ // then find the closest one
1953+ if (*color_count >= PIXEL8_MAXIMUM_COLORS)
1954+ {
1955+ // Set up minimum distance, its index
1956+ // Strictly speaking, the distance squared, since that will be
1957+ // what we will be calculating.
1958+ // The color values are data type "word", which is unsigned short;
1959+ // this explains the initial choice of minimum value --
1960+ // as greater than any possible such value.
1961+ double MinDiffSq = 3*double(65536)*double(65536);
1962+ short MinIndx = 0;
1963+
1964+ // Rescan
1965+ colors = colors_saved;
1966+ for (i= 1, colors+= 1; i<*color_count; ++i, ++colors)
1967+ {
1968+ double RedDiff = double(color->red) - double(colors->red);
1969+ double GreenDiff = double(color->green) - double(colors->green);
1970+ double BlueDiff = double(color->blue) - double(colors->blue);
1971+ double DiffSq = RedDiff*RedDiff + GreenDiff*GreenDiff + BlueDiff*BlueDiff;
1972+ if (DiffSq < MinDiffSq)
1973+ {
1974+ MinIndx = i;
1975+ MinDiffSq = DiffSq;
1976+ }
1977+ }
1978+ return MinIndx;
1979+ }
1980+
1981+ // assert(*color_count<PIXEL8_MAXIMUM_COLORS);
1982+ *colors= *color;
1983+
1984+ return (*color_count)++;
1985+}
1986+
1987+static void update_color_environment(
1988+ bool is_opengl)
1989+{
1990+ short color_count;
1991+ short collection_index;
1992+ short bitmap_index;
1993+
1994+ pixel8 remapping_table[PIXEL8_MAXIMUM_COLORS];
1995+ struct rgb_color_value colors[PIXEL8_MAXIMUM_COLORS];
1996+
1997+ memset(remapping_table, 0, PIXEL8_MAXIMUM_COLORS*sizeof(pixel8));
1998+
1999+ // dummy color to hold the first index (zero) for transparent pixels
2000+ colors[0].red= colors[0].green= colors[0].blue= 65535;
2001+ colors[0].flags= colors[0].value= 0;
2002+ color_count= 1;
2003+
2004+ /* loop through all collections, only paying attention to the loaded ones. weユre
2005+ depending on finding the gray run (white to black) first; so itユs the responsibility
2006+ of the lowest numbered loaded collection to give us this */
2007+ for (collection_index=0;collection_index<MAXIMUM_COLLECTIONS;++collection_index)
2008+ {
2009+ struct collection_definition *collection= get_collection_definition(collection_index);
2010+
2011+// dprintf("collection #%d", collection_index);
2012+
2013+ if (collection && collection->bitmap_count)
2014+ {
2015+ struct rgb_color_value *primary_colors= get_collection_colors(collection_index, 0)+NUMBER_OF_PRIVATE_COLORS;
2016+ assert(primary_colors);
2017+ short color_index, clut_index;
2018+
2019+// if (collection_index==15) dprintf("primary clut %p", primary_colors);
2020+// dprintf("primary clut %d entries;dm #%d #%d", collection->color_count, primary_colors, collection->color_count*sizeof(ColorSpec));
2021+
2022+ /* add the colors from this collectionユs primary color table to the aggregate color
2023+ table and build the remapping table */
2024+ for (color_index=0;color_index<collection->color_count-NUMBER_OF_PRIVATE_COLORS;++color_index)
2025+ {
2026+ primary_colors[color_index].value= remapping_table[primary_colors[color_index].value]=
2027+ find_or_add_color(&primary_colors[color_index], colors, &color_count);
2028+ }
2029+
2030+ /* then remap the collection and recalculate the base addresses of each bitmap */
2031+ for (bitmap_index= 0; bitmap_index<collection->bitmap_count; ++bitmap_index)
2032+ {
2033+ struct bitmap_definition *bitmap= get_bitmap_definition(collection_index, bitmap_index);
2034+ assert(bitmap);
2035+
2036+ /* calculate row base addresses ... */
2037+ bitmap->row_addresses[0]= calculate_bitmap_origin(bitmap);
2038+ precalculate_bitmap_row_addresses(bitmap);
2039+
2040+ /* ... and remap it */
2041+ remap_bitmap(bitmap, remapping_table);
2042+ }
2043+
2044+ /* build a shading table for each clut in this collection */
2045+ for (clut_index= 0; clut_index<collection->clut_count; ++clut_index)
2046+ {
2047+ void *primary_shading_table= get_collection_shading_tables(collection_index, 0);
2048+ short collection_bit_depth= collection->type==_interface_collection ? 8 : bit_depth;
2049+
2050+ if (clut_index)
2051+ {
2052+ struct rgb_color_value *alternate_colors= get_collection_colors(collection_index, clut_index)+NUMBER_OF_PRIVATE_COLORS;
2053+ assert(alternate_colors);
2054+ void *alternate_shading_table= get_collection_shading_tables(collection_index, clut_index);
2055+ pixel8 shading_remapping_table[PIXEL8_MAXIMUM_COLORS];
2056+
2057+ memset(shading_remapping_table, 0, PIXEL8_MAXIMUM_COLORS*sizeof(pixel8));
2058+
2059+// dprintf("alternate clut %d entries;dm #%d #%d", collection->color_count, alternate_colors, collection->color_count*sizeof(ColorSpec));
2060+
2061+ /* build a remapping table for the primary shading table which we can use to
2062+ calculate this alternate shading table */
2063+ for (color_index= 0; color_index<PIXEL8_MAXIMUM_COLORS; ++color_index) shading_remapping_table[color_index]= static_cast<pixel8>(color_index);
2064+ for (color_index= 0; color_index<collection->color_count-NUMBER_OF_PRIVATE_COLORS; ++color_index)
2065+ {
2066+ shading_remapping_table[find_or_add_color(&primary_colors[color_index], colors, &color_count, false)]=
2067+ find_or_add_color(&alternate_colors[color_index], colors, &color_count);
2068+ }
2069+// shading_remapping_table[iBLACK]= iBLACK; /* make iBLACK==>iBLACK remapping explicit */
2070+
2071+ switch (collection_bit_depth)
2072+ {
2073+ case 8:
2074+ /* duplicate the primary shading table and remap it */
2075+ memcpy(alternate_shading_table, primary_shading_table, get_shading_table_size(collection_index));
2076+ map_bytes((unsigned char *)alternate_shading_table, shading_remapping_table, get_shading_table_size(collection_index));
2077+ break;
2078+
2079+ case 16:
2080+ build_shading_tables16(colors, color_count, (pixel16 *)alternate_shading_table, shading_remapping_table, is_opengl); break;
2081+ break;
2082+
2083+ case 32:
2084+ build_shading_tables32(colors, color_count, (pixel32 *)alternate_shading_table, shading_remapping_table, is_opengl); break;
2085+ break;
2086+
2087+ default:
2088+ assert(false);
2089+ break;
2090+ }
2091+ }
2092+ else
2093+ {
2094+ /* build the primary shading table */
2095+ switch (collection_bit_depth)
2096+ {
2097+ case 8: build_shading_tables8(colors, color_count, (unsigned char *)primary_shading_table); break;
2098+ case 16: build_shading_tables16(colors, color_count, (pixel16 *)primary_shading_table, (byte *) NULL, is_opengl); break;
2099+ case 32: build_shading_tables32(colors, color_count, (pixel32 *)primary_shading_table, (byte *) NULL, is_opengl); break;
2100+ default:
2101+ assert(false);
2102+ break;
2103+ }
2104+ }
2105+ }
2106+
2107+ build_collection_tinting_table(colors, color_count, collection_index, is_opengl);
2108+
2109+ /* 8-bit interface, non-8-bit main window; remember interface CLUT separately */
2110+ if (collection_index==_collection_interface && interface_bit_depth==8 && bit_depth!=interface_bit_depth) _change_clut(change_interface_clut, colors, color_count);
2111+
2112+ /* if weユre not in 8-bit, we donユt have to carry our colors over into the next collection */
2113+ if (bit_depth!=8) color_count= 1;
2114+ }
2115+ }
2116+
2117+#ifdef DEBUG
2118+// dump_colors(colors, color_count);
2119+#endif
2120+
2121+ /* change the screen clut and rebuild our shading tables */
2122+ _change_clut(change_screen_clut, colors, color_count);
2123+}
2124+
2125+static void _change_clut(
2126+ void (*change_clut_proc)(struct color_table *color_table),
2127+ struct rgb_color_value *colors,
2128+ short color_count)
2129+{
2130+ struct color_table color_table;
2131+ struct rgb_color *color;
2132+ short i;
2133+
2134+ color= color_table.colors;
2135+ color_table.color_count= PIXEL8_MAXIMUM_COLORS;
2136+ for (i= 0; i<color_count; ++i, ++color, ++colors)
2137+ {
2138+ *color= *((struct rgb_color *)&colors->red);
2139+ }
2140+ for (i= color_count; i<PIXEL8_MAXIMUM_COLORS; ++i, ++color)
2141+ {
2142+ color->red= color->green= color->blue= 0;
2143+ }
2144+ change_clut_proc(&color_table);
2145+}
2146+
2147+#ifndef SCREAMING_METAL
2148+static void build_shading_tables8(
2149+ struct rgb_color_value *colors,
2150+ short color_count,
2151+ pixel8 *shading_tables)
2152+{
2153+ short i;
2154+ short start, count, level, value;
2155+
2156+ objlist_set(shading_tables, iBLACK, PIXEL8_MAXIMUM_COLORS);
2157+
2158+ start= 0, count= 0;
2159+ while (get_next_color_run(colors, color_count, &start, &count))
2160+ {
2161+ for (i= 0; i<count; ++i)
2162+ {
2163+ short adjust= start ? 1 : 0;
2164+
2165+ for (level= 0; level<number_of_shading_tables; ++level)
2166+ {
2167+ struct rgb_color_value *color= colors + start + i;
2168+ short multiplier= (color->flags&SELF_LUMINESCENT_COLOR_FLAG) ? (level>>1) : level;
2169+
2170+ value= i + (multiplier*(count+adjust-i))/(number_of_shading_tables-1);
2171+ if (value>=count) value= iBLACK; else value= start+value;
2172+ shading_tables[PIXEL8_MAXIMUM_COLORS*(number_of_shading_tables-level-1)+start+i]= value;
2173+ }
2174+ }
2175+ }
2176+}
2177+#else
2178+short find_closest_color(
2179+ struct rgb_color_value *color,
2180+ register struct rgb_color_value *colors,
2181+ short color_count)
2182+{
2183+ short i;
2184+ int32 closest_delta= INT32_MAX;
2185+ short closest_index= 0;
2186+
2187+ // = 1 to skip the transparent color
2188+ for (i= 1, colors+= 1; i<color_count; ++i, ++colors)
2189+ {
2190+ int32 delta= (int32)ABS(colors->red-color->red) +
2191+ (int32)ABS(colors->green-color->green) +
2192+ (int32)ABS(colors->blue-color->blue);
2193+
2194+ if (delta<closest_delta) closest_index= i, closest_delta= delta;
2195+ }
2196+
2197+ return closest_index;
2198+}
2199+
2200+static void build_shading_tables8(
2201+ struct rgb_color_value *colors,
2202+ short color_count,
2203+ pixel8 *shading_tables)
2204+{
2205+ short i;
2206+ short start, count, level;
2207+
2208+ objlist_set(shading_tables, iBLACK, PIXEL8_MAXIMUM_COLORS);
2209+
2210+ start= 0, count= 0;
2211+ while (get_next_color_run(colors, color_count, &start, &count))
2212+ {
2213+ for (i= 0; i<count; ++i)
2214+ {
2215+ for (level= 0; level<number_of_shading_tables; ++level)
2216+ {
2217+ struct rgb_color_value *color= colors + start + i;
2218+ rgb_color_value result;
2219+
2220+ result.red= (color->red*level)/(number_of_shading_tables-1);
2221+ result.green= (color->green*level)/(number_of_shading_tables-1);
2222+ result.blue= (color->blue*level)/(number_of_shading_tables-1);
2223+ shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2224+ find_closest_color(&result, colors, color_count);
2225+ }
2226+ }
2227+ }
2228+}
2229+#endif
2230+
2231+static void build_shading_tables16(
2232+ struct rgb_color_value *colors,
2233+ short color_count,
2234+ pixel16 *shading_tables,
2235+ byte *remapping_table,
2236+ bool is_opengl)
2237+{
2238+ short i;
2239+ short start, count, level;
2240+
2241+ objlist_set(shading_tables, 0, PIXEL8_MAXIMUM_COLORS);
2242+
2243+#ifdef SDL
2244+ SDL_PixelFormat *fmt = &pixel_format_16;
2245+#endif
2246+
2247+ start= 0, count= 0;
2248+ while (get_next_color_run(colors, color_count, &start, &count))
2249+ {
2250+ for (i=0;i<count;++i)
2251+ {
2252+ for (level= 0; level<number_of_shading_tables; ++level)
2253+ {
2254+ struct rgb_color_value *color= colors + (remapping_table ? remapping_table[start+i] : (start+i));
2255+ short multiplier= (color->flags&SELF_LUMINESCENT_COLOR_FLAG) ? ((number_of_shading_tables>>1)+(level>>1)) : level;
2256+#ifdef SDL
2257+ if (!is_opengl)
2258+ // Find optimal pixel value for video display
2259+ shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2260+ SDL_MapRGB(fmt,
2261+ ((color->red * multiplier) / (number_of_shading_tables-1)) >> 8,
2262+ ((color->green * multiplier) / (number_of_shading_tables-1)) >> 8,
2263+ ((color->blue * multiplier) / (number_of_shading_tables-1)) >> 8);
2264+ else
2265+#endif
2266+ // Mac xRGB 1555 pixel format
2267+ shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2268+ RGBCOLOR_TO_PIXEL16((color->red*multiplier)/(number_of_shading_tables-1),
2269+ (color->green*multiplier)/(number_of_shading_tables-1),
2270+ (color->blue*multiplier)/(number_of_shading_tables-1));
2271+ }
2272+ }
2273+ }
2274+}
2275+
2276+static void build_shading_tables32(
2277+ struct rgb_color_value *colors,
2278+ short color_count,
2279+ pixel32 *shading_tables,
2280+ byte *remapping_table,
2281+ bool is_opengl)
2282+{
2283+ short i;
2284+ short start, count, level;
2285+
2286+ objlist_set(shading_tables, 0, PIXEL8_MAXIMUM_COLORS);
2287+
2288+#ifdef SDL
2289+ SDL_PixelFormat *fmt = &pixel_format_32;
2290+#endif
2291+
2292+ start= 0, count= 0;
2293+ while (get_next_color_run(colors, color_count, &start, &count))
2294+ {
2295+ for (i= 0; i<count; ++i)
2296+ {
2297+ for (level= 0; level<number_of_shading_tables; ++level)
2298+ {
2299+ struct rgb_color_value *color= colors + (remapping_table ? remapping_table[start+i] : (start+i));
2300+ short multiplier= (color->flags&SELF_LUMINESCENT_COLOR_FLAG) ? ((number_of_shading_tables>>1)+(level>>1)) : level;
2301+
2302+#ifdef SDL
2303+ if (!is_opengl)
2304+ // Find optimal pixel value for video display
2305+ shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2306+ SDL_MapRGB(fmt,
2307+ ((color->red * multiplier) / (number_of_shading_tables-1)) >> 8,
2308+ ((color->green * multiplier) / (number_of_shading_tables-1)) >> 8,
2309+ ((color->blue * multiplier) / (number_of_shading_tables-1)) >> 8);
2310+ else
2311+#endif
2312+ // Mac xRGB 8888 pixel format
2313+ shading_tables[PIXEL8_MAXIMUM_COLORS*level+start+i]=
2314+ RGBCOLOR_TO_PIXEL32((color->red*multiplier)/(number_of_shading_tables-1),
2315+ (color->green*multiplier)/(number_of_shading_tables-1),
2316+ (color->blue*multiplier)/(number_of_shading_tables-1));
2317+ }
2318+ }
2319+ }
2320+}
2321+
2322+static void build_global_shading_table16(
2323+ void)
2324+{
2325+ if (!global_shading_table16)
2326+ {
2327+ short value, shading_table;
2328+ pixel16 *write;
2329+
2330+#ifdef SDL
2331+ SDL_PixelFormat *fmt = &pixel_format_16;
2332+#endif
2333+
2334+ global_shading_table16= (pixel16 *) malloc(sizeof(pixel16)*number_of_shading_tables*NUMBER_OF_COLOR_COMPONENTS*(PIXEL16_MAXIMUM_COMPONENT+1));
2335+ assert(global_shading_table16);
2336+
2337+ write= global_shading_table16;
2338+ for (shading_table= 0; shading_table<number_of_shading_tables; ++shading_table)
2339+ {
2340+#ifdef SDL
2341+ // Under SDL, the components may have different widths and different shifts
2342+ int shift = fmt->Rshift + (3 - fmt->Rloss);
2343+ for (value=0;value<=PIXEL16_MAXIMUM_COMPONENT;++value)
2344+ *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2345+ shift = fmt->Gshift + (3 - fmt->Gloss);
2346+ for (value=0;value<=PIXEL16_MAXIMUM_COMPONENT;++value)
2347+ *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2348+ shift = fmt->Bshift + (3 - fmt->Bloss);
2349+ for (value=0;value<=PIXEL16_MAXIMUM_COMPONENT;++value)
2350+ *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2351+#else
2352+ // Under MacOS, every component has the same width
2353+ for (short component=0;component<NUMBER_OF_COLOR_COMPONENTS;++component)
2354+ {
2355+ short shift= 5*(NUMBER_OF_COLOR_COMPONENTS-component-1);
2356+
2357+ for (value=0;value<=PIXEL16_MAXIMUM_COMPONENT;++value)
2358+ {
2359+ *write++= ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2360+ }
2361+ }
2362+#endif
2363+ }
2364+ }
2365+}
2366+
2367+static void build_global_shading_table32(
2368+ void)
2369+{
2370+ if (!global_shading_table32)
2371+ {
2372+ short value, shading_table;
2373+ pixel32 *write;
2374+
2375+#ifdef SDL
2376+ SDL_PixelFormat *fmt = &pixel_format_32;
2377+#endif
2378+
2379+ global_shading_table32= (pixel32 *) malloc(sizeof(pixel32)*number_of_shading_tables*NUMBER_OF_COLOR_COMPONENTS*(PIXEL32_MAXIMUM_COMPONENT+1));
2380+ assert(global_shading_table32);
2381+
2382+ write= global_shading_table32;
2383+ for (shading_table= 0; shading_table<number_of_shading_tables; ++shading_table)
2384+ {
2385+#ifdef SDL
2386+ // Under SDL, the components may have different widths and different shifts
2387+ int shift = fmt->Rshift - fmt->Rloss;
2388+ for (value=0;value<=PIXEL32_MAXIMUM_COMPONENT;++value)
2389+ *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2390+ shift = fmt->Gshift - fmt->Gloss;
2391+ for (value=0;value<=PIXEL32_MAXIMUM_COMPONENT;++value)
2392+ *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2393+ shift = fmt->Bshift - fmt->Bloss;
2394+ for (value=0;value<=PIXEL32_MAXIMUM_COMPONENT;++value)
2395+ *write++ = ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2396+#else
2397+ // Under MacOS, every component has the same width
2398+ for (short component= 0; component<NUMBER_OF_COLOR_COMPONENTS; ++component)
2399+ {
2400+ short shift= 8*(NUMBER_OF_COLOR_COMPONENTS-component-1);
2401+
2402+ for (value= 0; value<=PIXEL32_MAXIMUM_COMPONENT; ++value)
2403+ {
2404+ *write++= ((value*(shading_table))/(number_of_shading_tables-1))<<shift;
2405+ }
2406+ }
2407+#endif
2408+ }
2409+ }
2410+}
2411+
2412+static bool get_next_color_run(
2413+ struct rgb_color_value *colors,
2414+ short color_count,
2415+ short *start,
2416+ short *count)
2417+{
2418+ bool not_done= false;
2419+ struct rgb_color_value last_color;
2420+
2421+ if (*start+*count<color_count)
2422+ {
2423+ *start+= *count;
2424+ for (*count=0;*start+*count<color_count;*count+= 1)
2425+ {
2426+ if (*count)
2427+ {
2428+ if (new_color_run(colors+*start+*count, &last_color))
2429+ {
2430+ break;
2431+ }
2432+ }
2433+ last_color= colors[*start+*count];
2434+ }
2435+
2436+ not_done= true;
2437+ }
2438+
2439+ return not_done;
2440+}
2441+
2442+static bool new_color_run(
2443+ struct rgb_color_value *_new,
2444+ struct rgb_color_value *last)
2445+{
2446+ if ((int32)last->red+(int32)last->green+(int32)last->blue<(int32)_new->red+(int32)_new->green+(int32)_new->blue)
2447+ {
2448+ return true;
2449+ }
2450+ else
2451+ {
2452+ return false;
2453+ }
2454+}
2455+
2456+static int32 get_shading_table_size(
2457+ short collection_code)
2458+{
2459+ int32 size;
2460+
2461+ switch (bit_depth)
2462+ {
2463+ case 8: size= number_of_shading_tables*shading_table_size; break;
2464+ case 16: size= number_of_shading_tables*shading_table_size; break;
2465+ case 32: size= number_of_shading_tables*shading_table_size; break;
2466+ default:
2467+ assert(false);
2468+ break;
2469+ }
2470+
2471+ return size;
2472+}
2473+
2474+/* --------- light enhancement goggles */
2475+
2476+enum /* collection tint colors */
2477+{
2478+ _tint_collection_red,
2479+ _tint_collection_green,
2480+ _tint_collection_blue,
2481+ _tint_collection_yellow,
2482+ NUMBER_OF_TINT_COLORS
2483+};
2484+
2485+struct tint_color8_data
2486+{
2487+ short start, count;
2488+};
2489+
2490+static struct rgb_color tint_colors16[NUMBER_OF_TINT_COLORS]=
2491+{
2492+ {65535, 0, 0},
2493+ {0, 65535, 0},
2494+ {0, 0, 65535},
2495+ {65535, 65535, 0},
2496+};
2497+
2498+static struct tint_color8_data tint_colors8[NUMBER_OF_TINT_COLORS]=
2499+{
2500+ {45, 13},
2501+ {32, 13},
2502+ {96, 13},
2503+ {83, 13},
2504+};
2505+
2506+
2507+// LP addition to make it more generic;
2508+// the ultimate in this would be to make every collection
2509+// have its own infravision tint.
2510+static short CollectionTints[NUMBER_OF_COLLECTIONS] =
2511+{
2512+ // Interface
2513+ NONE,
2514+ // Weapons in hand
2515+ _tint_collection_yellow,
2516+ // Juggernaut, tick
2517+ _tint_collection_red,
2518+ _tint_collection_red,
2519+ // Explosion effects
2520+ _tint_collection_yellow,
2521+ // Hunter
2522+ _tint_collection_red,
2523+ // Player
2524+ _tint_collection_yellow,
2525+ // Items
2526+ _tint_collection_green,
2527+ // Trooper, Pfhor, S'pht'Kr, F'lickta
2528+ _tint_collection_red,
2529+ _tint_collection_red,
2530+ _tint_collection_red,
2531+ _tint_collection_red,
2532+ // Bob and VacBobs
2533+ _tint_collection_yellow,
2534+ _tint_collection_yellow,
2535+ // Enforcer, Drone
2536+ _tint_collection_red,
2537+ _tint_collection_red,
2538+ // S'pht
2539+ _tint_collection_blue,
2540+ // Walls
2541+ _tint_collection_blue,
2542+ _tint_collection_blue,
2543+ _tint_collection_blue,
2544+ _tint_collection_blue,
2545+ _tint_collection_blue,
2546+ // Scenery
2547+ _tint_collection_blue,
2548+ _tint_collection_blue,
2549+ _tint_collection_blue,
2550+ _tint_collection_blue,
2551+ _tint_collection_blue,
2552+ // Landscape
2553+ _tint_collection_blue,
2554+ _tint_collection_blue,
2555+ _tint_collection_blue,
2556+ _tint_collection_blue,
2557+ // Cyborg
2558+ _tint_collection_red
2559+};
2560+
2561+
2562+static void build_collection_tinting_table(
2563+ struct rgb_color_value *colors,
2564+ short color_count,
2565+ short collection_index,
2566+ bool is_opengl)
2567+{
2568+ struct collection_definition *collection= get_collection_definition(collection_index);
2569+ if (!collection) return;
2570+
2571+ void *tint_table= get_collection_tint_tables(collection_index, 0);
2572+ short tint_color;
2573+
2574+ /* get the tint color */
2575+ // LP change: look up a table
2576+ tint_color = CollectionTints[collection_index];
2577+ // Idiot-proofing:
2578+ if (tint_color >= NUMBER_OF_TINT_COLORS)
2579+ tint_color = NONE;
2580+ else
2581+ tint_color = MAX(tint_color,NONE);
2582+
2583+ /* build the tint table */
2584+ if (tint_color!=NONE)
2585+ {
2586+ // LP addition: OpenGL support
2587+ rgb_color &Color = tint_colors16[tint_color];
2588+#ifdef HAVE_OPENGL
2589+ OGL_SetInfravisionTint(collection_index,true,Color.red/65535.0F,Color.green/65535.0F,Color.blue/65535.0F);
2590+#endif
2591+ switch (bit_depth)
2592+ {
2593+ case 8:
2594+ build_tinting_table8(colors, color_count, (unsigned char *)tint_table, tint_colors8[tint_color].start, tint_colors8[tint_color].count);
2595+ break;
2596+ case 16:
2597+ build_tinting_table16(colors, color_count, (pixel16 *)tint_table, tint_colors16+tint_color);
2598+ break;
2599+ case 32:
2600+ build_tinting_table32(colors, color_count, (pixel32 *)tint_table, tint_colors16+tint_color, is_opengl);
2601+ break;
2602+ }
2603+ }
2604+ else
2605+ {
2606+ // LP addition: OpenGL support
2607+#ifdef HAVE_OPENGL
2608+ OGL_SetInfravisionTint(collection_index,false,1,1,1);
2609+#endif
2610+ }
2611+}
2612+
2613+static void build_tinting_table8(
2614+ struct rgb_color_value *colors,
2615+ short color_count,
2616+ pixel8 *tint_table,
2617+ short tint_start,
2618+ short tint_count)
2619+{
2620+ short start, count;
2621+
2622+ start= count= 0;
2623+ while (get_next_color_run(colors, color_count, &start, &count))
2624+ {
2625+ short i;
2626+
2627+ for (i=0; i<count; ++i)
2628+ {
2629+ short adjust= start ? 0 : 1;
2630+ short value= (i*(tint_count+adjust))/count;
2631+
2632+ value= (value>=tint_count) ? iBLACK : tint_start + value;
2633+ tint_table[start+i]= value;
2634+ }
2635+ }
2636+}
2637+
2638+static void build_tinting_table16(
2639+ struct rgb_color_value *colors,
2640+ short color_count,
2641+ pixel16 *tint_table,
2642+ struct rgb_color *tint_color)
2643+{
2644+ short i;
2645+
2646+#ifdef SDL
2647+ SDL_PixelFormat *fmt = &pixel_format_16;
2648+#endif
2649+
2650+ for (i= 0; i<color_count; ++i, ++colors)
2651+ {
2652+ int32 magnitude= ((int32)colors->red + (int32)colors->green + (int32)colors->blue)/(short)3;
2653+
2654+#ifdef SDL
2655+ // Find optimal pixel value for video display
2656+ *tint_table++= SDL_MapRGB(fmt,
2657+ ((magnitude * tint_color->red) / 0xFFFF) >> 8,
2658+ ((magnitude * tint_color->green) / 0xFFFF) >> 8,
2659+ ((magnitude * tint_color->blue) / 0xFFFF) >> 8);
2660+#else
2661+ // Mac xRGB 1555 pixel format
2662+ *tint_table++= RGBCOLOR_TO_PIXEL16((magnitude*tint_color->red)/0xFFFF,
2663+ (magnitude*tint_color->green)/0xFFFF, (magnitude*tint_color->blue)/0xFFFF);
2664+#endif
2665+ }
2666+}
2667+
2668+static void build_tinting_table32(
2669+ struct rgb_color_value *colors,
2670+ short color_count,
2671+ pixel32 *tint_table,
2672+ struct rgb_color *tint_color,
2673+ bool is_opengl)
2674+{
2675+ short i;
2676+
2677+#ifdef SDL
2678+ SDL_PixelFormat *fmt = &pixel_format_32;
2679+#endif
2680+
2681+ for (i= 0; i<color_count; ++i, ++colors)
2682+ {
2683+ int32 magnitude= ((int32)colors->red + (int32)colors->green + (int32)colors->blue)/(short)3;
2684+
2685+#ifdef SDL
2686+ // Find optimal pixel value for video display
2687+ if (!is_opengl)
2688+ *tint_table++= SDL_MapRGB(fmt,
2689+ ((magnitude * tint_color->red) / 65535) >> 8,
2690+ ((magnitude * tint_color->green) / 65535) >> 8,
2691+ ((magnitude * tint_color->blue) / 65535) >> 8);
2692+ else
2693+#endif
2694+ // Mac xRGB 8888 pixel format
2695+ *tint_table++= RGBCOLOR_TO_PIXEL32((magnitude*tint_color->red)/65535,
2696+ (magnitude*tint_color->green)/65535, (magnitude*tint_color->blue)/65535);
2697+ }
2698+}
2699+
2700+
2701+/* ---------- collection accessors */
2702+// Some originally from shapes_macintosh.c
2703+
2704+static struct collection_header *get_collection_header(
2705+ short collection_index)
2706+{
2707+ // This one is intended to bomb because collection indices can only be from 1 to 31,
2708+ // short of drastic changes in how collection indices are specified (a bigger structure
2709+ // than shape_descriptor, for example).
2710+ collection_header *header = GetMemberWithBounds(collection_headers,collection_index,MAXIMUM_COLLECTIONS);
2711+ vassert(header,csprintf(temporary,"Collection index out of range: %d",collection_index));
2712+
2713+ return header;
2714+
2715+ /*
2716+ assert(collection_index>=0 && collection_index<MAXIMUM_COLLECTIONS);
2717+
2718+ return collection_headers + collection_index;
2719+ */
2720+}
2721+
2722+/*static*/ struct collection_definition *get_collection_definition(
2723+ short collection_index)
2724+{
2725+ return get_collection_header(collection_index)->collection;
2726+}
2727+
2728+static struct rgb_color_value *get_collection_colors(
2729+ short collection_index,
2730+ short clut_number)
2731+{
2732+ collection_definition *definition = get_collection_definition(collection_index);
2733+ if (!definition) return NULL;
2734+ if (!(clut_number >= 0 && clut_number < definition->clut_count))
2735+ return NULL;
2736+
2737+ return &definition->color_tables[clut_number * definition->color_count];
2738+}
2739+
2740+struct rgb_color_value *get_collection_colors(
2741+ short collection_index,
2742+ short clut_number,
2743+ int &num_colors)
2744+{
2745+ collection_definition *definition = get_collection_definition(collection_index);
2746+ if (!definition) return NULL;
2747+ if (!(clut_number >=0 && clut_number < definition->clut_count)) return NULL;
2748+ num_colors = definition->color_count;
2749+ return &definition->color_tables[clut_number * definition->color_count];
2750+}
2751+
2752+static struct high_level_shape_definition *get_high_level_shape_definition(
2753+ short collection_index,
2754+ short high_level_shape_index)
2755+{
2756+ struct collection_definition *definition = get_collection_definition(collection_index);
2757+ if (!definition) return NULL;
2758+
2759+ if (!(high_level_shape_index >= 0 && high_level_shape_index<definition->high_level_shapes.size()))
2760+ return NULL;
2761+
2762+ return (high_level_shape_definition *) &definition->high_level_shapes[high_level_shape_index][0];
2763+}
2764+
2765+struct low_level_shape_definition *get_low_level_shape_definition(
2766+ short collection_index,
2767+ short low_level_shape_index)
2768+{
2769+ collection_definition *definition = get_collection_definition(collection_index);
2770+ if (!definition) return NULL;
2771+ if (low_level_shape_index >= 0 && low_level_shape_index < definition->low_level_shapes.size())
2772+ {
2773+ return &definition->low_level_shapes[low_level_shape_index];
2774+ }
2775+ else
2776+ return NULL;
2777+}
2778+
2779+static struct bitmap_definition *get_bitmap_definition(
2780+ short collection_index,
2781+ short bitmap_index)
2782+{
2783+ collection_definition *definition = get_collection_definition(collection_index);
2784+ if (!definition) return NULL;
2785+ if (!(bitmap_index >= 0 && bitmap_index < definition->bitmaps.size()))
2786+ return NULL;
2787+
2788+ return (bitmap_definition *) &definition->bitmaps[bitmap_index][0];
2789+}
2790+
2791+static void *get_collection_shading_tables(
2792+ short collection_index,
2793+ short clut_index)
2794+{
2795+ void *shading_tables= get_collection_header(collection_index)->shading_tables;
2796+
2797+ shading_tables = (uint8 *)shading_tables + clut_index*get_shading_table_size(collection_index);
2798+
2799+ return shading_tables;
2800+}
2801+
2802+static void *get_collection_tint_tables(
2803+ short collection_index,
2804+ short tint_index)
2805+{
2806+ struct collection_definition *definition= get_collection_definition(collection_index);
2807+ if (!definition) return NULL;
2808+
2809+ void *tint_table= get_collection_header(collection_index)->shading_tables;
2810+
2811+ tint_table = (uint8 *)tint_table + get_shading_table_size(collection_index)*definition->clut_count + shading_table_size*tint_index;
2812+
2813+ return tint_table;
2814+}
2815+
2816+// LP additions:
2817+
2818+// Whether or not collection is present
2819+bool is_collection_present(short collection_index)
2820+{
2821+ collection_header *CollHeader = get_collection_header(collection_index);
2822+ if (!CollHeader) return false;
2823+ return collection_loaded(CollHeader);
2824+}
2825+
2826+// Number of texture frames in a collection (good for wall-texture error checking)
2827+short get_number_of_collection_frames(short collection_index)
2828+{
2829+ struct collection_definition *Collection = get_collection_definition(collection_index);
2830+ if (!Collection) return 0;
2831+ return Collection->low_level_shape_count;
2832+}
2833+
2834+// Number of bitmaps in a collection (good for allocating texture information for OpenGL)
2835+short get_number_of_collection_bitmaps(short collection_index)
2836+{
2837+ struct collection_definition *Collection = get_collection_definition(collection_index);
2838+ if (!Collection) return 0;
2839+ return Collection->bitmap_count;
2840+}
2841+
2842+// Which bitmap index for a frame (good for OpenGL texture rendering)
2843+short get_bitmap_index(short collection_index, short low_level_shape_index)
2844+{
2845+ struct low_level_shape_definition *low_level_shape= get_low_level_shape_definition(collection_index, low_level_shape_index);
2846+ if (!low_level_shape) return NONE;
2847+ return low_level_shape->bitmap_index;
2848+}
2849+
2850+
2851+// XML elements for parsing infravision specification;
2852+// this is a specification of a set of infravision colors
2853+// and which collections are to get them
2854+
2855+short *OriginalCollectionTints = NULL;
2856+// This assigns an infravision color to a collection
2857+class XML_InfravisionAssignParser: public XML_ElementParser
2858+{
2859+ bool IsPresent[2];
2860+ short Coll, Color;
2861+
2862+public:
2863+ bool Start();
2864+ bool HandleAttribute(const char *Tag, const char *Value);
2865+ bool AttributesDone();
2866+ bool ResetValues();
2867+
2868+ XML_InfravisionAssignParser(): XML_ElementParser("assign") {}
2869+};
2870+
2871+bool XML_InfravisionAssignParser::Start()
2872+{
2873+ // back up old values first
2874+ if (!OriginalCollectionTints) {
2875+ OriginalCollectionTints = (short *) malloc(sizeof(short) * NUMBER_OF_COLLECTIONS);
2876+ assert(OriginalCollectionTints);
2877+ for (int i = 0; i < NUMBER_OF_COLLECTIONS; i++)
2878+ OriginalCollectionTints[i] = CollectionTints[i];
2879+ }
2880+
2881+ for (int k=0; k<2; k++)
2882+ IsPresent[k] = false;
2883+ return true;
2884+}
2885+
2886+bool XML_InfravisionAssignParser::HandleAttribute(const char *Tag, const char *Value)
2887+{
2888+ if (StringsEqual(Tag,"coll"))
2889+ {
2890+ if (ReadBoundedInt16Value(Value,Coll,0,NUMBER_OF_COLLECTIONS-1))
2891+ {
2892+ IsPresent[0] = true;
2893+ return true;
2894+ }
2895+ else return false;
2896+ }
2897+ else if (StringsEqual(Tag,"color"))
2898+ {
2899+ if (ReadBoundedInt16Value(Value,Color,0,NUMBER_OF_TINT_COLORS-1))
2900+ {
2901+ IsPresent[1] = true;
2902+ return true;
2903+ }
2904+ else return false;
2905+ }
2906+ UnrecognizedTag();
2907+ return false;
2908+}
2909+
2910+bool XML_InfravisionAssignParser::AttributesDone()
2911+{
2912+ // Verify...
2913+ bool AllPresent = true;
2914+ for (int k=0; k<2; k++)
2915+ if (!IsPresent[k]) AllPresent = false;
2916+
2917+ if (!AllPresent)
2918+ {
2919+ AttribsMissing();
2920+ return false;
2921+ }
2922+
2923+ // Put into place
2924+ CollectionTints[Coll] = Color;
2925+ return true;
2926+}
2927+
2928+bool XML_InfravisionAssignParser::ResetValues()
2929+{
2930+ if (OriginalCollectionTints) {
2931+ for (int i = 0; i < NUMBER_OF_COLLECTIONS; i++)
2932+ CollectionTints[i] = OriginalCollectionTints[i];
2933+ free(OriginalCollectionTints);
2934+ OriginalCollectionTints = NULL;
2935+ }
2936+ return true;
2937+}
2938+
2939+static XML_InfravisionAssignParser InfravisionAssignParser;
2940+
2941+
2942+struct rgb_color *original_tint_colors16 = NULL;
2943+// Subclassed to set the color objects appropriately
2944+class XML_InfravisionParser: public XML_ElementParser
2945+{
2946+public:
2947+ bool Start()
2948+ {
2949+ // back up old values first
2950+ if (!original_tint_colors16) {
2951+ original_tint_colors16 = (struct rgb_color *) malloc(sizeof(struct rgb_color) * NUMBER_OF_TINT_COLORS);
2952+ assert(original_tint_colors16);
2953+ for (int i = 0; i < NUMBER_OF_TINT_COLORS; i++)
2954+ original_tint_colors16[i] = tint_colors16[i];
2955+ }
2956+ Color_SetArray(tint_colors16,NUMBER_OF_TINT_COLORS);
2957+ return true;
2958+ }
2959+ bool HandleAttribute(const char *Tag, const char *Value)
2960+ {
2961+ UnrecognizedTag();
2962+ return false;
2963+ }
2964+ bool ResetValues()
2965+ {
2966+ if (original_tint_colors16) {
2967+ for (int i = 0; i < NUMBER_OF_TINT_COLORS; i++)
2968+ tint_colors16[i] = original_tint_colors16[i];
2969+ free(original_tint_colors16);
2970+ original_tint_colors16 = NULL;
2971+ }
2972+ return true;
2973+ }
2974+
2975+ XML_InfravisionParser(): XML_ElementParser("infravision") {}
2976+};
2977+
2978+static XML_InfravisionParser InfravisionParser;
2979+
2980+// LP change: added infravision-parser export
2981+XML_ElementParser *Infravision_GetParser()
2982+{
2983+ InfravisionParser.AddChild(&InfravisionAssignParser);
2984+ InfravisionParser.AddChild(Color_GetParser());
2985+
2986+ return &InfravisionParser;
2987+}
--- marathon/trunk/Source_Files/RenderMain/OGL_Subst_Texture_Def.h (revision 509)
+++ marathon/trunk/Source_Files/RenderMain/OGL_Subst_Texture_Def.h (revision 510)
@@ -41,18 +41,8 @@
4141
4242 // Parameters for mapping substitute sprites (inhabitants, weapons in hand)
4343
44- // shape bounding box, in pixel units (need to apply scale factor)
45- short shape_width;
46- short shape_height;
47-
48- // shape origin / keypoint offset, in pixel units (need to apply scale factor)
49- short offset_x;
50- short offset_y;
51-
5244 OGL_TextureOptions():
53- VoidVisible(false),
54- shape_width(0), shape_height(0),
55- offset_x(0), offset_y(0) {}
45+ VoidVisible(false) {}
5646 };
5747
5848
--- marathon/trunk/Source_Files/Misc/preferences.cpp (revision 509)
+++ marathon/trunk/Source_Files/Misc/preferences.cpp (revision 510)
@@ -345,7 +345,7 @@
345345 };
346346
347347 static const char *shape_labels[3] = {
348- "Cross", "Octagon", NULL
348+ "十\字", "多角形", NULL
349349 };
350350
351351 enum { kCrosshairWidget };
@@ -835,7 +835,7 @@
835835 os << it->first << "x" << it->second;
836836 if (first_mode)
837837 {
838- result.push_back("Automatic");
838+ result.push_back("自動");
839839 first_mode = false;
840840 }
841841 result.push_back(os.str());
@@ -1138,7 +1138,7 @@
11381138 table->dual_add_row(new w_static_text("ネットワークマイク"), d);
11391139
11401140 w_toggle* mute_while_transmitting_w = new w_toggle(!sound_preferences->mute_while_transmitting);
1141- table->dual_add(mute_while_transmitting_w->label("Headset Mic Mode"), d);
1141+ table->dual_add(mute_while_transmitting_w->label("ヘッドセットマイクモード"), d);
11421142 table->dual_add(mute_while_transmitting_w, d);
11431143
11441144 table->add_row(new w_spacer(), true);
@@ -1522,7 +1522,7 @@
15221522
15231523 static const char *action_name[NUM_KEYS] = {
15241524 "前進", "後退", "左に向く", "右に向く", "左にサイドステップ", "右にサイドステップ",
1525- "左を一瞥", "右を一瞥", "上を見る", "下を見る", "Look Ahead",
1525+ "左を見る", "右を見る", "上を見る", "下を見る", "前を見る",
15261526 "前の武器", "次の武器", "主砲", "副砲",
15271527 "サイドステップ", "走る/泳ぐ", "見る",
15281528 "アクション", "地図", "マイク"
@@ -1529,7 +1529,7 @@
15291529 };
15301530
15311531 static const char *shell_action_name[NUMBER_OF_SHELL_KEYS] = {
1532- "道具左", "道具右", "プレイヤービューを切り替え", "ボリュームを上げる", "ボリュームを下げる", "マップを拡大", "マップを縮小", "FPSを表\示", "チャット/コンソ\ール", "ネットワーク状況"
1532+ "前の道具", "次の道具", "主観/客観切り替え", "ボリュームを上げる", "ボリュームを下げる", "マップを拡大", "マップを縮小", "FPSを表\示", "チャット/コンソ\ール", "ネットワーク状況"
15331533 };
15341534
15351535 static SDLKey default_keys[NUM_KEYS] = {
--- marathon/trunk/Source_Files/Misc/sdl_widgets.cpp (revision 509)
+++ marathon/trunk/Source_Files/Misc/sdl_widgets.cpp (revision 510)
@@ -1314,35 +1314,35 @@
13141314
13151315 // ZZZ: we provide phony key names for the phony keys used for mouse buttons.
13161316 static const char* sMouseButtonKeyName[NUM_SDL_MOUSE_BUTTONS] = {
1317- "mouse 1", // things like "Middle Mouse Button" are too long to draw properly
1318- "mouse 3",
1319- "mouse 2",
1320- "mouse 4",
1321- "mouse 5",
1322- "mouse 6",
1323- "mouse 7",
1324- "mouse 8"
1317+ "マウス1", // things like "Middle マウスButton" are too long to draw properly
1318+ "マウス3",
1319+ "マウス2",
1320+ "マウス4",
1321+ "マウス5",
1322+ "マウス6",
1323+ "マウス7",
1324+ "マウス8"
13251325 };
13261326
13271327 static const char* sJoystickButtonKeyName[NUM_SDL_JOYSTICK_BUTTONS] = {
1328- "joystick 1",
1329- "joystick 2",
1330- "joystick 3",
1331- "joystick 4",
1332- "joystick 5",
1333- "joystick 6",
1334- "joystick 7",
1335- "joystick 8",
1336- "joystick 9",
1337- "joystick 10",
1338- "joystick 11",
1339- "joystick 12",
1340- "joystick 13",
1341- "joystick 14",
1342- "joystick 15",
1343- "joystick 16",
1344- "joystick 17",
1345- "joystick 18"
1328+ "ジョイスティック1",
1329+ "ジョイスティック2",
1330+ "ジョイスティック3",
1331+ "ジョイスティック4",
1332+ "ジョイスティック5",
1333+ "ジョイスティック6",
1334+ "ジョイスティック7",
1335+ "ジョイスティック8",
1336+ "ジョイスティック9",
1337+ "ジョイスティック10",
1338+ "ジョイスティック11",
1339+ "ジョイスティック12",
1340+ "ジョイスティック13",
1341+ "ジョイスティック14",
1342+ "ジョイスティック15",
1343+ "ジョイスティック16",
1344+ "ジョイスティック17",
1345+ "ジョイスティック18"
13461346 };
13471347
13481348 // ZZZ: this injects our phony key names but passes along the rest.
@@ -2150,16 +2150,16 @@
21502150 {
21512151 if (item.minutes_remaining() == 1)
21522152 {
2153- time_or_ping << "~1 Minute";
2153+ time_or_ping << "1分未満";
21542154 }
21552155 else
21562156 {
2157- time_or_ping << item.minutes_remaining() << " Minutes";
2157+ time_or_ping << item.minutes_remaining() << "分";
21582158 }
21592159 }
21602160 else
21612161 {
2162- time_or_ping << "Untimed";
2162+ time_or_ping << "無制限";
21632163 }
21642164 }
21652165 else
@@ -2186,7 +2186,7 @@
21862186 game_and_map << "|i" << item.m_description.m_scenarioName;
21872187 if (item.m_description.m_scenarioVersion != "")
21882188 {
2189- game_and_map << ", Version " << item.m_description.m_scenarioVersion;
2189+ game_and_map << ", バージョン " << item.m_description.m_scenarioVersion;
21902190 }
21912191 }
21922192 else
@@ -2208,11 +2208,11 @@
22082208 {
22092209 if (item.m_description.m_numPlayers == 1)
22102210 {
2211- game_settings << "1 Player";
2211+ game_settings << "1人のプレイヤー";
22122212 }
22132213 else
22142214 {
2215- game_settings << static_cast<uint16>(item.m_description.m_numPlayers) << " Players";
2215+ game_settings << static_cast<uint16>(item.m_description.m_numPlayers) << "人のプレイヤー";
22162216 }
22172217 }
22182218 else
@@ -2220,7 +2220,7 @@
22202220 game_settings << static_cast<uint16>(item.m_description.m_numPlayers)
22212221 << "/"
22222222 << item.m_description.m_maxPlayers
2223- << " Players";
2223+ << "人のプレイヤー";
22242224 }
22252225
22262226 if (item.m_description.m_timeLimit && !(item.m_description.m_timeLimit == INT32_MAX || item.m_description.m_timeLimit == -1))
@@ -2227,12 +2227,12 @@
22272227 {
22282228 game_settings << ", "
22292229 << item.m_description.m_timeLimit / 60 / TICKS_PER_SECOND
2230- << " Minutes";
2230+ << "分";
22312231 }
22322232
22332233 if (item.m_description.m_teamsAllowed)
22342234 {
2235- game_settings << ", Teams";
2235+ game_settings << ", チーム";
22362236 }
22372237
22382238 draw_text(s, game_settings.str().c_str(), x, y, fg, font, game_style);
--- marathon/trunk/Source_Files/Misc/alephversion.h (revision 509)
+++ marathon/trunk/Source_Files/Misc/alephversion.h (revision 510)
@@ -24,9 +24,9 @@
2424
2525
2626 #define A1_DISPLAY_NAME "Aleph One JP"
27-#define A1_DISPLAY_VERSION "1.0JP2"
28-#define A1_DISPLAY_DATE_VERSION "2011-12-15"
29-#define A1_DATE_VERSION "20111215"
27+#define A1_DISPLAY_VERSION "1.0JP3"
28+#define A1_DISPLAY_DATE_VERSION "2011-12-26"
29+#define A1_DATE_VERSION "20111226"
3030
3131 #ifdef WIN32
3232 #define A1_DISPLAY_PLATFORM "Windows"
--- marathon/trunk/Source_Files/Misc/DefaultStringSets.cpp (revision 509)
+++ marathon/trunk/Source_Files/Misc/DefaultStringSets.cpp (revision 510)
@@ -50,38 +50,38 @@
5050 // -----------------------------------------------------------------------------------------
5151 // <!-- STR# Resource: "Errors" -->
5252 static const char* sStringSetNumber128[] = {
53- "AlephOneには68040以上のプロセッサが必要です。", - "AlephOneには Color QuickDraw が必要です。", - "AlephOneには 漢字Talk 7.1 以降のシステムが必要です。", - "AlephOneには 3000k 以上の空きRAMが必要です。", - "AlephOneには13インチ以上(640x480)そして256色(またはグレー)が表\示できるモニタが必要です。", - "Map, Shapes, Images, Sounds のファイルが Marathon アプリケーションと同じフォルダに入っているか確認してください。", - "システムメモリが少ないためサウンド用のメモリが割り当てられません(Marathonの割り当てメモリを減らしてください)。", - "AlephOneの実行中にファイルシステムエラーが発生しました。ディスク上の空要領とロックされていないか確認してください。", - "このAlephOneのコピーはウイルスなどによって変更されています。オリジナルのディスクから再度インストールしてください。", - "This beta copy of Marathon has expired and is no longer functional. Call Bungie at (312) 563-6200 ext. 21 for more information.", - "そのキーは既にボリューム調整に使われています。", - "そのキーは既に地図のズームに使われています。", - "そのキーは既にアイテムのスクロールに使われています。", - "そのキーは既にゲームの機能\に使われています。", - "AlephOneはこのマップをロードするためのメモリが足りません。メモリ量を増やしてもう一度実行してください。", - "AlephOneはこれから別の物理設定ファイルをロードします。そのため性能\が落ちたり、クラッシュしたり、保存ゲームファイルが悪化したり、ネットワークゲームが不安定になるおそれがあります。ご注意ください!", - "AlephOneは Bungie製以外の地図を使っています。そのため性能\が落ちたり、クラッシュしたり、保存ゲームファイルが悪化するおそれがあります。ご注意ください!", - "地図または保存ゲームファイルを読み込む際に致命的エラーが発生しました。", - "セーブファイルからマップを読み込むときにシステムエラーが発生しました。", - "保存ゲームファイルの保存中にエラーが発生しました。ハードディスクが一杯か、ロックされているかもしれません。", - "シリアル番号が無効です。もう一度入力してください。", - "ネットワークゲームの際に同じシリアル番号を複数のマシンでご使用いただくことはできません。新たに製品をご購入いただく必要があります。詳しくは日本国内の販売代理店まで連絡してください。", - "このAlephOneのコピーはネットワーク専用のシリアル番号で登録されています。ネットワーク専用のシリアル番号では一人用のプレーはできません。", - "読み込もうとしている地図がこわれているぞ。バックアップコピーから再度インストールしよう。", - "チェックポイント %d は見つかりませんでした!", - "ピクチャー %d は見つかりませんでした!", - "このバージョンのAleph Oneはプレビュー版につき、ネットワークゲームをサポートしていません。Bungie社からは、まもなくネットワーク対応版が出ます。(この他多くのクールな特徴を持った)", - "プレーヤーを集めたプレーヤーが勝手にみんなをおいてゲームを終了してしまった。張本人を処罰した方がよいかも...。", - "すまん。AlephOneはネットワークゲームからの終了に失敗してしまった。その結果、このレベルでの君の努力は水の泡となってしまった。", - "この保存されたゲームのシナリオファイルが見つかりません。レベルを替えるとき、デフォルトの地図に戻ります。", - "この映画を記録した地図が見つかりません。映画は再生できません。", - "AlephOneをネットワーク上で遊ぶには 6000k 以上の空きRAMが必要です。メモリ量を増やしてもう一度実行してください。", + "AlephOneには68040以上のプロセッサが必要です。",
53+ "AlephOneには Color QuickDraw が必要です。",
54+ "AlephOneには 漢字Talk 7.1 以降のシステムが必要です。",
55+ "AlephOneには 3000k 以上の空きRAMが必要です。",
56+ "AlephOneには13インチ以上(640x480)そして256色(またはグレー)が表\示できるモニタが必要です。",
57+ "Map, Shapes, Images, Sounds のファイルが Marathon アプリケーションと同じフォルダに入っているか確認してください。",
58+ "システムメモリが少ないためサウンド用のメモリが割り当てられません(Marathonの割り当てメモリを減らしてください)。",
59+ "AlephOneの実行中にファイルシステムエラーが発生しました。ディスク上の空要領とロックされていないか確認してください。",
60+ "このAlephOneのコピーはウイルスなどによって変更されています。オリジナルのディスクから再度インストールしてください。",
61+ "This beta copy of Marathon has expired and is no longer functional. Call Bungie at (312) 563-6200 ext. 21 for more information.",
62+ "そのキーは既にボリューム調整に使われています。",
63+ "そのキーは既に地図のズームに使われています。",
64+ "そのキーは既にアイテムのスクロールに使われています。",
65+ "そのキーは既にゲームの機能\に使われています。",
66+ "AlephOneはこのマップをロードするためのメモリが足りません。メモリ量を増やしてもう一度実行してください。",
67+ "AlephOneはこれから別の物理設定ファイルをロードします。そのため性能\が落ちたり、クラッシュしたり、保存ゲームファイルが悪化したり、ネットワークゲームが不安定になるおそれがあります。ご注意ください!",
68+ "AlephOneは Bungie製以外の地図を使っています。そのため性能\が落ちたり、クラッシュしたり、保存ゲームファイルが悪化するおそれがあります。ご注意ください!",
69+ "地図または保存ゲームファイルを読み込む際に致命的エラーが発生しました。",
70+ "セーブファイルからマップを読み込むときにシステムエラーが発生しました。",
71+ "保存ゲームファイルの保存中にエラーが発生しました。ハードディスクが一杯か、ロックされているかもしれません。",
72+ "シリアル番号が無効です。もう一度入力してください。",
73+ "ネットワークゲームの際に同じシリアル番号を複数のマシンでご使用いただくことはできません。新たに製品をご購入いただく必要があります。詳しくは日本国内の販売代理店まで連絡してください。",
74+ "このAlephOneのコピーはネットワーク専用のシリアル番号で登録されています。ネットワーク専用のシリアル番号では一人用のプレーはできません。",
75+ "読み込もうとしている地図がこわれているぞ。バックアップコピーから再度インストールしよう。",
76+ "チェックポイント %d は見つかりませんでした!",
77+ "ピクチャー %d は見つかりませんでした!",
78+ "このバージョンのAleph Oneはプレビュー版につき、ネットワークゲームをサポートしていません。Bungie社からは、まもなくネットワーク対応版が出ます。(この他多くのクールな特徴を持った)",
79+ "プレーヤーを集めたプレーヤーが勝手にみんなをおいてゲームを終了してしまった。張本人を処罰した方がよいかも...。",
80+ "すまん。AlephOneはネットワークゲームからの終了に失敗してしまった。その結果、このレベルでの君の努力は水の泡となってしまった。",
81+ "この保存されたゲームのシナリオファイルが見つかりません。レベルを替えるとき、デフォルトの地図に戻ります。",
82+ "この映画を記録した地図が見つかりません。映画は再生できません。",
83+ "AlephOneをネットワーク上で遊ぶには 6000k 以上の空きRAMが必要です。メモリ量を増やしてもう一度実行してください。",
5484 "スクリプト同士が競合を起こしているようです。MMLとネットスクリプトで誰をLuaでコントロールするかが異なっていると思われます。予\期しない動きや同期乱れが起こるかもしれません。",
5585 "この通知は、新しいバージョンのAlephOne向けに作られており、プレイできない場合に表\示されます。AlephOneをアップグレードしてください。",
5686 "スクロールホイールは、武器の切り替えで使用されています。",
@@ -140,13 +140,13 @@
140140 "ホストをしているコンピュータからの応答がありません。"
141141 "ファイヤーウォールが適切に設定されているか、アドレスが間違っていないかを確認して下さい。",
142142
143- "Sorry, the gathering computer has cancelled the game (you should all gang up on him next game).",
143+ "プレーヤーを集めていたプレーヤーが、勝手にみんなをおいてゲームを終了してしまった。(張本人を処罰した方がよいかも…。)",
144144
145- "The map was not received in its entirety, so the game has been canceled.",
145+ "マップを全員に送ることが出来なかったため、ゲームがキャンセルされました。",
146146
147147 "呼び出し側のコンピュータが地図を送らなかったため、ゲームがキャンセルされました。他のコンピュータの接続が切れたかもしれません。",
148148 "AlephOneは、ゲームを開始できません。他のコンピュータの接続が切れたかもしれません。",
149- "ゲームの参加中にエラーが発生しました(アプリケーションのバージョンが違うかもしれません)。もう一度試してみてください。",
149+ "ゲームの参加中にエラーが発生しました(アプリケーションのバージョンが違うかもしれません)。もう一度試してみてください。",
150150 "ネットワークエラーのためAlephOneは続行できません。",
151151
152152 "バージョンが異なるためそのプレーヤーはゲームに参加できませんでした。",
@@ -160,15 +160,15 @@
160160
161161 "サーバーからマップを送るときにエラーが発生しました。ゲーム終了します。",
162162
163- "The gatherer is using the star protocol, but your configuration is set to ring. You will not appear in the list of available players.",
163+ "募集をかけている人は、スタープロトコルを使用していますが、あなたの設定はリングになっています。このため、対戦可能\な他のプレイヤーのリストに表\示されません。",
164164
165- "The gatherer is using the ring protocol, but your configuration is set to star. You will not appear in the list of available players.",
165+ "募集をかけている人は、リングプロトコルを使用していますが、あなたの設定はスターになっています。このため、対戦可能\な他のプレイヤーのリストに表\示されません。",
166166
167- "The gatherer is using a Lua netscript, but this version was built without Lua support. You will not appear in the list of available players.",
167+ "募集をかけている人はLuaのネットスクリプトを使用していますが、このバージョンは、ビルド時にLuaが有効になっていません。このため、対戦可能\な他のプレイヤーのリストに表\示されません。",
168168
169- "There was a problem connecting to the server that tracks Internet games. Please try again later.",
169+ "インターネット上のゲームを募集しているサーバーへの接続に問題が発生しました。お手数ですが、もう一度やり直してください。",
170170
171- "Your game could not be advertised on the Internet. Please distribute your public IP address by other means or try again later.",
171+ "あなたが募集しようとしているゲームは、インターネット上に通知することができませんでした。他の方法で、あなたのIPアドレスを知らせるか、もう一度やり直してください。",
172172
173173 "Aleph Oneは、ファイヤーウォールやルーターの設定を変更することができませんでした。プレイヤーを募集することができません。"
174174
@@ -212,7 +212,7 @@
212212 "[",
213213 "I",
214214 "P",
215- "Return",
215+ "リターン",
216216 "L",
217217 "J",
218218 "'",
@@ -225,7 +225,7 @@
225225 "M",
226226 ".",
227227 "Tab",
228- "Space",
228+ "スペース",
229229 "`",
230230 "Delete",
231231 "0x34",
@@ -241,34 +241,34 @@
241241 "0x3e",
242242 "0x3f",
243243 "0x40",
244- "Keypad .",
244+ "テンキーの.",
245245 "0x42",
246- "Keypad *",
246+ "テンキーの*",
247247 "0x44",
248- "Keypad +",
248+ "テンキーの+",
249249 "0x46",
250250 "Clear",
251251 "0x48",
252252 "0x49",
253253 "0x4a",
254- "Keypad /",
254+ "テンキーの/",
255255 "Enter",
256256 "0x4d",
257- "Keypad -",
257+ "テンキーの-",
258258 "0x4f",
259259 "0x50",
260- "Keypad =",
261- "Keypad 0",
262- "Keypad 1",
263- "Keypad 2",
264- "Keypad 3",
265- "Keypad 4",
266- "Keypad 5",
267- "Keypad 6",
268- "Keypad 7",
260+ "テンキーの=",
261+ "テンキーの0",
262+ "テンキーの1",
263+ "テンキーの2",
264+ "テンキーの3",
265+ "テンキーの4",
266+ "テンキーの5",
267+ "テンキーの6",
268+ "テンキーの7",
269269 "0x5a",
270- "Keypad 8",
271- "Keypad 9",
270+ "テンキーの8",
271+ "テンキーの9",
272272 "0x5d",
273273 "0x5e",
274274 "0x5f",
@@ -308,49 +308,43 @@
308308
309309 // STR# Resource: "Preferences Advice"
310310 static const char* sStringSetNumber134[] = {
311- "外部スピーカー又はヘッドフォンが接続され、サウンドのコントロールパネルでステレオ出力がオンになっていることを確認してください。", - "Cybermaxx ヘルメットがシリアルポートに接続され、オンになっていることを確認してください。", + "外部スピーカー又はヘッドフォンが接続され、サウンドのコントロールパネルでステレオ出力がオンになっていることを確認してください。",
311+ "Cybermaxx ヘルメットがシリアルポートに接続され、オンになっていることを確認してください。",
312312 "機能\拡張フォルダに QuickTime Musical Instruments ファイルが入っていることを確認してくさい。入っていないとBGMはすごくバカらしく聞こえるぞ..."
313313 };
314314
315315 // STR# Resource: "Computer Interface"
316316 static const char* sStringSetNumber135[] = {
317- "U.E.S.C. Marathon",
318-// "Opening Connection to b.4.5-23",
317+ "U.E.S.C. Marathon",
319318 "β.4.5-23 と接続開始中",
320- "CAS.qterm//CyberAcme Systems Inc.",
321- "<931.461.60231.14.vt920>",
322-// "UESCTerm 802.11 (remote override)",
319+ "CAS.qterm//CyberAcme Systems Inc.",
320+ "<931.461.60231.14.vt920>",
323321 "UESCターミナル 802.11(リモートオーバードライブ)",
324-// "PgUp/PgDown/Arrows To Scroll",
325322 "PgUp/PgDown/矢印キーでスクロール",
326-// "Return/Enter To Acknowledge",
327323 "Return/Enterキーで了解",
328-// "Disconnecting...",
329- "接続切断",
330-// "Connection Terminated.",
324+ "接続切断中…",
331325 "接続終了",
332- "%H%M %m.%d.%Y",
326+ "%H%M %m.%d.%Y",
333327 };
334328
335329 // STR# Resource: "Join Dialog Messages"
336330 static const char* sStringSetNumber136[] = {
337- "「参加」をクリックするとネットワークゲームに参加できます。",
338- "サーバーからネットワークゲームに呼び出されるのを待っています。「キャンセル」をクリックすると中断します。",
339- "ネットワークゲームに参加しました。サーバーは他のプレーヤーを集めています..."
331+ "「参加」をクリックするとネットワークゲームに参加できます。",
332+ "サーバーからネットワークゲームに呼び出されるのを待っています。「キャンセル」をクリックすると中断します。",
333+ "ネットワークゲームに参加しました。サーバーは他のプレーヤーを集めています…。"
340334 };
341335
342336 // STR# Resource: "Weapon Names"
343337 static const char* sStringSetNumber137[] = {
344- "拳骨",
345- ".44 マグナム・メガ級 A1",
346- "ゼウス級核融合ピストル",
347- "MA-75B 機関銃/グレネード砲",
348- "SPNKR-X18型ミサイルランチャー",
349- "TOZT-7 火炎放射機",
350- "武器類不明 システムエラー 0xfded",
351- "WSTE-M 戦闘用ショットガン",
352- "(somehow related to time of applicability)",
338+ "拳骨",
339+ ".44 マグナム・メガ級 A1",
340+ "ゼウス級核融合ピストル",
341+ "MA-75B 機関銃/グレネード砲",
342+ "SPNKR-X18型ミサイルランチャー",
343+ "TOZT-7 火炎放射機",
344+ "武器類不明 システムエラー 0xfded",
345+ "WSTE-M 戦闘用ショットガン",
346+ "(適用可能\な時間に関連する何か)",
353347 "KKV-7 10MMフルチエット小型軽機関銃",
354348 };
355349
@@ -361,25 +355,25 @@
361355
362356 // STR# Resource: "Preferences Groupings"
363357 static const char* sStringSetNumber139[] = {
364- "グラフィック",
365- "プレイヤー",
366- "サウンド",
367- "コントロール",
358+ "グラフィック",
359+ "プレイヤー",
360+ "サウンド",
361+ "コントロール",
368362 "環境"
369363 };
370364
371365 // STR# Resource: "Postgame network game stats"
372366 static const char* sStringSetNumber140[] = {
373- "%d 旗",
374- "%d:%02d",
375- "%d 点",
376- "チーム",
377- "ボールの保持時間",
378- "旗の捕獲",
379- "時間",
380- "ゴール",
381- "陣地にいた時間",
367+ "%d 旗",
368+ "%d:%02d",
369+ "%d 点",
370+ "チーム",
371+ "ボールの保持時間",
372+ "旗の捕獲",
373+ "時間",
374+ "ゴール",
382375 "陣地にいた時間",
376+ "陣地にいた時間",
383377 "ポイント",
384378 "時間"
385379 };
@@ -386,13 +380,13 @@
386380
387381 // STR# Resource: "Net Game Setup"
388382 static const char* sStringSetNumber141[] = {
389- "殺傷制限",
390- "殺傷",
391- "捕獲制限",
392- "旗",
393- "点数制限",
394- "点数",
395- "陣地にいた時間",
383+ "殺傷制限",
384+ "殺傷",
385+ "捕獲制限",
386+ "旗",
387+ "点数制限",
388+ "点数",
389+ "陣地にいた時間",
396390 "分",
397391 "ポイント",
398392 "時間"
@@ -400,14 +394,14 @@
400394
401395 // STR# Resource: "New Join Dialog Messages"
402396 static const char* sStringSetNumber142[] = {
403- "君は「%s」ゲームに受け入れられました。サーバーが残りのプレーヤーを追加するまで少々おまちください…",
404- "個人対戦"
405- "君は「共同対戦」ゲームに受け入れられました。サーバーが残りのプレーヤーを追加するまで少々おまちください…",
406- "旗取り",
407- "陣地取り",
408- "ボールの取り合い",
409- "防衛戦",
410- "ラグビー",
397+ "君は「%s」ゲームに受け入れられました。サーバーが残りのプレーヤーを追加するまで少々おまちください…",
398+ "個人対戦"
399+ "君は「共同対戦」ゲームに受け入れられました。サーバーが残りのプレーヤーを追加するまで少々おまちください…",
400+ "旗取り",
401+ "陣地取り",
402+ "ボールの取り合い",
403+ "防衛戦",
404+ "ラグビー",
411405 "鬼ごっこ",
412406 "君はカスタムゲームに受け入れられました。サーバーが残りのプレーヤーを追加するまで少々おまちください…",
413407 };
@@ -414,17 +408,17 @@
414408
415409 // STR# Resource: "Progress strings for networking"
416410 static const char* sStringSetNumber143[] = {
417- "プレイヤーへ地図を転送中です。",
418- "プレイヤーへ地図を転送中です。",
419- "サーバーから地図を転送しています。",
420- "サーバーから地図の転送をお待ちください。",
421- "環境データを他のプレイヤーへ転送中です。",
422- "環境データを他のプレイヤーへ転送中です。",
411+ "プレイヤーへ地図を転送中です。",
412+ "プレイヤーへ地図を転送中です。",
413+ "サーバーから地図を転送しています。",
414+ "サーバーから地図の転送をお待ちください。",
415+ "環境データを他のプレイヤーへ転送中です。",
416+ "環境データを他のプレイヤーへ転送中です。",
423417 "環境データをサーバーから転送しています。",
424- "読み込み中…"
425- "ルーターのポートを開いています…",
426- "ルーターのポートを閉じています…",
427- "アップデートを確認中です…"
418+ "読み込み中…。"
419+ "ルーターのポートを開いています…。",
420+ "ルーターのポートを閉じています…。",
421+ "アップデートを確認中です…。"
428422 };
429423
430424 BUILD_STRINGSET(128, sStringSetNumber128);
@@ -451,20 +445,20 @@
451445 #include "network_dialogs.h" // for stringset ID's
452446
453447 static const char* sDifficultyLevelsStrings[] = {
454- "ちびっ子",
455- "簡単",
456- "普通",
457- "難しい",
448+ "ちびっ子",
449+ "簡単",
450+ "普通",
451+ "難しい",
458452 "虐殺"
459453 };
460454
461455 static const char* sNetworkGameTypesStrings[] = {
462- "個人対戦",
463- "チームプレイ",
464- "旗取り",
465- "陣地取り",
466- "鬼ごっこ",
467- "ラグビー",
456+ "個人対戦",
457+ "チームプレイ",
458+ "旗取り",
459+ "陣地取り",
460+ "鬼ごっこ",
461+ "ラグビー",
468462 "タグ",
469463 "ネットスクリプト"
470464 };
@@ -471,13 +465,13 @@
471465
472466 static const char* sEndConditionTypeStrings[] = {
473467 // "No Limit (Alt+Q to quit)",
474- "無制限",
468+ "無制限",
475469 "時間制限",
476470 "スコア上限"
477471 };
478472
479473 static const char* sSingleOrNetworkStrings[] = {
480- "ソ\ロでゲーム",
474+ "ソ\ロでゲーム",
481475 "ネットワークでゲーム"
482476 };
483477
--- marathon/trunk/Source_Files/Misc/interface.cpp (revision 509)
+++ marathon/trunk/Source_Files/Misc/interface.cpp (revision 510)
@@ -1,3131 +1,3131 @@
1-/*
2- INTERFACE.C
3-
4- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5- and the "Aleph One" developers.
6-
7- This program is free software; you can redistribute it and/or modify
8- it under the terms of the GNU General Public License as published by
9- the Free Software Foundation; either version 3 of the License, or
10- (at your option) any later version.
11-
12- This program is distributed in the hope that it will be useful,
13- but WITHOUT ANY WARRANTY; without even the implied warranty of
14- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15- GNU General Public License for more details.
16-
17- This license is contained in the file "COPYING",
18- which is included with this source code; it is available online at
19- http://www.gnu.org/licenses/gpl.html
20-
21- Thursday, December 30, 1993 6:56:22 PM
22- Mac specific code.....
23-
24- Friday, July 8, 1994 2:32:44 PM (alain)
25- All old code in here is obsolete. This now has interface for the top-level
26- interface (Begin Game, etcノ)
27- Saturday, September 10, 1994 12:45:48 AM (alain)
28- the interface gutted again. just the stuff that handles the menu though, the rest stayed
29- the same.
30- Thursday, June 8, 1995 2:56:16 PM (ryan)
31- Pillaged, raped, & burned. (in that order)
32-
33-Jan 30, 2000 (Loren Petrich):
34- Added some typecasts
35- Removed some "static" declarations that conflict with "extern"
36- Surrounded choose_saved_game_to_load with "extern "C""
37-
38-Feb. 4, 2000 (Loren Petrich):
39- Changed halt() to assert(false) for better debugging
40-
41-Feb. 9, 2000 (Loren Petrich):
42- Changed NUMBER_OF_INTRO_SCREENS to 3
43- Changed NUMBER_OF_CREDIT_SCREENS to Hamish Sinclair's favorite number
44-
45- Fixed multiple-clicks-necessary problem for too few screens.
46- Was in next_game_state(); set game_state.phase (countdown value) to zero.
47-
48-Feb 19, 2000 (Loren Petrich):
49- Set the single-player color to the player color set in the preferences,
50- for the benefit of chase-cam users.
51-
52-Mar 5, 2000 (Loren Petrich):
53- Added reset_screen() when starting a game, so that extravision
54- will not be persistent.
55-
56-May 13, 2000 (Loren Petrich):
57- Added Rhys Hill's fix for problems with quitting OpenGL
58-
59-Aug 12, 2000 (Loren Petrich):
60- Using object-oriented file handler
61-
62-Aug 24, 2000 (Loren Petrich):
63- Added source selector to calculate_picture_clut(), in order to better deal with
64- object-oriented file handlers
65-
66-Nov 25, 2000 (Loren Petrich):
67- Added support for movies that start at any level, including at the end of a game.
68- Also added end-screen control.
69-
70-Jan 31, 2001 (Loren Petrich):
71- In pause_game(), will stop the liquid faders that are active
72-
73-Jan 25, 2002 (Br'fin (Jeremy Parsons)):
74- Disabled network and network microphone calls under Carbon
75-
76-Feb 27, 2002 (Br'fin (Jeremy Parsons)):
77- Renabled network calls, but not microphone calls under Carbon
78-
79-May 16, 2002 (Woody Zenfell):
80- Enforcing standard player behavior with regard to films and netplay
81-
82-Jun 5, 2002 (Loren Petrich):
83- Added do-nothing "case _revert_game:" in portable_process_screen_click()
84- at the request of Michael Adams.
85-
86-Feb 1, 2003 (Woody Zenfell):
87- Reenabling network microphone support on all platforms, trying to share code
88- and present consistent interfaces to the greatest degree practical.
89-
90-Feb 8-12, 2003 (Woody Zenfell):
91- Introducing support for generalized game startup (will enable resumption of saved-games
92- as netgames, among other things).
93-
94-Feb 13, 2003 (Woody Zenfell):
95- We can now resume games as network games.
96-*/
97-
98-// NEED VISIBLE FEEDBACK WHEN APPLETALK IS NOT AVAILABLE!!!
99-
100-/* ZZZ: more on enforcing standard behavior...
101- + Standard behavior forced when playing a network game.
102- + Standard behavior forced when replaying a film.
103- + Custom behavior allowed when starting or restoring a single-player game.
104- + No film recorded in single-player if custom behavior != standard behavior.
105-
106- Once films and netplay properly record each player's behavior prefs,
107- and the relevant code uses per-player settings, this won't be necessary.
108- Try a mass-search for "player_behavior" to find the areas affected.
109-*/
110-
111-#include "cseries.h" // sorry ryan, nov. 4
112-#include <string.h>
113-#include <stdlib.h>
114-#include <limits.h>
115-#include <algorithm>
116-#include <sstream>
117-
118-#ifdef PERFORMANCE
119-#include <perf.h>
120-
121-extern TP2PerfGlobals perf_globals;
122-#endif
123-
124-#include "map.h"
125-#include "shell.h"
126-#include "interface.h"
127-#include "player.h"
128-#include "network.h"
129-#include "screen_drawing.h"
130-#include "SoundManager.h"
131-#include "fades.h"
132-#include "game_window.h"
133-#include "game_errors.h"
134-#include "Mixer.h"
135-#include "Music.h"
136-#include "images.h"
137-#include "screen.h"
138-#include "network.h"
139-#include "vbl.h"
140-#include "shell.h"
141-#include "preferences.h"
142-#include "FileHandler.h"
143-#include "lua_script.h" // PostIdle
144-#include "interface_menus.h"
145-#include "XML_LevelScript.h"
146-#include "Music.h"
147-
148-#ifdef HAVE_SMPEG
149-#include <smpeg/smpeg.h>
150-#endif
151-
152-#include "sdl_dialogs.h"
153-#include "sdl_widgets.h"
154-#include "network_dialog_widgets_sdl.h"
155-
156-/* Change this when marathon changes & replays are no longer valid */
157-enum recording_version {
158- RECORDING_VERSION_UNKNOWN = 0,
159- RECORDING_VERSION_MARATHON = 1,
160- RECORDING_VERSION_MARATHON_2 = 2,
161- RECORDING_VERSION_MARATHON_INFINITY = 3,
162- RECORDING_VERSION_ALEPH_ONE_EARLY = 4,
163- RECORDING_VERSION_ALEPH_ONE_PRE_NET = 5,
164- RECORDING_VERSION_ALEPH_ONE_PRE_PIN = 6,
165- RECORDING_VERSION_ALEPH_ONE_1_0 = 7
166-};
167-const short default_recording_version = RECORDING_VERSION_ALEPH_ONE_1_0;
168-const short max_handled_recording= RECORDING_VERSION_ALEPH_ONE_1_0;
169-
170-#include "screen_definitions.h"
171-#include "interface_menus.h"
172-
173-// LP addition: getting OpenGL rendering stuff
174-#include "render.h"
175-#include "OGL_Render.h"
176-#include "OGL_Blitter.h"
177-#include "alephversion.h"
178-
179-// To tell it to stop playing,
180-// and also to run the end-game script
181-#include "XML_LevelScript.h"
182-
183-// Network microphone/speaker
184-#include "network_sound.h"
185-#include "network_distribution_types.h"
186-
187-// ZZZ: should the function that uses these (join_networked_resume_game()) go elsewhere?
188-#include "wad.h"
189-#include "game_wad.h"
190-
191-#include "motion_sensor.h" // for reset_motion_sensor()
192-
193-#include "lua_hud_script.h"
194-
195-using alephone::Screen;
196-
197-#ifdef env68k
198- #pragma segment shell
199-#endif
200-
201-/* ------------- enums */
202-
203-/* ------------- constants */
204-#define DISPLAY_PICT_RESOURCE_TYPE 'PICT'
205-#define CLOSE_WITHOUT_WARNING_DELAY (5*TICKS_PER_SECOND)
206-
207-#define NUMBER_OF_INTRO_SCREENS (3)
208-#define INTRO_SCREEN_DURATION (215 * MACHINE_TICKS_PER_SECOND / TICKS_PER_SECOND) // fudge to align with sound
209-
210-#ifdef DEMO
211-#define INTRO_SCREEN_TO_START_SONG_ON (1)
212-#else
213-#define INTRO_SCREEN_TO_START_SONG_ON (0)
214-#endif
215-
216-#define INTRO_SCREEN_BETWEEN_DEMO_BASE (INTRO_SCREEN_BASE+1) /* +1 to get past the powercomputing */
217-#define NUMBER_OF_INTRO_SCREENS_BETWEEN_DEMOS (1)
218-#define DEMO_INTRO_SCREEN_DURATION (10 * MACHINE_TICKS_PER_SECOND)
219-
220-#define TICKS_UNTIL_DEMO_STARTS (30 * MACHINE_TICKS_PER_SECOND)
221-
222-#define NUMBER_OF_PROLOGUE_SCREENS 0
223-#define PROLOGUE_DURATION (10 * MACHINE_TICKS_PER_SECOND)
224-
225-#define NUMBER_OF_EPILOGUE_SCREENS 1
226-#define EPILOGUE_DURATION (INDEFINATE_TIME_DELAY)
227-
228-#define NUMBER_OF_CREDIT_SCREENS 7
229-#define CREDIT_SCREEN_DURATION (15 * 60 * MACHINE_TICKS_PER_SECOND)
230-
231-#define NUMBER_OF_CHAPTER_HEADINGS 0
232-#define CHAPTER_HEADING_DURATION (7*MACHINE_TICKS_PER_SECOND)
233-
234-// For exiting the Marathon app
235-// #if defined(DEBUG) || !defined(DEMO)
236-#define NUMBER_OF_FINAL_SCREENS 0
237-// #else
238-// #define NUMBER_OF_FINAL_SCREENS 1
239-// #endif
240-#define FINAL_SCREEN_DURATION (INDEFINATE_TIME_DELAY)
241-
242-/* For teleportation, end movie, etc. */
243-#define EPILOGUE_LEVEL_NUMBER 256
244-
245-/* ------------- structures */
246-struct game_state {
247- short state;
248- short flags;
249- short user;
250- int32 phase;
251- int32 last_ticks_on_idle;
252- short current_screen;
253- bool suppress_background_tasks;
254- bool current_netgame_allows_microphone;
255- short main_menu_display_count; // how many times have we shown the main menu?
256-};
257-
258-struct screen_data {
259- short screen_base;
260- short screen_count;
261- int32 duration;
262-};
263-
264-/* -------------- constants */
265-struct screen_data display_screens[]= {
266- { INTRO_SCREEN_BASE, NUMBER_OF_INTRO_SCREENS, INTRO_SCREEN_DURATION },
267- { MAIN_MENU_BASE, 1, 0 },
268- { CHAPTER_SCREEN_BASE, NUMBER_OF_CHAPTER_HEADINGS, CHAPTER_HEADING_DURATION },
269- { PROLOGUE_SCREEN_BASE, NUMBER_OF_PROLOGUE_SCREENS, PROLOGUE_DURATION },
270- { EPILOGUE_SCREEN_BASE, NUMBER_OF_EPILOGUE_SCREENS, EPILOGUE_DURATION },
271- { CREDIT_SCREEN_BASE, NUMBER_OF_CREDIT_SCREENS, CREDIT_SCREEN_DURATION},
272- { INTRO_SCREEN_BETWEEN_DEMO_BASE, NUMBER_OF_INTRO_SCREENS_BETWEEN_DEMOS, DEMO_INTRO_SCREEN_DURATION },
273- { FINAL_SCREEN_BASE, NUMBER_OF_FINAL_SCREENS, FINAL_SCREEN_DURATION }
274-};
275-
276-#if 0
277-struct chapter_screen_sound_data {
278- short level;
279- short sound_code;
280-};
281-
282-struct chapter_screen_sound_data chapter_screen_sounds[]=
283-{
284- {0, _snd_chapter1},
285- {1, _snd_chapter2},
286- {2, _snd_chapter3}
287-};
288-#define NUMBER_OF_CHAPTER_SCREEN_SOUNDS (sizeof(chapter_screen_sounds)/sizeof(chapter_screen_sounds[1]))
289-#endif
290-
291-/* -------------- local globals */
292-static struct game_state game_state;
293-static FileSpecifier DraggedReplayFile;
294-static bool interface_fade_in_progress= false;
295-static short interface_fade_type;
296-static short current_picture_clut_depth;
297-static struct color_table *animated_color_table= NULL;
298-static struct color_table *current_picture_clut= NULL;
299-
300-/* -------------- externs */
301-extern short interface_bit_depth;
302-extern short bit_depth;
303-extern bool insecure_lua;
304-
305-/* ----------- prototypes/PREPROCESS_MAP_MAC.C */
306-extern bool load_game_from_file(FileSpecifier& File);
307-extern bool choose_saved_game_to_load(FileSpecifier& File);
308-
309-/* ---------------------- prototypes */
310-static void display_credits(void);
311-static void draw_button(short index, bool pressed);
312-static void draw_powered_by_aleph_one();
313-static void handle_replay(bool last_replay);
314-static bool begin_game(short user, bool cheat);
315-static void start_game(short user, bool changing_level);
316-// LP: "static" removed
317-void handle_load_game(void);
318-static void handle_save_film(void);
319-static void finish_game(bool return_to_main_menu);
320-static void clean_up_after_failed_game(bool inNetgame, bool inRecording, bool inFullCleanup);
321-static void handle_network_game(bool gatherer);
322-static void next_game_screen(void);
323-static void handle_interface_menu_screen_click(short x, short y, bool cheatkeys_down);
324-
325-static void display_introduction(void);
326-static void display_loading_map_error(void);
327-static void display_quit_screens(void);
328-static void display_screen(short base_pict_id);
329-static void display_introduction_screen_for_demo(void);
330-static void display_epilogue(void);
331-static void display_about_dialog();
332-
333-static void force_system_colors(void);
334-static bool point_in_rectangle(short x, short y, screen_rectangle *rect);
335-
336-static void start_interface_fade(short type, struct color_table *original_color_table);
337-static void update_interface_fades(void);
338-static void interface_fade_out(short pict_resource_number, bool fade_music);
339-static bool can_interface_fade_out(void);
340-static void transfer_to_new_level(short level_number);
341-static void try_and_display_chapter_screen(short level, bool interface_table_is_valid, bool text_block);
342-
343-static screen_data *get_screen_data(
344- short index);
345-
346-/* ---------------------- code begins */
347-
348-screen_data *get_screen_data(
349- short index)
350-{
351- assert(index>=0 && index<NUMBER_OF_SCREENS);
352- return display_screens+index;
353-}
354-
355-void initialize_game_state(
356- void)
357-{
358- game_state.state= _display_intro_screens;
359- game_state.user= _single_player;
360- game_state.flags= 0;
361- game_state.current_screen= 0;
362- game_state.suppress_background_tasks= true;
363- game_state.main_menu_display_count= 0;
364-
365- toggle_menus(false);
366-
367- if(insecure_lua) {
368- alert_user(expand_app_variables("Insecure Lua has been manually enabled. Malicious Lua scripts can use Insecure Lua to take over your computer. Unless you specifically trust every single Lua script that will be running, you should quit $appName$ IMMEDIATELY.").c_str());
369- }
370-
371- display_introduction();
372-}
373-
374-void force_game_state_change(
375- void)
376-{
377- game_state.phase= 0;
378-}
379-
380-bool player_controlling_game(
381- void)
382-{
383- bool player_in_control= false;
384-
385- assert(game_state.state==_game_in_progress || game_state.state==_switch_demo);
386-
387- if(game_state.user==_single_player || game_state.user==_network_player)
388- {
389- player_in_control= true;
390- }
391-
392- return player_in_control;
393-}
394-
395-void toggle_suppression_of_background_tasks(
396- void)
397-{
398- game_state.suppress_background_tasks= !game_state.suppress_background_tasks;
399-}
400-
401-void set_game_state(
402- short new_state)
403-{
404- short old_state= game_state.state;
405-
406- switch(old_state)
407- {
408- case _game_in_progress:
409- switch(new_state)
410- {
411- case _display_epilogue:
412- game_state.state= _begin_display_of_epilogue;
413- game_state.phase= 0;
414- break;
415-
416- case _close_game:
417- finish_game(true);
418- break;
419-
420- case _quit_game:
421- finish_game(false);
422- display_quit_screens();
423- break;
424-
425- case _switch_demo:
426- /* Because Alain's code calls us at interrupt level 1, */
427- /* we must defer processing of this message until idle */
428- game_state.state= _switch_demo;
429- game_state.phase= 0;
430- break;
431-
432- case _revert_game:
433- /* Because reverting a game in the middle of the update_world loop sounds */
434- /* sketchy, this is not done until idle time.. */
435- game_state.state= new_state;
436- game_state.phase= 0;
437- break;
438-
439- case _change_level:
440- game_state.state= new_state;
441- game_state.phase= 0;
442- break;
443-
444- default:
445- assert(false);
446- break;
447- }
448- break;
449-
450- default:
451- game_state.state= new_state;
452- break;
453- }
454-}
455-
456-short get_game_state(
457- void)
458-{
459- return game_state.state;
460-}
461-
462-bool current_netgame_allows_microphone()
463-{
464- return game_state.current_netgame_allows_microphone;
465-}
466-
467-bool suppress_background_events(
468- void)
469-{
470- return game_state.suppress_background_tasks;
471-}
472-
473-short get_game_controller(
474- void)
475-{
476- return game_state.user;
477-}
478-
479-void set_change_level_destination(
480- short level_number)
481-{
482- assert(game_state.state== _change_level);
483- game_state.current_screen= level_number;
484-}
485-
486-static short get_difficulty_level(void)
487-{
488- return player_preferences->difficulty_level;
489-}
490-
491-
492-// ----- ZZZ start support for generalized game startup -----
493-// (should this be split out (with some other game startup code) to a new file?)
494-
495-// In this scheme, a "start" corresponds to a player available at the moment, who will
496-// participate in the game we're starting up. In general when this code talks about a
497-// 'player', it is referring to an already-existing player in the game world (which should
498-// already be restored or initialized fairly well before these routines are used).
499-// Generalized game startup will match starts to existing players, set leftover players
500-// as "zombies" so they exist but just stand there, and create new players to correspond
501-// with any remaining starts. As such it can handle both resume-game (some players already
502-// exist) and new-game (dynamic_world->player_count == 0) operations.
503-
504-static void construct_single_player_start(player_start_data* outStartArray, short* outStartCount)
505-{
506- if(outStartCount != NULL)
507- {
508- *outStartCount = 1;
509- }
510-
511- outStartArray[0].team = player_preferences->color;
512- outStartArray[0].color = player_preferences->color;
513- outStartArray[0].identifier = 0;
514- memcpy(outStartArray[0].name, &(player_preferences->name[1]), player_preferences->name[0]);
515- outStartArray[0].name[player_preferences->name[0]] = '\0';
516-
517- set_player_start_doesnt_auto_recenter_status(&outStartArray[0], dont_auto_recenter());
518- set_player_start_doesnt_auto_switch_weapons_status(&outStartArray[0], dont_switch_to_new_weapon());
519-}
520-
521-#if !defined(DISABLE_NETWORKING)
522-static void construct_multiplayer_starts(player_start_data* outStartArray, short* outStartCount)
523-{
524- int number_of_players = NetGetNumberOfPlayers();
525-
526- if(outStartCount != NULL)
527- {
528- *outStartCount = number_of_players;
529- }
530-
531- for(int player_index= 0; player_index<number_of_players; ++player_index)
532- {
533- player_info *player_information = (player_info *)NetGetPlayerData(player_index);
534- outStartArray[player_index].team = player_information->team;
535- outStartArray[player_index].color= player_information->color;
536- outStartArray[player_index].identifier = NetGetPlayerIdentifier(player_index);
537-
538- /* Copy and translate from pascal string to cstring */
539- memcpy(outStartArray[player_index].name, &player_information->name[1],
540- player_information->name[0]);
541- outStartArray[player_index].name[player_information->name[0]]= 0;
542- }
543-}
544-#endif // !defined(DISABLE_NETWORKING)
545-
546-// This should be safe to use whether starting or resuming and whether single-player or multiplayer.
547-void match_starts_with_existing_players(player_start_data* ioStartArray, short* ioStartCount)
548-{
549- // This code could be smarter, but it doesn't run very often, doesn't get big data sets, etc.
550- // so I'm not going to worry about it.
551-
552- bool startAssigned[MAXIMUM_NUMBER_OF_PLAYERS];
553- int8 startAssignedToPlayer[MAXIMUM_NUMBER_OF_PLAYERS];
554- for(int i = 0; i < MAXIMUM_NUMBER_OF_PLAYERS; i++)
555- {
556- startAssigned[i] = false;
557- startAssignedToPlayer[i] = NONE;
558- }
559-
560- // First, match starts to players by name.
561- for(int s = 0; s < *ioStartCount; s++)
562- {
563- for(int p = 0; p < dynamic_world->player_count; p++)
564- {
565- if(startAssignedToPlayer[p] == NONE)
566- {
567- if(strcmp(ioStartArray[s].name, get_player_data(p)->name) == 0)
568- {
569- startAssignedToPlayer[p] = s;
570- startAssigned[s] = true;
571- break;
572- }
573- }
574- }
575- }
576-
577- // Match remaining starts to remaining players arbitrarily.
578- for(int s = 0; s < *ioStartCount; s++)
579- {
580- if(!startAssigned[s])
581- {
582- for(int p = 0; p < dynamic_world->player_count; p++)
583- {
584- if(startAssignedToPlayer[p] == NONE)
585- {
586- startAssignedToPlayer[p] = s;
587- startAssigned[s] = true;
588- break;
589- }
590- }
591- }
592- }
593-
594- // Create new starts for any players not covered.
595- int p = 0;
596- while(*ioStartCount < dynamic_world->player_count)
597- {
598- if(startAssignedToPlayer[p] == NONE)
599- {
600- player_data* thePlayer = get_player_data(p);
601- ioStartArray[*ioStartCount].team = thePlayer->team;
602- ioStartArray[*ioStartCount].color = thePlayer->color;
603- ioStartArray[*ioStartCount].identifier = NONE;
604- strcpy(ioStartArray[*ioStartCount].name, thePlayer->name);
605- startAssignedToPlayer[p] = *ioStartCount;
606- startAssigned[*ioStartCount] = true;
607- (*ioStartCount)++;
608- }
609-
610- p++;
611- }
612-
613- // Assign remaining starts to players that don't exist yet
614- p = dynamic_world->player_count;
615- for(int s = 0; s < *ioStartCount; s++)
616- {
617- if(!startAssigned[s])
618- {
619- startAssignedToPlayer[p] = s;
620- startAssigned[s] = true;
621- p++;
622- }
623- }
624-
625- // Reorder starts to match players - this is particularly unclever
626- player_start_data theOriginalStarts[MAXIMUM_NUMBER_OF_PLAYERS];
627- memcpy(theOriginalStarts, ioStartArray, sizeof(theOriginalStarts));
628- for(p = 0; p < *ioStartCount; p++)
629- {
630- ioStartArray[p] = theOriginalStarts[startAssignedToPlayer[p]];
631- }
632-}
633-
634-// This should be safe to use whether starting or resuming, and whether single- or multiplayer.
635-static void synchronize_players_with_starts(const player_start_data* inStartArray, short inStartCount)
636-{
637- // s will walk through all the starts
638- int s = 0;
639-
640- // First we process existing players
641- for( ; s < dynamic_world->player_count; s++)
642- {
643- player_data* thePlayer = get_player_data(s);
644-
645- if(inStartArray[s].identifier == NONE)
646- {
647- // No start (live player) to go with this player (stored player)
648- SET_PLAYER_ZOMBIE_STATUS(thePlayer, true);
649- }
650- else
651- {
652- // Update player's appearance to match the start
653- thePlayer->team = inStartArray[s].team;
654- thePlayer->color = inStartArray[s].color;
655- thePlayer->identifier = player_identifier_value(inStartArray[s].identifier);
656- strcpy(thePlayer->name, inStartArray[s].name);
657-
658- SET_PLAYER_DOESNT_AUTO_RECENTER_STATUS(thePlayer,
659- player_identifier_doesnt_auto_recenter(inStartArray[s].identifier));
660- SET_PLAYER_DOESNT_AUTO_SWITCH_WEAPONS_STATUS(thePlayer,
661- player_identifier_doesnt_auto_switch_weapons(inStartArray[s].identifier));
662-
663- // Make sure if player was saved as zombie, they're not now.
664- SET_PLAYER_ZOMBIE_STATUS(thePlayer, false);
665- }
666- }
667-
668- // If there are any starts left, we need new players for them
669- for( ; s < inStartCount; s++)
670- {
671- int theIndex = new_player(inStartArray[s].team, inStartArray[s].color, inStartArray[s].identifier);
672- assert(theIndex == s);
673- player_data* thePlayer = get_player_data(theIndex);
674- strcpy(thePlayer->name, inStartArray[s].name);
675- }
676-}
677-
678-static short find_start_for_identifier(const player_start_data* inStartArray, short inStartCount, short _inIdentifier)
679-{
680- short inIdentifier= player_identifier_value(_inIdentifier);
681- short s;
682- for(s = 0; s < inStartCount; s++)
683- {
684- if(player_identifier_value(inStartArray[s].identifier) == inIdentifier)
685- {
686- break;
687- }
688- }
689-
690- return (s == inStartCount) ? NONE : s;
691-}
692-
693-// The single-player machine, gatherer, and joiners all will use this routine. It should take most of its
694-// cues from the "extras" that load_game_from_file() does.
695-static bool make_restored_game_relevant(bool inNetgame, const player_start_data* inStartArray, short inStartCount)
696-{
697- game_is_networked = inNetgame;
698-
699- // set_random_seed() needs to happen before synchronize_players_with_starts()
700- // since the latter calls new_player() which almost certainly uses global_random().
701- // Note we always take the random seed directly from the dynamic_world, no need to screw around
702- // with copying it from game_information or the like.
703- set_random_seed(dynamic_world->random_seed);
704-
705- synchronize_players_with_starts(inStartArray, inStartCount);
706-
707- short theLocalPlayerIndex;
708-
709-#if !defined(DISABLE_NETWORKING)
710- // Much of the code in this if()...else is very similar to code in begin_game(), should probably try to share.
711- if(inNetgame)
712- {
713- game_info *network_game_info= (game_info *)NetGetGameData();
714-
715- dynamic_world->game_information.game_time_remaining= network_game_info->time_limit;
716- dynamic_world->game_information.kill_limit= network_game_info->kill_limit;
717- dynamic_world->game_information.game_type= network_game_info->net_game_type;
718- dynamic_world->game_information.game_options= network_game_info->game_options;
719- dynamic_world->game_information.initial_random_seed= network_game_info->initial_random_seed;
720- dynamic_world->game_information.difficulty_level= network_game_info->difficulty_level;
721- dynamic_world->game_information.cheat_flags= network_game_info->cheat_flags;
722-
723- if (network_game_info->allow_mic)
724- {
725- install_network_microphone();
726- game_state.current_netgame_allows_microphone= true;
727- } else {
728- game_state.current_netgame_allows_microphone= false;
729- }
730-
731- // ZZZ: until players specify their behavior modifiers over the network,
732- // to avoid out-of-sync we must force them all the same.
733- standardize_player_behavior_modifiers();
734-
735- theLocalPlayerIndex = NetGetLocalPlayerIndex();
736- }
737- else
738-#endif // !defined(DISABLE_NETWORKING)
739- {
740- dynamic_world->game_information.difficulty_level= get_difficulty_level();
741- restore_custom_player_behavior_modifiers();
742- theLocalPlayerIndex = find_start_for_identifier(inStartArray, inStartCount, 0);
743- }
744-
745- assert(theLocalPlayerIndex != NONE);
746- set_local_player_index(theLocalPlayerIndex);
747- set_current_player_index(theLocalPlayerIndex);
748-
749- bool success = entering_map(true /*restoring game*/);
750-
751- reset_motion_sensor(theLocalPlayerIndex);
752-
753- if(!success) clean_up_after_failed_game(inNetgame, false /*recording*/, true /*full cleanup*/);
754-
755- return success;
756-}
757-
758-// ZZZ end generalized game startup support -----
759-
760-#if !defined(DISABLE_NETWORKING)
761-// ZZZ: this will get called (eventually) shortly after NetUpdateJoinState() returns netStartingResumeGame
762-bool join_networked_resume_game()
763-{
764- bool success = true;
765-
766- // Get the saved-game data
767- byte* theSavedGameFlatData = NetReceiveGameData(false /* do_physics */);
768- if(theSavedGameFlatData == NULL)
769- {
770- success = false;
771- }
772-
773- if(success)
774- {
775- // Use the saved-game data
776- wad_header theWadHeader;
777- wad_data* theWad;
778-
779- theWad = inflate_flat_data(theSavedGameFlatData, &theWadHeader);
780- if(theWad == NULL)
781- {
782- success = false;
783- free(theSavedGameFlatData);
784- }
785-
786- if(success)
787- {
788- success = process_map_wad(theWad, true /* resuming */, theWadHeader.data_version);
789- free_wad(theWad); /* Note that the flat data points into the wad. */
790- // ZZZ: maybe this is what the Bungie comment meant, but apparently
791- // free_wad() somehow (voodoo) frees theSavedGameFlatData as well.
792- }
793-
794- if(success)
795- {
796- Crosshairs_SetActive(player_preferences->crosshairs_active);
797- LoadHUDLua();
798- RunLuaHUDScript();
799-
800- // try to locate the Map file for the saved-game, so that (1) we have a crack
801- // at continuing the game if the original gatherer disappears, and (2) we can
802- // save the game on our own machine and continue it properly (as part of a bigger scenario) later.
803- uint32 theParentChecksum = theWadHeader.parent_checksum;
804- if(use_map_file(theParentChecksum))
805- {
806- // LP: getting the level scripting off of the map file
807- // Being careful to carry over errors so that Pfhortran errors can be ignored
808- short SavedType, SavedError = get_game_error(&SavedType);
809- RunLevelScript(dynamic_world->current_level_number);
810- RunScriptChunks();
811- set_game_error(SavedType,SavedError);
812- }
813- else
814- {
815- /* Tell the user theyユre screwed when they try to leave this level. */
816- // ZZZ: should really issue a different warning since the ramifications are different
817- alert_user(infoError, strERRORS, cantFindMap, 0);
818-
819- // LP addition: makes the game look normal
820- hide_cursor();
821-
822- /* Set to the default map. */
823- set_to_default_map();
824-
825- ResetLevelScript();
826- RunScriptChunks();
827- }
828-
829- // set the revert-game info to defaults (for full-auto saving on the local machine)
830- set_saved_game_name_to_default();
831-
832- player_start_data theStarts[MAXIMUM_NUMBER_OF_PLAYERS];
833- short theStartCount;
834- construct_multiplayer_starts(theStarts, &theStartCount);
835-
836- RunLuaScript();
837- success = make_restored_game_relevant(true /* multiplayer */, theStarts, theStartCount);
838- }
839- }
840-
841- if(success)
842- {
843- Music::instance()->PreloadLevelMusic();
844- start_game(_network_player, false /*changing level?*/);
845- }
846-
847- return success;
848-}
849-#endif // !defined(DISABLE_NETWORKING)
850-
851-extern bool load_and_start_game(FileSpecifier& File);
852-
853-// ZZZ: changes to use generalized game startup support
854-// This will be used only on the machine that picked "Continue Saved Game".
855-bool load_and_start_game(FileSpecifier& File)
856-{
857- bool success;
858-
859- hide_cursor();
860- if (can_interface_fade_out())
861- {
862- interface_fade_out(MAIN_MENU_BASE, true);
863- }
864-
865- Crosshairs_SetActive(player_preferences->crosshairs_active);
866- LoadHUDLua();
867- RunLuaHUDScript();
868-
869- success= load_game_from_file(File);
870-
871- if (!success)
872- {
873- /* Reset the system colors, since the screen clut is all black.. */
874- force_system_colors();
875- show_cursor(); // JTP: Was hidden by force system colors
876- display_loading_map_error();
877- }
878-
879- bool userWantsMultiplayer;
880- size_t theResult = UNONE;
881-
882- if (success)
883- {
884-#ifdef __MACOS__
885- theResult = 0;
886-#else
887- theResult = should_restore_game_networked();
888-#endif
889- }
890-
891- if (theResult == UNONE)
892- {
893- // cancelled
894- success = false;
895- }
896- else
897- {
898- userWantsMultiplayer = (theResult != 0);
899- }
900-
901- if (success)
902- {
903-#if !defined(DISABLE_NETWORKING)
904- if (userWantsMultiplayer)
905- {
906- set_game_state(_displaying_network_game_dialogs);
907- success = network_gather(true /*resuming*/);
908- }
909-#endif // !defined(DISABLE_NETWORKING)
910-
911- if (success)
912- {
913- player_start_data theStarts[MAXIMUM_NUMBER_OF_PLAYERS];
914- short theNumberOfStarts;
915-
916-#if !defined(DISABLE_NETWORKING)
917- if (userWantsMultiplayer)
918- {
919- construct_multiplayer_starts(theStarts, &theNumberOfStarts);
920- }
921- else
922-#endif // !defined(DISABLE_NETWORKING)
923- {
924- construct_single_player_start(theStarts, &theNumberOfStarts);
925- }
926-
927- match_starts_with_existing_players(theStarts, &theNumberOfStarts);
928-
929-#if !defined(DISABLE_NETWORKING)
930- if (userWantsMultiplayer)
931- {
932- NetSetupTopologyFromStarts(theStarts, theNumberOfStarts);
933- success = NetStart();
934- if (success)
935- {
936- byte* theSavedGameFlatData = (byte*)get_flat_data(File, false /* union wad? */, 0 /* level # */);
937- if (theSavedGameFlatData == NULL)
938- {
939- success = false;
940- }
941-
942- if (success)
943- {
944- int32 theSavedGameFlatDataLength = get_flat_data_length(theSavedGameFlatData);
945- OSErr theError = NetDistributeGameDataToAllPlayers(theSavedGameFlatData, theSavedGameFlatDataLength, false /* do_physics? */);
946- if (theError != noErr)
947- {
948- success = false;
949- }
950- free(theSavedGameFlatData);
951- }
952- }
953- }
954-#endif // !defined(DISABLE_NETWORKING)
955-
956- if (success)
957- {
958- RunLuaScript();
959- success = make_restored_game_relevant(userWantsMultiplayer, theStarts, theNumberOfStarts);
960- if (success)
961- {
962- Music::instance()->PreloadLevelMusic();
963- start_game(userWantsMultiplayer ? _network_player : _single_player, false);
964- }
965- }
966- }
967- }
968-
969- if (!success) {
970- /* We failed. Balance the cursor */
971- /* Should this also force the system colors or something? */
972- show_cursor();
973- }
974-
975- return success;
976-}
977-
978-extern bool handle_open_replay(FileSpecifier& File);
979-
980-bool handle_open_replay(FileSpecifier& File)
981-{
982- DraggedReplayFile = File;
983-
984- bool success;
985-
986- force_system_colors();
987- success= begin_game(_replay_from_file, false);
988- if(!success) display_main_menu();
989- return success;
990-}
991-
992-// Called from within update_world..
993-bool check_level_change(
994- void)
995-{
996- bool level_changed= false;
997-
998- if(game_state.state==_change_level)
999- {
1000- transfer_to_new_level(game_state.current_screen);
1001- level_changed= true;
1002- }
1003-
1004- return level_changed;
1005-}
1006-
1007-void pause_game(
1008- void)
1009-{
1010- stop_fade();
1011- if (!OGL_IsActive() || !(TEST_FLAG(Get_OGL_ConfigureData().Flags,OGL_Flag_Fader)))
1012- set_fade_effect(NONE);
1013- darken_world_window();
1014- set_keyboard_controller_status(false);
1015-#ifdef SDL
1016- show_cursor();
1017-#endif
1018-}
1019-
1020-void resume_game(
1021- void)
1022-{
1023-#ifdef SDL
1024- hide_cursor();
1025-#endif
1026- if (!OGL_IsActive() || !(TEST_FLAG(Get_OGL_ConfigureData().Flags,OGL_Flag_Fader)))
1027- SetFadeEffectDelay(TICKS_PER_SECOND/2);
1028- validate_world_window();
1029- set_keyboard_controller_status(true);
1030-}
1031-
1032-void draw_menu_button_for_command(
1033- short index)
1034-{
1035- short rectangle_index= index-1+_new_game_button_rect;
1036-
1037- assert(get_game_state()==_display_main_menu);
1038-
1039- /* Draw it initially depressed.. */
1040- draw_button(rectangle_index, true);
1041-#ifdef SDL
1042- SDL_Delay(1000 / 12);
1043-#else
1044- uint32 initial_tick= machine_tick_count();
1045- while(machine_tick_count()-initial_tick<5) /* 1/12 second */
1046- ;
1047-#endif
1048- draw_button(rectangle_index, false);
1049-}
1050-
1051-void update_interface_display(
1052- void)
1053-{
1054- struct screen_data *data;
1055-
1056- data= get_screen_data(game_state.state);
1057-
1058- /* Use this to avoid the fade.. */
1059- draw_full_screen_pict_resource_from_images(data->screen_base+game_state.current_screen);
1060-
1061- if (game_state.state == _display_main_menu)
1062- {
1063- draw_powered_by_aleph_one();
1064- }
1065-}
1066-
1067-bool idle_game_state(uint32 time)
1068-{
1069- int machine_ticks_elapsed = time - game_state.last_ticks_on_idle;
1070-
1071- if(machine_ticks_elapsed || game_state.phase==0)
1072- {
1073- if(game_state.phase != INDEFINATE_TIME_DELAY)
1074- {
1075- game_state.phase-= machine_ticks_elapsed;
1076- }
1077-
1078- /* Note that we still go through this if we have an indefinate phase.. */
1079- if(game_state.phase<=0)
1080- {
1081- switch(get_game_state())
1082- {
1083- case _display_quit_screens:
1084- case _display_intro_screens:
1085- case _display_prologue:
1086- case _display_epilogue:
1087- case _display_credits:
1088- next_game_screen();
1089- break;
1090-
1091- case _display_intro_screens_for_demo:
1092- case _display_main_menu:
1093- /* Start the demo.. */
1094- if(!begin_game(_demo, false))
1095- {
1096- /* This means that there was not a valid demo to play */
1097- game_state.phase= TICKS_UNTIL_DEMO_STARTS;
1098- }
1099- break;
1100-
1101- case _close_game:
1102- display_main_menu();
1103- break;
1104-
1105- case _switch_demo:
1106- /* This is deferred to the idle task because it */
1107- /* occurs at interrupt time.. */
1108- switch(game_state.user)
1109- {
1110- case _replay:
1111- finish_game(true);
1112- break;
1113-
1114- case _demo:
1115- finish_game(false);
1116- display_introduction_screen_for_demo();
1117- break;
1118-
1119- default:
1120- assert(false);
1121- break;
1122- }
1123- break;
1124-
1125- case _display_chapter_heading:
1126- dprintf("Chapter heading...");
1127- break;
1128-
1129- case _quit_game:
1130- /* About to quit, but can still hit this through order of ops.. */
1131- break;
1132-
1133- case _revert_game:
1134- /* Reverting while in the update loop sounds sketchy.. */
1135- if(revert_game())
1136- {
1137- game_state.state= _game_in_progress;
1138- game_state.phase = 15 * MACHINE_TICKS_PER_SECOND;
1139- game_state.last_ticks_on_idle= machine_tick_count();
1140- update_interface(NONE);
1141- } else {
1142- /* Give them the error... */
1143- display_loading_map_error();
1144-
1145- /* And finish their current game.. */
1146- finish_game(true);
1147- }
1148- break;
1149-
1150- case _begin_display_of_epilogue:
1151- finish_game(false);
1152- display_epilogue();
1153- break;
1154-
1155- case _game_in_progress:
1156- game_state.phase = 15 * MACHINE_TICKS_PER_SECOND;
1157- //game_state.last_ticks_on_idle= machine_tick_count();
1158- break;
1159-
1160- case _change_level:
1161- case _displaying_network_game_dialogs:
1162- break;
1163-
1164- default:
1165- assert(false);
1166- break;
1167- }
1168- }
1169- game_state.last_ticks_on_idle= machine_tick_count();
1170- }
1171-
1172- /* if weユre not paused and thereユs something to draw (i.e., anything different from
1173- last time), render a frame */
1174- if(game_state.state==_game_in_progress)
1175- {
1176- // ZZZ change: update_world() whether or not get_keyboard_controller_status() is true
1177- // This way we won't fill up queues and stall netgames if one player switches out for a bit.
1178- std::pair<bool, int16> theUpdateResult= update_world();
1179- short ticks_elapsed= theUpdateResult.second;
1180-
1181- if (get_keyboard_controller_status())
1182- {
1183- // ZZZ: I don't know for sure that render_screen works best with the number of _real_
1184- // ticks elapsed rather than the number of (potentially predictive) ticks elapsed.
1185- // This is a guess.
1186- if (theUpdateResult.first)
1187- render_screen(ticks_elapsed);
1188- }
1189-
1190- return theUpdateResult.first;
1191- } else {
1192- /* Update the fade ins, etc.. */
1193- update_interface_fades();
1194- return false;
1195- }
1196-}
1197-
1198-extern SDL_Surface *draw_surface; // from screen_drawing.cpp
1199-//void draw_intro_screen(void); // from screen.cpp
1200-
1201-static SDL_Surface *powered_by_alephone_surface = 0;
1202-#include "powered_by_alephone.h"
1203-
1204-extern void set_about_alephone_rect(int width, int height);
1205-
1206-static void draw_powered_by_aleph_one()
1207-{
1208- if (!powered_by_alephone_surface)
1209- {
1210- SDL_RWops *rw = SDL_RWFromConstMem(powered_by_alephone_bmp, sizeof(powered_by_alephone_bmp));
1211- powered_by_alephone_surface = SDL_LoadBMP_RW(rw, 0);
1212- SDL_FreeRW(rw);
1213-
1214- set_about_alephone_rect(powered_by_alephone_surface->w, powered_by_alephone_surface->h);
1215- }
1216-
1217- SDL_Rect rect;
1218- rect.x = 640 - powered_by_alephone_surface->w;
1219- rect.y = 480 - powered_by_alephone_surface->h;
1220- rect.w = powered_by_alephone_surface->w;
1221- rect.h = powered_by_alephone_surface->h;
1222-
1223- _set_port_to_intro();
1224- SDL_BlitSurface(powered_by_alephone_surface, NULL, draw_surface, &rect);
1225- _restore_port();
1226-
1227- // have to reblit :(
1228- draw_intro_screen();
1229-}
1230-
1231-void display_main_menu(
1232- void)
1233-{
1234- game_state.state= _display_main_menu;
1235- game_state.current_screen= 0;
1236- game_state.phase= TICKS_UNTIL_DEMO_STARTS;
1237- game_state.last_ticks_on_idle= machine_tick_count();
1238- game_state.user= _single_player;
1239- game_state.flags= 0;
1240-
1241- change_screen_mode(_screentype_menu);
1242- display_screen(MAIN_MENU_BASE);
1243-
1244- /* Start up the song! */
1245- if(!Music::instance()->Playing() && game_state.main_menu_display_count==0)
1246- {
1247- Music::instance()->RestartIntroMusic();
1248- }
1249-
1250- draw_powered_by_aleph_one();
1251-
1252- game_state.main_menu_display_count++;
1253-}
1254-
1255-
1256-// Kludge for Carbon/Classic -- when exiting a main-menu dialog box, redisplay
1257-static void ForceRepaintMenuDisplay()
1258-{
1259-#ifdef mac
1260- if (!system_information->has_ten || system_information->machine_is_bluebox)
1261- {
1262- if (get_game_state() == _display_main_menu)
1263- display_screen(MAIN_MENU_BASE);
1264- }
1265-#endif
1266-}
1267-
1268-
1269-void do_menu_item_command(
1270- short menu_id,
1271- short menu_item,
1272- bool cheat)
1273-{
1274- switch(menu_id)
1275- {
1276-
1277- case mGame:
1278- switch(menu_item)
1279- {
1280- case iPause:
1281- switch(game_state.user)
1282- {
1283- case _single_player:
1284- case _replay:
1285- if (get_keyboard_controller_status())
1286- {
1287- pause_game();
1288- }
1289- else
1290- {
1291- resume_game();
1292- }
1293- break;
1294-
1295- case _demo:
1296- finish_game(true);
1297- break;
1298-
1299- case _network_player:
1300- break;
1301-
1302- default:
1303- assert(false);
1304- break;
1305- }
1306- break;
1307-
1308- case iSave:
1309- switch(game_state.user)
1310- {
1311- case _single_player:
1312-#if 0
1313- save_game();
1314- validate_world_window();
1315-#endif
1316- break;
1317-
1318- case _demo:
1319- case _replay:
1320- finish_game(true);
1321- break;
1322-
1323- case _network_player:
1324- break;
1325-
1326- default:
1327- assert(false);
1328- break;
1329- }
1330- break;
1331-
1332- case iRevert:
1333- /* Not implemented.. */
1334- break;
1335-
1336- case iCloseGame:
1337- case iQuitGame:
1338- {
1339- bool really_wants_to_quit= false;
1340-
1341- switch(game_state.user)
1342- {
1343- case _single_player:
1344- if(PLAYER_IS_DEAD(local_player) ||
1345- dynamic_world->tick_count-local_player->ticks_at_last_successful_save<CLOSE_WITHOUT_WARNING_DELAY)
1346- {
1347- really_wants_to_quit= true;
1348- } else {
1349- pause_game();
1350- show_cursor();
1351- really_wants_to_quit= quit_without_saving();
1352- hide_cursor();
1353- resume_game();
1354- }
1355- break;
1356-
1357- case _demo:
1358- case _replay:
1359- case _network_player:
1360- really_wants_to_quit= true;
1361- break;
1362-
1363- default:
1364- assert(false);
1365- break;
1366- }
1367-
1368- if(really_wants_to_quit)
1369- {
1370- // Rhys Hill fix for crash when quitting OpenGL
1371- if (!OGL_IsActive())
1372- render_screen(0); /* Get rid of hole.. */
1373-/* If you want to quit on command-q while in the game.. */
1374-#if 0
1375- if(menu_item==iQuitGame)
1376- {
1377- set_game_state(_quit_game);
1378- } else
1379-#endif
1380- set_game_state(_close_game);
1381- }
1382- }
1383- break;
1384-
1385- default:
1386- assert(false);
1387- break;
1388- }
1389- break;
1390-
1391- case mInterface:
1392- switch(menu_item)
1393- {
1394- case iNewGame:
1395- begin_game(_single_player, cheat);
1396- ForceRepaintMenuDisplay();
1397- break;
1398- case iPlaySingletonLevel:
1399- begin_game(_single_player,2);
1400- break;
1401-
1402- case iJoinGame:
1403-#ifdef mac
1404- if (system_information->machine_has_network_memory)
1405- {
1406- handle_network_game(false);
1407- }
1408- else
1409- {
1410- alert_user(infoError, strERRORS, notEnoughNetworkMemory, 0);
1411- }
1412-#elif defined(__MACOS__)
1413- break;
1414-#else
1415- handle_network_game(false);
1416-#endif
1417- break;
1418-
1419- case iGatherGame:
1420-#ifdef mac
1421- if (system_information->machine_has_network_memory)
1422- {
1423- handle_network_game(true);
1424- }
1425- else
1426- {
1427- alert_user(infoError, strERRORS, notEnoughNetworkMemory, 0);
1428- }
1429-#elif defined(__MACOS__)
1430- break;
1431-#else
1432- handle_network_game(true);
1433-#endif
1434- break;
1435-
1436- case iLoadGame:
1437- handle_load_game();
1438- break;
1439-
1440- case iReplayLastFilm:
1441- case iReplaySavedFilm:
1442- handle_replay(menu_item==iReplayLastFilm);
1443- break;
1444-
1445- case iCredits:
1446- display_credits();
1447- break;
1448-
1449- case iPreferences:
1450- do_preferences();
1451- game_state.phase= TICKS_UNTIL_DEMO_STARTS;
1452- game_state.last_ticks_on_idle= machine_tick_count();
1453- ForceRepaintMenuDisplay();
1454- break;
1455-
1456- case iCenterButton:
1457- break;
1458-
1459- case iSaveLastFilm:
1460- handle_save_film();
1461- break;
1462-
1463- case iQuit:
1464- display_quit_screens();
1465- break;
1466- case iAbout:
1467- display_about_dialog();
1468- game_state.phase= TICKS_UNTIL_DEMO_STARTS;
1469- game_state.last_ticks_on_idle= machine_tick_count();
1470- break;
1471-
1472- default:
1473- assert(false);
1474- break;
1475- }
1476- break;
1477-
1478- default:
1479- assert(false);
1480- break;
1481- }
1482-}
1483-
1484-void portable_process_screen_click(
1485- short x,
1486- short y,
1487- bool cheatkeys_down)
1488-{
1489- switch(get_game_state())
1490- {
1491- case _game_in_progress:
1492- case _begin_display_of_epilogue:
1493- case _change_level:
1494- case _displaying_network_game_dialogs:
1495- case _quit_game:
1496- case _close_game:
1497- case _switch_demo:
1498- case _revert_game:
1499- break;
1500-
1501- case _display_intro_screens_for_demo:
1502- /* Get out of user mode. */
1503- display_main_menu();
1504- break;
1505-
1506- case _display_quit_screens:
1507- case _display_intro_screens:
1508- case _display_chapter_heading:
1509- case _display_prologue:
1510- case _display_epilogue:
1511- case _display_credits:
1512- /* Force the state change next time through.. */
1513- force_game_state_change();
1514- break;
1515-
1516- case _display_main_menu:
1517- handle_interface_menu_screen_click(x, y, cheatkeys_down);
1518- break;
1519-
1520- default:
1521- assert(false);
1522- break;
1523- }
1524-}
1525-
1526-bool enabled_item(
1527- short item)
1528-{
1529- bool enabled= true;
1530-
1531- switch(item)
1532- {
1533- case iNewGame:
1534- case iLoadGame:
1535- case iPlaySingletonLevel:
1536- case iPreferences:
1537- case iReplaySavedFilm:
1538- case iCredits:
1539- case iQuit:
1540- case iAbout:
1541