• R/O
  • SSH
  • HTTPS

marathon: Commit


Commit MetaInfo

Revisão530 (tree)
Hora2012-06-02 14:44:12
Autorookawa_mi

Mensagem de Log

1.0.2対応
改行コード修正

Mudança Sumário

Diff

--- marathon/trunk/Source_Files/RenderMain/Rasterizer.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/Rasterizer.h (revision 530)
@@ -1,63 +1,63 @@
1-#ifndef _RASTERIZER_CLASS_
2-#define _RASTERIZER_CLASS_
3-/*
4-
5- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6- and the "Aleph One" developers.
7-
8- This program is free software; you can redistribute it and/or modify
9- it under the terms of the GNU General Public License as published by
10- the Free Software Foundation; either version 3 of the License, or
11- (at your option) any later version.
12-
13- This program is distributed in the hope that it will be useful,
14- but WITHOUT ANY WARRANTY; without even the implied warranty of
15- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16- GNU General Public License for more details.
17-
18- This license is contained in the file "COPYING",
19- which is included with this source code; it is available online at
20- http://www.gnu.org/licenses/gpl.html
21-
22- Rasterizer Implementation Base Class
23- by Loren Petrich,
24- August 7, 2000
25-
26- To be subclassed for specific rasterizers (software, OpenGL, etc.)
27-*/
28-
29-#include "render.h"
30-#ifdef HAVE_OPENGL
31-#include "OGL_Render.h"
32-#endif
33-
34-
35-class RasterizerClass
36-{
37-public:
38-
39- // Sets the rasterizer's view data;
40- // be sure to call it before doing any rendering
41- virtual void SetView(view_data& View) {}
42-
43- // Sets the rasterizer so that it will start rendering foreground objects
44- // like weapons in hand
45- virtual void SetForeground() {}
46-
47- // Sets the view of a foreground object;
48- // parameter is whether it is horizontally reflected
49- virtual void SetForegroundView(bool HorizReflect) {}
50-
51- // Rendering calls
52- virtual void Begin() {}
53- virtual void End() {}
54-
55- virtual void texture_horizontal_polygon(polygon_definition& textured_polygon) {}
56-
57- virtual void texture_vertical_polygon(polygon_definition& textured_polygon) {}
58-
59- virtual void texture_rectangle(rectangle_definition& textured_rectangle) {}
60-};
61-
62-
63-#endif
1+#ifndef _RASTERIZER_CLASS_
2+#define _RASTERIZER_CLASS_
3+/*
4+
5+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6+ and the "Aleph One" developers.
7+
8+ This program is free software; you can redistribute it and/or modify
9+ it under the terms of the GNU General Public License as published by
10+ the Free Software Foundation; either version 3 of the License, or
11+ (at your option) any later version.
12+
13+ This program is distributed in the hope that it will be useful,
14+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU General Public License for more details.
17+
18+ This license is contained in the file "COPYING",
19+ which is included with this source code; it is available online at
20+ http://www.gnu.org/licenses/gpl.html
21+
22+ Rasterizer Implementation Base Class
23+ by Loren Petrich,
24+ August 7, 2000
25+
26+ To be subclassed for specific rasterizers (software, OpenGL, etc.)
27+*/
28+
29+#include "render.h"
30+#ifdef HAVE_OPENGL
31+#include "OGL_Render.h"
32+#endif
33+
34+
35+class RasterizerClass
36+{
37+public:
38+
39+ // Sets the rasterizer's view data;
40+ // be sure to call it before doing any rendering
41+ virtual void SetView(view_data& View) {}
42+
43+ // Sets the rasterizer so that it will start rendering foreground objects
44+ // like weapons in hand
45+ virtual void SetForeground() {}
46+
47+ // Sets the view of a foreground object;
48+ // parameter is whether it is horizontally reflected
49+ virtual void SetForegroundView(bool HorizReflect) {}
50+
51+ // Rendering calls
52+ virtual void Begin() {}
53+ virtual void End() {}
54+
55+ virtual void texture_horizontal_polygon(polygon_definition& textured_polygon) {}
56+
57+ virtual void texture_vertical_polygon(polygon_definition& textured_polygon) {}
58+
59+ virtual void texture_rectangle(rectangle_definition& textured_rectangle) {}
60+};
61+
62+
63+#endif
--- marathon/trunk/Source_Files/RenderMain/OGL_Subst_Texture_Def.cpp (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/OGL_Subst_Texture_Def.cpp (revision 530)
@@ -1,489 +1,495 @@
1-/*
2-
3- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4- and the "Aleph One" developers.
5-
6- This program is free software; you can redistribute it and/or modify
7- it under the terms of the GNU General Public License as published by
8- the Free Software Foundation; either version 3 of the License, or
9- (at your option) any later version.
10-
11- This program is distributed in the hope that it will be useful,
12- but WITHOUT ANY WARRANTY; without even the implied warranty of
13- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14- GNU General Public License for more details.
15-
16- This license is contained in the file "COPYING",
17- which is included with this source code; it is available online at
18- http://www.gnu.org/licenses/gpl.html
19-
20- OpenGL Substitute-Texture-Definition File
21- by Loren Petrich,
22- March 12, 2000
23-
24- This contains implementations of functions for handling
25- the OpenGL substitute textures for the walls and the sprites
26-*/
27-
28-#include "cseries.h"
29-#include "OGL_Subst_Texture_Def.h"
30-#include "Logging.h"
31-
32-#include <set>
33-#include <string>
34-#include <boost/unordered_map.hpp>
35-
36-#ifdef HAVE_OPENGL
37-
38-// Texture-options stuff;
39-// defaults for whatever might need them
40-static OGL_TextureOptions DefaultTextureOptions;
41-
42-typedef std::pair<short, short> TOKey;
43-typedef boost::unordered_map<TOKey, OGL_TextureOptions> TOHash;
44-static TOHash Collections[NUMBER_OF_COLLECTIONS];
45-
46-// Deletes a collection's texture-options sequences
47-void TODelete(short Collection)
48-{
49- Collections[Collection].clear();
50-}
51-
52-// Deletes all of them
53-static void TODelete_All()
54-{
55- for (int c = 0; c < NUMBER_OF_COLLECTIONS; c++) TODelete(c);
56-}
57-
58-int OGL_CountTextures(short Collection)
59-{
60- return Collections[Collection].size();
61-}
62-
63-extern void OGL_ProgressCallback(int);
64-
65-void OGL_LoadTextures(short Collection)
66-{
67-
68- for (TOHash::iterator it = Collections[Collection].begin(); it != Collections[Collection].end(); ++it)
69- {
70- it->second.Load();
71- OGL_ProgressCallback(1);
72-
73- }
74-}
75-
76-
77-void OGL_UnloadTextures(short Collection)
78-{
79- for (TOHash::iterator it = Collections[Collection].begin(); it != Collections[Collection].end(); ++it)
80- {
81- it->second.Unload();
82- }
83-}
84-
85-
86-OGL_TextureOptions *OGL_GetTextureOptions(short Collection, short CLUT, short Bitmap)
87-{
88- TOHash::iterator it = Collections[Collection].find(TOKey(CLUT, Bitmap));
89- if (it != Collections[Collection].end())
90- {
91- return &it->second;
92- }
93-
94- it = Collections[Collection].find(TOKey(ALL_CLUTS, Bitmap));
95- if (it != Collections[Collection].end())
96- {
97- return &it->second;
98- }
99-
100- return &DefaultTextureOptions;
101-}
102-
103-
104-class XML_TO_ClearParser: public XML_ElementParser
105-{
106- bool IsPresent;
107- short Collection;
108-
109-public:
110- bool Start();
111- bool HandleAttribute(const char *Tag, const char *Value);
112- bool AttributesDone();
113-
114- XML_TO_ClearParser(): XML_ElementParser("txtr_clear") {}
115-};
116-
117-bool XML_TO_ClearParser::Start()
118-{
119- IsPresent = false;
120- return true;
121-}
122-
123-bool XML_TO_ClearParser::HandleAttribute(const char *Tag, const char *Value)
124-{
125- if (StringsEqual(Tag,"coll"))
126- {
127- if (ReadBoundedInt16Value(Value,Collection,0,NUMBER_OF_COLLECTIONS-1))
128- {
129- IsPresent = true;
130- return true;
131- }
132- else return false;
133- }
134- UnrecognizedTag();
135- return false;
136-}
137-
138-bool XML_TO_ClearParser::AttributesDone()
139-{
140- if (IsPresent)
141- TODelete(Collection);
142- else
143- TODelete_All();
144-
145- return true;
146-}
147-
148-static XML_TO_ClearParser TO_ClearParser;
149-
150-
151-class XML_TextureOptionsParser: public XML_ElementParser
152-{
153- bool CollIsPresent, BitmapIsPresent;
154- short Collection, CLUT, Bitmap;
155-
156- std::set<std::string> Attributes;
157-
158- OGL_TextureOptions Data;
159-
160- bool _HandleAttribute(const char *Tag, const char *Value);
161-
162-public:
163- bool Start();
164- bool HandleAttribute(const char *Tag, const char *Value);
165- bool AttributesDone();
166- bool ResetValues();
167-
168- XML_TextureOptionsParser(): XML_ElementParser("texture") {}
169-};
170-
171-bool XML_TextureOptionsParser::Start()
172-{
173- Data = DefaultTextureOptions;
174- CollIsPresent = BitmapIsPresent = false;
175- CLUT = ALL_CLUTS;
176- Attributes.clear();
177-
178- return true;
179-}
180-
181-bool XML_TextureOptionsParser::_HandleAttribute(const char *Tag, const char *Value)
182-{
183- if (StringsEqual(Tag,"coll"))
184- {
185- if (ReadBoundedInt16Value(Value,Collection,0,NUMBER_OF_COLLECTIONS-1))
186- {
187- CollIsPresent = true;
188- return true;
189- }
190- else return false;
191- }
192- else if (StringsEqual(Tag,"clut"))
193- {
194- return ReadBoundedInt16Value(Value,CLUT,short(ALL_CLUTS),short(SILHOUETTE_BITMAP_SET));
195- }
196- else if (StringsEqual(Tag,"bitmap"))
197- {
198- if (ReadBoundedInt16Value(Value,Bitmap,0,MAXIMUM_SHAPES_PER_COLLECTION-1))
199- {
200- BitmapIsPresent = true;
201- return true;
202- }
203- else return false;
204- }
205- else if (StringsEqual(Tag,"opac_type"))
206- {
207- return ReadBoundedInt16Value(Value,Data.OpacityType,0,OGL_NUMBER_OF_OPACITY_TYPES-1);
208- }
209- else if (StringsEqual(Tag,"opac_scale"))
210- {
211- return ReadFloatValue(Value,Data.OpacityScale);
212- }
213- else if (StringsEqual(Tag,"opac_shift"))
214- {
215- return ReadFloatValue(Value,Data.OpacityShift);
216- }
217- else if (StringsEqual(Tag,"void_visible"))
218- {
219- return ReadBooleanValueAsBool(Value,Data.VoidVisible);
220- }
221- else if (StringsEqual(Tag,"normal_image"))
222- {
223- Data.NormalColors.SetNameWithPath(Value);
224- return true;
225- }
226- else if (StringsEqual(Tag,"offset_image"))
227- {
228- Data.OffsetMap.SetNameWithPath(Value);
229- return true;
230- }
231- else if (StringsEqual(Tag,"normal_mask"))
232- {
233- Data.NormalMask.SetNameWithPath(Value);
234- return true;
235- }
236- else if (StringsEqual(Tag,"glow_image"))
237- {
238- Data.GlowColors.SetNameWithPath(Value);
239- return true;
240- }
241- else if (StringsEqual(Tag,"glow_mask"))
242- {
243- Data.GlowMask.SetNameWithPath(Value);
244- return true;
245- }
246- else if (StringsEqual(Tag,"normal_blend"))
247- {
248- return ReadBoundedInt16Value(Value,Data.NormalBlend,0,OGL_NUMBER_OF_BLEND_TYPES-1);
249- }
250- else if (StringsEqual(Tag,"glow_blend"))
251- {
252- return ReadBoundedInt16Value(Value,Data.GlowBlend,0,OGL_NUMBER_OF_BLEND_TYPES-1);
253- }
254- else if (StringsEqual(Tag, "image_scale"))
255- {
256- logWarning("Ignoring deprecated image_scale tag");
257- return true;
258- }
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- }
269- else if (StringsEqual(Tag,"shape_width"))
270- {
271- logWarning("Ignoring deprecated shape_width tag");
272- return true;
273- }
274- else if (StringsEqual(Tag,"shape_height"))
275- {
276- logWarning("Ignoring deprecated shape_height tag");
277- return true;
278- }
279- else if (StringsEqual(Tag,"offset_x"))
280- {
281- logWarning("Ignoring deprecated offset_x tag");
282- return true;
283- }
284- else if (StringsEqual(Tag,"offset_y"))
285- {
286- logWarning("Ignoring deprecated offset_y tag");
287- return true;
288- }
289- else if (StringsEqual(Tag,"actual_height"))
290- {
291- return ReadInt16Value(Value, Data.actual_height);
292- }
293- else if (StringsEqual(Tag, "actual_width"))
294- {
295- return ReadInt16Value(Value, Data.actual_width);
296- }
297- else if (StringsEqual(Tag, "type"))
298- {
299- return ReadInt16Value(Value, Data.Type);
300- }
301- else if (StringsEqual(Tag, "normal_premultiply"))
302- {
303- return ReadBooleanValueAsBool(Value, Data.NormalIsPremultiplied);
304- }
305- else if (StringsEqual(Tag, "glow_premultiply"))
306- {
307- return ReadBooleanValueAsBool(Value, Data.GlowIsPremultiplied);
308- }
309- else if (StringsEqual(Tag,"normal_bloom_scale"))
310- {
311- return ReadFloatValue(Value,Data.BloomScale);
312- }
313- else if (StringsEqual(Tag,"normal_bloom_shift"))
314- {
315- return ReadFloatValue(Value,Data.BloomShift);
316- }
317- else if (StringsEqual(Tag,"glow_bloom_scale"))
318- {
319- return ReadFloatValue(Value,Data.GlowBloomScale);
320- }
321- else if (StringsEqual(Tag,"glow_bloom_shift"))
322- {
323- return ReadFloatValue(Value,Data.GlowBloomShift);
324- }
325- else if (StringsEqual(Tag,"landscape_bloom"))
326- {
327- return ReadFloatValue(Value,Data.LandscapeBloom);
328- }
329- else if (StringsEqual(Tag,"minimum_glow_intensity"))
330- {
331- return ReadFloatValue(Value,Data.MinGlowIntensity);
332- }
333- UnrecognizedTag();
334- return false;
335-}
336-
337-bool XML_TextureOptionsParser::HandleAttribute(const char* Tag, const char* Value)
338-{
339- if (_HandleAttribute(Tag, Value))
340- {
341- Attributes.insert(Tag);
342- return true;
343- }
344- return false;
345-}
346-
347-bool XML_TextureOptionsParser::AttributesDone()
348-{
349- // Verify...
350- if (!CollIsPresent || !BitmapIsPresent)
351- {
352- AttribsMissing();
353- return false;
354- }
355-
356- TOHash::iterator it = Collections[Collection].find(TOKey(CLUT, Bitmap));
357- if (it == Collections[Collection].end())
358- {
359- Collections[Collection][TOKey(CLUT, Bitmap)] = Data;
360- return true;
361- }
362-
363- if (Attributes.count("opac_type"))
364- {
365- it->second.OpacityType = Data.OpacityType;
366- }
367-
368- if (Attributes.count("opac_scale"))
369- {
370- it->second.OpacityScale = Data.OpacityScale;
371- }
372-
373- if (Attributes.count("opac_shift"))
374- {
375- it->second.OpacityShift = Data.OpacityShift;
376- }
377-
378- if (Attributes.count("void_visible"))
379- {
380- it->second.VoidVisible = Data.VoidVisible;
381- }
382-
383- if (Attributes.count("normal_image"))
384- {
385- it->second.NormalColors = Data.NormalColors;
386- }
387-
388- if (Attributes.count("offset_image"))
389- {
390- it->second.OffsetMap = Data.OffsetMap;
391- }
392-
393- if (Attributes.count("normal_mask"))
394- {
395- it->second.NormalMask = Data.NormalMask;
396- }
397-
398- if (Attributes.count("glow_image"))
399- {
400- it->second.GlowColors = Data.GlowColors;
401- }
402-
403- if (Attributes.count("glow_mask"))
404- {
405- it->second.GlowMask = Data.GlowMask;
406- }
407-
408- if (Attributes.count("normal_blend"))
409- {
410- it->second.NormalBlend = Data.NormalBlend;
411- }
412-
413- if (Attributes.count("glow_blend"))
414- {
415- it->second.GlowBlend = Data.GlowBlend;
416- }
417-
418- if (Attributes.count("actual_height"))
419- {
420- it->second.actual_height = Data.actual_height;
421- }
422-
423- if (Attributes.count("actual_width"))
424- {
425- it->second.actual_width = Data.actual_width;
426- }
427-
428- if (Attributes.count("type"))
429- {
430- it->second.Type = Data.Type;
431- }
432-
433- if (Attributes.count("normal_premultiply"))
434- {
435- it->second.NormalIsPremultiplied = Data.NormalIsPremultiplied;
436- }
437-
438- if (Attributes.count("glow_premultiply"))
439- {
440- it->second.GlowIsPremultiplied = Data.GlowIsPremultiplied;
441- }
442-
443- if (Attributes.count("normal_bloom_scale"))
444- {
445- it->second.BloomScale = Data.BloomScale;
446- }
447-
448- if (Attributes.count("normal_bloom_shift"))
449- {
450- it->second.BloomShift = Data.BloomShift;
451- }
452-
453- if (Attributes.count("glow_bloom_scale"))
454- {
455- it->second.GlowBloomScale = Data.GlowBloomScale;
456- }
457-
458- if (Attributes.count("glow_bloom_shift"))
459- {
460- it->second.GlowBloomShift = Data.GlowBloomShift;
461- }
462-
463- if (Attributes.count("landscape_bloom"))
464- {
465- it->second.LandscapeBloom = Data.LandscapeBloom;
466- }
467-
468- if (Attributes.count("minimum_glow_intensity"))
469- {
470- it->second.MinGlowIntensity = Data.MinGlowIntensity;
471- }
472-
473- return true;
474-}
475-
476-bool XML_TextureOptionsParser::ResetValues()
477-{
478- TODelete_All();
479- return true;
480-}
481-
482-static XML_TextureOptionsParser TextureOptionsParser;
483-
484-
485-// XML-parser support:
486-XML_ElementParser *TextureOptions_GetParser() {return &TextureOptionsParser;}
487-XML_ElementParser *TO_Clear_GetParser() {return &TO_ClearParser;}
488-
489-#endif
1+/*
2+
3+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4+ and the "Aleph One" developers.
5+
6+ This program is free software; you can redistribute it and/or modify
7+ it under the terms of the GNU General Public License as published by
8+ the Free Software Foundation; either version 3 of the License, or
9+ (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU General Public License for more details.
15+
16+ This license is contained in the file "COPYING",
17+ which is included with this source code; it is available online at
18+ http://www.gnu.org/licenses/gpl.html
19+
20+ OpenGL Substitute-Texture-Definition File
21+ by Loren Petrich,
22+ March 12, 2000
23+
24+ This contains implementations of functions for handling
25+ the OpenGL substitute textures for the walls and the sprites
26+*/
27+
28+#include "cseries.h"
29+#include "OGL_Subst_Texture_Def.h"
30+#include "Logging.h"
31+
32+#include <set>
33+#include <string>
34+#include <boost/unordered_map.hpp>
35+
36+#ifdef HAVE_OPENGL
37+
38+// Texture-options stuff;
39+// defaults for whatever might need them
40+static OGL_TextureOptions DefaultTextureOptions;
41+
42+typedef std::pair<short, short> TOKey;
43+typedef boost::unordered_map<TOKey, OGL_TextureOptions> TOHash;
44+static TOHash Collections[NUMBER_OF_COLLECTIONS];
45+
46+// Deletes a collection's texture-options sequences
47+void TODelete(short Collection)
48+{
49+ Collections[Collection].clear();
50+}
51+
52+// Deletes all of them
53+static void TODelete_All()
54+{
55+ for (int c = 0; c < NUMBER_OF_COLLECTIONS; c++) TODelete(c);
56+}
57+
58+int OGL_CountTextures(short Collection)
59+{
60+ return Collections[Collection].size();
61+}
62+
63+extern void OGL_ProgressCallback(int);
64+
65+void OGL_LoadTextures(short Collection)
66+{
67+
68+ for (TOHash::iterator it = Collections[Collection].begin(); it != Collections[Collection].end(); ++it)
69+ {
70+ it->second.Load();
71+ OGL_ProgressCallback(1);
72+
73+ }
74+}
75+
76+
77+void OGL_UnloadTextures(short Collection)
78+{
79+ for (TOHash::iterator it = Collections[Collection].begin(); it != Collections[Collection].end(); ++it)
80+ {
81+ it->second.Unload();
82+ }
83+}
84+
85+
86+OGL_TextureOptions *OGL_GetTextureOptions(short Collection, short CLUT, short Bitmap)
87+{
88+ TOHash::iterator it = Collections[Collection].find(TOKey(CLUT, Bitmap));
89+ if (it != Collections[Collection].end())
90+ {
91+ return &it->second;
92+ }
93+
94+ it = Collections[Collection].find(TOKey(ALL_CLUTS, Bitmap));
95+ if (it != Collections[Collection].end())
96+ {
97+ return &it->second;
98+ }
99+
100+ return &DefaultTextureOptions;
101+}
102+
103+
104+class XML_TO_ClearParser: public XML_ElementParser
105+{
106+ bool IsPresent;
107+ short Collection;
108+
109+public:
110+ bool Start();
111+ bool HandleAttribute(const char *Tag, const char *Value);
112+ bool AttributesDone();
113+
114+ XML_TO_ClearParser(): XML_ElementParser("txtr_clear") {}
115+};
116+
117+bool XML_TO_ClearParser::Start()
118+{
119+ IsPresent = false;
120+ return true;
121+}
122+
123+bool XML_TO_ClearParser::HandleAttribute(const char *Tag, const char *Value)
124+{
125+ if (StringsEqual(Tag,"coll"))
126+ {
127+ if (ReadBoundedInt16Value(Value,Collection,0,NUMBER_OF_COLLECTIONS-1))
128+ {
129+ IsPresent = true;
130+ return true;
131+ }
132+ else return false;
133+ }
134+ UnrecognizedTag();
135+ return false;
136+}
137+
138+bool XML_TO_ClearParser::AttributesDone()
139+{
140+ if (IsPresent)
141+ TODelete(Collection);
142+ else
143+ TODelete_All();
144+
145+ return true;
146+}
147+
148+static XML_TO_ClearParser TO_ClearParser;
149+
150+
151+class XML_TextureOptionsParser: public XML_ElementParser
152+{
153+ bool CollIsPresent, BitmapIsPresent;
154+ short Collection, CLUT, Bitmap;
155+
156+ std::set<std::string> Attributes;
157+
158+ OGL_TextureOptions Data;
159+
160+ bool _HandleAttribute(const char *Tag, const char *Value);
161+
162+public:
163+ bool Start();
164+ bool HandleAttribute(const char *Tag, const char *Value);
165+ bool AttributesDone();
166+ bool ResetValues();
167+
168+ XML_TextureOptionsParser(): XML_ElementParser("texture") {}
169+};
170+
171+bool XML_TextureOptionsParser::Start()
172+{
173+ Data = DefaultTextureOptions;
174+ CollIsPresent = BitmapIsPresent = false;
175+ CLUT = ALL_CLUTS;
176+ Attributes.clear();
177+
178+ return true;
179+}
180+
181+bool XML_TextureOptionsParser::_HandleAttribute(const char *Tag, const char *Value)
182+{
183+ if (StringsEqual(Tag,"coll"))
184+ {
185+ if (ReadBoundedInt16Value(Value,Collection,0,NUMBER_OF_COLLECTIONS-1))
186+ {
187+ CollIsPresent = true;
188+ return true;
189+ }
190+ else return false;
191+ }
192+ else if (StringsEqual(Tag,"clut"))
193+ {
194+ return ReadBoundedInt16Value(Value,CLUT,short(ALL_CLUTS),short(SILHOUETTE_BITMAP_SET));
195+ }
196+ else if (StringsEqual(Tag,"bitmap"))
197+ {
198+ if (ReadBoundedInt16Value(Value,Bitmap,0,MAXIMUM_SHAPES_PER_COLLECTION-1))
199+ {
200+ BitmapIsPresent = true;
201+ return true;
202+ }
203+ else return false;
204+ }
205+ else if (StringsEqual(Tag,"opac_type"))
206+ {
207+ return ReadBoundedInt16Value(Value,Data.OpacityType,0,OGL_NUMBER_OF_OPACITY_TYPES-1);
208+ }
209+ else if (StringsEqual(Tag,"opac_scale"))
210+ {
211+ return ReadFloatValue(Value,Data.OpacityScale);
212+ }
213+ else if (StringsEqual(Tag,"opac_shift"))
214+ {
215+ return ReadFloatValue(Value,Data.OpacityShift);
216+ }
217+ else if (StringsEqual(Tag,"void_visible"))
218+ {
219+ return ReadBooleanValueAsBool(Value,Data.VoidVisible);
220+ }
221+ else if (StringsEqual(Tag,"normal_image"))
222+ {
223+ Data.NormalColors.SetNameWithPath(Value);
224+ return true;
225+ }
226+ else if (StringsEqual(Tag,"offset_image"))
227+ {
228+ Data.OffsetMap.SetNameWithPath(Value);
229+ return true;
230+ }
231+ else if (StringsEqual(Tag,"normal_mask"))
232+ {
233+ Data.NormalMask.SetNameWithPath(Value);
234+ return true;
235+ }
236+ else if (StringsEqual(Tag,"glow_image"))
237+ {
238+ Data.GlowColors.SetNameWithPath(Value);
239+ return true;
240+ }
241+ else if (StringsEqual(Tag,"glow_mask"))
242+ {
243+ Data.GlowMask.SetNameWithPath(Value);
244+ return true;
245+ }
246+ else if (StringsEqual(Tag,"normal_blend"))
247+ {
248+ return ReadBoundedInt16Value(Value,Data.NormalBlend,0,OGL_NUMBER_OF_BLEND_TYPES-1);
249+ }
250+ else if (StringsEqual(Tag,"glow_blend"))
251+ {
252+ return ReadBoundedInt16Value(Value,Data.GlowBlend,0,OGL_NUMBER_OF_BLEND_TYPES-1);
253+ }
254+ else if (StringsEqual(Tag, "image_scale"))
255+ {
256+ logWarning("Ignoring deprecated image_scale tag");
257+ return true;
258+ }
259+ else if (StringsEqual(Tag,"shape_width"))
260+ {
261+ return ReadInt16Value(Value,Data.shape_width);
262+ }
263+ else if (StringsEqual(Tag,"shape_height"))
264+ {
265+ return ReadInt16Value(Value,Data.shape_height);
266+ }
267+ else if (StringsEqual(Tag,"offset_x"))
268+ {
269+ return ReadInt16Value(Value,Data.offset_x);
270+ }
271+ else if (StringsEqual(Tag,"offset_y"))
272+ {
273+ return ReadInt16Value(Value,Data.offset_y);
274+ }
275+ else if (StringsEqual(Tag,"actual_height"))
276+ {
277+ return ReadInt16Value(Value, Data.actual_height);
278+ }
279+ else if (StringsEqual(Tag, "actual_width"))
280+ {
281+ return ReadInt16Value(Value, Data.actual_width);
282+ }
283+ else if (StringsEqual(Tag, "type"))
284+ {
285+ return ReadInt16Value(Value, Data.Type);
286+ }
287+ else if (StringsEqual(Tag, "normal_premultiply"))
288+ {
289+ return ReadBooleanValueAsBool(Value, Data.NormalIsPremultiplied);
290+ }
291+ else if (StringsEqual(Tag, "glow_premultiply"))
292+ {
293+ return ReadBooleanValueAsBool(Value, Data.GlowIsPremultiplied);
294+ }
295+ else if (StringsEqual(Tag,"normal_bloom_scale"))
296+ {
297+ return ReadFloatValue(Value,Data.BloomScale);
298+ }
299+ else if (StringsEqual(Tag,"normal_bloom_shift"))
300+ {
301+ return ReadFloatValue(Value,Data.BloomShift);
302+ }
303+ else if (StringsEqual(Tag,"glow_bloom_scale"))
304+ {
305+ return ReadFloatValue(Value,Data.GlowBloomScale);
306+ }
307+ else if (StringsEqual(Tag,"glow_bloom_shift"))
308+ {
309+ return ReadFloatValue(Value,Data.GlowBloomShift);
310+ }
311+ else if (StringsEqual(Tag,"landscape_bloom"))
312+ {
313+ return ReadFloatValue(Value,Data.LandscapeBloom);
314+ }
315+ else if (StringsEqual(Tag,"minimum_glow_intensity"))
316+ {
317+ return ReadFloatValue(Value,Data.MinGlowIntensity);
318+ }
319+ UnrecognizedTag();
320+ return false;
321+}
322+
323+bool XML_TextureOptionsParser::HandleAttribute(const char* Tag, const char* Value)
324+{
325+ if (_HandleAttribute(Tag, Value))
326+ {
327+ Attributes.insert(Tag);
328+ return true;
329+ }
330+ return false;
331+}
332+
333+bool XML_TextureOptionsParser::AttributesDone()
334+{
335+ // Verify...
336+ if (!CollIsPresent || !BitmapIsPresent)
337+ {
338+ AttribsMissing();
339+ return false;
340+ }
341+
342+ TOHash::iterator it = Collections[Collection].find(TOKey(CLUT, Bitmap));
343+ if (it == Collections[Collection].end())
344+ {
345+ Collections[Collection][TOKey(CLUT, Bitmap)] = Data;
346+ return true;
347+ }
348+
349+ if (Attributes.count("opac_type"))
350+ {
351+ it->second.OpacityType = Data.OpacityType;
352+ }
353+
354+ if (Attributes.count("opac_scale"))
355+ {
356+ it->second.OpacityScale = Data.OpacityScale;
357+ }
358+
359+ if (Attributes.count("opac_shift"))
360+ {
361+ it->second.OpacityShift = Data.OpacityShift;
362+ }
363+
364+ if (Attributes.count("void_visible"))
365+ {
366+ it->second.VoidVisible = Data.VoidVisible;
367+ }
368+
369+ if (Attributes.count("normal_image"))
370+ {
371+ it->second.NormalColors = Data.NormalColors;
372+ }
373+
374+ if (Attributes.count("offset_image"))
375+ {
376+ it->second.OffsetMap = Data.OffsetMap;
377+ }
378+
379+ if (Attributes.count("normal_mask"))
380+ {
381+ it->second.NormalMask = Data.NormalMask;
382+ }
383+
384+ if (Attributes.count("glow_image"))
385+ {
386+ it->second.GlowColors = Data.GlowColors;
387+ }
388+
389+ if (Attributes.count("glow_mask"))
390+ {
391+ it->second.GlowMask = Data.GlowMask;
392+ }
393+
394+ if (Attributes.count("normal_blend"))
395+ {
396+ it->second.NormalBlend = Data.NormalBlend;
397+ }
398+
399+ if (Attributes.count("glow_blend"))
400+ {
401+ it->second.GlowBlend = Data.GlowBlend;
402+ }
403+
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+
424+ if (Attributes.count("actual_height"))
425+ {
426+ it->second.actual_height = Data.actual_height;
427+ }
428+
429+ if (Attributes.count("actual_width"))
430+ {
431+ it->second.actual_width = Data.actual_width;
432+ }
433+
434+ if (Attributes.count("type"))
435+ {
436+ it->second.Type = Data.Type;
437+ }
438+
439+ if (Attributes.count("normal_premultiply"))
440+ {
441+ it->second.NormalIsPremultiplied = Data.NormalIsPremultiplied;
442+ }
443+
444+ if (Attributes.count("glow_premultiply"))
445+ {
446+ it->second.GlowIsPremultiplied = Data.GlowIsPremultiplied;
447+ }
448+
449+ if (Attributes.count("normal_bloom_scale"))
450+ {
451+ it->second.BloomScale = Data.BloomScale;
452+ }
453+
454+ if (Attributes.count("normal_bloom_shift"))
455+ {
456+ it->second.BloomShift = Data.BloomShift;
457+ }
458+
459+ if (Attributes.count("glow_bloom_scale"))
460+ {
461+ it->second.GlowBloomScale = Data.GlowBloomScale;
462+ }
463+
464+ if (Attributes.count("glow_bloom_shift"))
465+ {
466+ it->second.GlowBloomShift = Data.GlowBloomShift;
467+ }
468+
469+ if (Attributes.count("landscape_bloom"))
470+ {
471+ it->second.LandscapeBloom = Data.LandscapeBloom;
472+ }
473+
474+ if (Attributes.count("minimum_glow_intensity"))
475+ {
476+ it->second.MinGlowIntensity = Data.MinGlowIntensity;
477+ }
478+
479+ return true;
480+}
481+
482+bool XML_TextureOptionsParser::ResetValues()
483+{
484+ TODelete_All();
485+ return true;
486+}
487+
488+static XML_TextureOptionsParser TextureOptionsParser;
489+
490+
491+// XML-parser support:
492+XML_ElementParser *TextureOptions_GetParser() {return &TextureOptionsParser;}
493+XML_ElementParser *TO_Clear_GetParser() {return &TO_ClearParser;}
494+
495+#endif
--- marathon/trunk/Source_Files/RenderMain/Rasterizer_OGL.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/Rasterizer_OGL.h (revision 530)
@@ -1,69 +1,69 @@
1-#ifndef _RASTERIZER_OPENGL_CLASS_
2-#define _RASTERIZER_OPENGL_CLASS_
3-/*
4-
5- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6- and the "Aleph One" developers.
7-
8- This program is free software; you can redistribute it and/or modify
9- it under the terms of the GNU General Public License as published by
10- the Free Software Foundation; either version 3 of the License, or
11- (at your option) any later version.
12-
13- This program is distributed in the hope that it will be useful,
14- but WITHOUT ANY WARRANTY; without even the implied warranty of
15- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16- GNU General Public License for more details.
17-
18- This license is contained in the file "COPYING",
19- which is included with this source code; it is available online at
20- http://www.gnu.org/licenses/gpl.html
21-
22- Rasterizer OpenGL impementation
23- by Loren Petrich,
24- August 7, 2000
25-
26- As it says... will need to rewrite OGL_Render to make it truly object-oriented
27-*/
28-
29-#include "Rasterizer.h"
30-
31-
32-class Rasterizer_OGL_Class: public RasterizerClass
33-{
34-public:
35-
36- // Sets the rasterizer's view data;
37- // be sure to call it before doing any rendering
38- virtual void SetView(view_data& View) {OGL_SetView(View);}
39-
40- // Sets the rasterizer so that it will start rendering foreground objects
41- // like weapons in hand
42- virtual void SetForeground() {OGL_SetForeground();}
43-
44- // Sets the view of a foreground object;
45- // parameter is whether it is horizontally reflected
46- virtual void SetForegroundView(bool HorizReflect) {OGL_SetForegroundView(HorizReflect);}
47-
48- // Rendering calls
49- void Begin() {OGL_StartMain();}
50- void End() {OGL_EndMain();}
51-
52- void texture_horizontal_polygon(polygon_definition& textured_polygon)
53- {
54- OGL_RenderWall(textured_polygon,false);
55- }
56-
57- void texture_vertical_polygon(polygon_definition& textured_polygon)
58- {
59- OGL_RenderWall(textured_polygon,true);
60- }
61-
62- void texture_rectangle(rectangle_definition& textured_rectangle)
63- {
64- OGL_RenderSprite(textured_rectangle);
65- }
66-};
67-
68-
69-#endif
1+#ifndef _RASTERIZER_OPENGL_CLASS_
2+#define _RASTERIZER_OPENGL_CLASS_
3+/*
4+
5+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6+ and the "Aleph One" developers.
7+
8+ This program is free software; you can redistribute it and/or modify
9+ it under the terms of the GNU General Public License as published by
10+ the Free Software Foundation; either version 3 of the License, or
11+ (at your option) any later version.
12+
13+ This program is distributed in the hope that it will be useful,
14+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU General Public License for more details.
17+
18+ This license is contained in the file "COPYING",
19+ which is included with this source code; it is available online at
20+ http://www.gnu.org/licenses/gpl.html
21+
22+ Rasterizer OpenGL impementation
23+ by Loren Petrich,
24+ August 7, 2000
25+
26+ As it says... will need to rewrite OGL_Render to make it truly object-oriented
27+*/
28+
29+#include "Rasterizer.h"
30+
31+
32+class Rasterizer_OGL_Class: public RasterizerClass
33+{
34+public:
35+
36+ // Sets the rasterizer's view data;
37+ // be sure to call it before doing any rendering
38+ virtual void SetView(view_data& View) {OGL_SetView(View);}
39+
40+ // Sets the rasterizer so that it will start rendering foreground objects
41+ // like weapons in hand
42+ virtual void SetForeground() {OGL_SetForeground();}
43+
44+ // Sets the view of a foreground object;
45+ // parameter is whether it is horizontally reflected
46+ virtual void SetForegroundView(bool HorizReflect) {OGL_SetForegroundView(HorizReflect);}
47+
48+ // Rendering calls
49+ void Begin() {OGL_StartMain();}
50+ void End() {OGL_EndMain();}
51+
52+ void texture_horizontal_polygon(polygon_definition& textured_polygon)
53+ {
54+ OGL_RenderWall(textured_polygon,false);
55+ }
56+
57+ void texture_vertical_polygon(polygon_definition& textured_polygon)
58+ {
59+ OGL_RenderWall(textured_polygon,true);
60+ }
61+
62+ void texture_rectangle(rectangle_definition& textured_rectangle)
63+ {
64+ OGL_RenderSprite(textured_rectangle);
65+ }
66+};
67+
68+
69+#endif
--- marathon/trunk/Source_Files/RenderMain/RenderSortPoly.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/RenderSortPoly.h (revision 530)
@@ -1,105 +1,105 @@
1-#ifndef _RENDER_SORT_POLYGONS_CLASS_
2-#define _RENDER_SORT_POLYGONS_CLASS_
3-/*
4-
5- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6- and the "Aleph One" developers.
7-
8- This program is free software; you can redistribute it and/or modify
9- it under the terms of the GNU General Public License as published by
10- the Free Software Foundation; either version 3 of the License, or
11- (at your option) any later version.
12-
13- This program is distributed in the hope that it will be useful,
14- but WITHOUT ANY WARRANTY; without even the implied warranty of
15- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16- GNU General Public License for more details.
17-
18- This license is contained in the file "COPYING",
19- which is included with this source code; it is available online at
20- http://www.gnu.org/licenses/gpl.html
21-
22- Rendering Polygon-Sorting Class
23- by Loren Petrich,
24- August 6, 2000
25-
26- Defines a class for sorting the polygons into appropriate depth order; from render.c
27- Works from RenderVisTree stuff.
28-
29- Made [view_data *view] a member and removed it as an argument
30-
31-Oct 13, 2000
32- LP: replaced ResizableList with STL vector class
33-
34-Oct 13, 2000
35- LP: replaced GrowableLists and ResizableLists with STL vectors
36-*/
37-
38-#include <vector>
39-#include "world.h"
40-#include "render.h"
41-#include "RenderVisTree.h"
42-
43-
44-/* ---------- sorted nodes */
45-
46-struct sorted_node_data
47-{
48- short polygon_index;
49-
50- struct render_object_data *interior_objects;
51- struct render_object_data *exterior_objects;
52-
53- struct clipping_window_data *clipping_windows;
54-};
55-
56-
57-class RenderSortPolyClass
58-{
59- // Auxiliary data and routines:
60-
61- void initialize_sorted_render_tree();
62-
63- clipping_window_data *build_clipping_windows(node_data *ChainBegin);
64-
65- void calculate_vertical_clip_data(line_clip_data **accumulated_line_clips,
66- size_t accumulated_line_clip_count, clipping_window_data *window, short x0, short x1);
67-
68-public:
69-
70- /* converts map polygon indexes to sorted nodes (only valid if _polygon_is_visible) */
71- vector<sorted_node_data *> polygon_index_to_sorted_node;
72-
73- // LP additions: growable list of sorted nodes
74- // Length changed in initialize_sorted_render_tree() and sort_render_tree()
75- // When being built, the render objects are yet to be listed
76- vector<sorted_node_data> SortedNodes;
77-
78- // LP addition: growable lists of accumulations of endpoint and line clips
79- // used in build_clipping_windows()
80- vector<endpoint_clip_data *> AccumulatedEndpointClips;
81- vector<line_clip_data *> AccumulatedLineClips;
82-
83- // Pointers to view and calculated visibility tree
84- view_data *view;
85- RenderVisTreeClass *RVPtr;
86-
87- // Resizes all the objects defined inside;
88- // the resizing is lazy
89- void Resize(size_t NumPolygons);
90-
91- // Does the sorting
92- void sort_render_tree();
93-
94- // Inits everything
95- RenderSortPolyClass();
96-};
97-
98-// Historical note: cause of too-many-transparent-line errors
99-// LP addition: node-alias growable list
100-// Only used in sort_render_tree()
101-// Suppressed as unnecessary because of node_data polygon-sorted-tree structure
102-// static GrowableList<node_data *> NodeAliases(32);
103-
104-
105-#endif
1+#ifndef _RENDER_SORT_POLYGONS_CLASS_
2+#define _RENDER_SORT_POLYGONS_CLASS_
3+/*
4+
5+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6+ and the "Aleph One" developers.
7+
8+ This program is free software; you can redistribute it and/or modify
9+ it under the terms of the GNU General Public License as published by
10+ the Free Software Foundation; either version 3 of the License, or
11+ (at your option) any later version.
12+
13+ This program is distributed in the hope that it will be useful,
14+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU General Public License for more details.
17+
18+ This license is contained in the file "COPYING",
19+ which is included with this source code; it is available online at
20+ http://www.gnu.org/licenses/gpl.html
21+
22+ Rendering Polygon-Sorting Class
23+ by Loren Petrich,
24+ August 6, 2000
25+
26+ Defines a class for sorting the polygons into appropriate depth order; from render.c
27+ Works from RenderVisTree stuff.
28+
29+ Made [view_data *view] a member and removed it as an argument
30+
31+Oct 13, 2000
32+ LP: replaced ResizableList with STL vector class
33+
34+Oct 13, 2000
35+ LP: replaced GrowableLists and ResizableLists with STL vectors
36+*/
37+
38+#include <vector>
39+#include "world.h"
40+#include "render.h"
41+#include "RenderVisTree.h"
42+
43+
44+/* ---------- sorted nodes */
45+
46+struct sorted_node_data
47+{
48+ short polygon_index;
49+
50+ struct render_object_data *interior_objects;
51+ struct render_object_data *exterior_objects;
52+
53+ struct clipping_window_data *clipping_windows;
54+};
55+
56+
57+class RenderSortPolyClass
58+{
59+ // Auxiliary data and routines:
60+
61+ void initialize_sorted_render_tree();
62+
63+ clipping_window_data *build_clipping_windows(node_data *ChainBegin);
64+
65+ void calculate_vertical_clip_data(line_clip_data **accumulated_line_clips,
66+ size_t accumulated_line_clip_count, clipping_window_data *window, short x0, short x1);
67+
68+public:
69+
70+ /* converts map polygon indexes to sorted nodes (only valid if _polygon_is_visible) */
71+ vector<sorted_node_data *> polygon_index_to_sorted_node;
72+
73+ // LP additions: growable list of sorted nodes
74+ // Length changed in initialize_sorted_render_tree() and sort_render_tree()
75+ // When being built, the render objects are yet to be listed
76+ vector<sorted_node_data> SortedNodes;
77+
78+ // LP addition: growable lists of accumulations of endpoint and line clips
79+ // used in build_clipping_windows()
80+ vector<endpoint_clip_data *> AccumulatedEndpointClips;
81+ vector<line_clip_data *> AccumulatedLineClips;
82+
83+ // Pointers to view and calculated visibility tree
84+ view_data *view;
85+ RenderVisTreeClass *RVPtr;
86+
87+ // Resizes all the objects defined inside;
88+ // the resizing is lazy
89+ void Resize(size_t NumPolygons);
90+
91+ // Does the sorting
92+ void sort_render_tree();
93+
94+ // Inits everything
95+ RenderSortPolyClass();
96+};
97+
98+// Historical note: cause of too-many-transparent-line errors
99+// LP addition: node-alias growable list
100+// Only used in sort_render_tree()
101+// Suppressed as unnecessary because of node_data polygon-sorted-tree structure
102+// static GrowableList<node_data *> NodeAliases(32);
103+
104+
105+#endif
--- marathon/trunk/Source_Files/RenderMain/shape_definitions.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/shape_definitions.h (revision 530)
@@ -1,51 +1,51 @@
1-#ifndef __SHAPE_DEFINITIONS_H
2-#define __SHAPE_DEFINITIONS_H
3-/*
4-SHAPE_DEFINITIONS.H
5-
6- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
7- and the "Aleph One" developers.
8-
9- This program is free software; you can redistribute it and/or modify
10- it under the terms of the GNU General Public License as published by
11- the Free Software Foundation; either version 3 of the License, or
12- (at your option) any later version.
13-
14- This program is distributed in the hope that it will be useful,
15- but WITHOUT ANY WARRANTY; without even the implied warranty of
16- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17- GNU General Public License for more details.
18-
19- This license is contained in the file "COPYING",
20- which is included with this source code; it is available online at
21- http://www.gnu.org/licenses/gpl.html
22-
23-Tuesday, August 29, 1995 9:56:56 AM (Jason)
24-
25-Aug 14, 2000 (Loren Petrich):
26- Turned collection and shading-table handles into pointers,
27- because handles are needlessly MacOS-specific,
28- and because these are variable-format objects.
29-*/
30-
31-/* ---------- structures */
32-
33-struct collection_header /* 32 bytes on disk */
34-{
35- int16 status;
36- uint16 flags;
37-
38- int32 offset, length;
39- int32 offset16, length16;
40-
41- // LP: handles to pointers
42- collection_definition *collection;
43- byte *shading_tables;
44-};
45-const int SIZEOF_collection_header = 32;
46-
47-/* ---------- globals */
48-
49-static struct collection_header collection_headers[MAXIMUM_COLLECTIONS];
50-
51-#endif
1+#ifndef __SHAPE_DEFINITIONS_H
2+#define __SHAPE_DEFINITIONS_H
3+/*
4+SHAPE_DEFINITIONS.H
5+
6+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
7+ and the "Aleph One" developers.
8+
9+ This program is free software; you can redistribute it and/or modify
10+ it under the terms of the GNU General Public License as published by
11+ the Free Software Foundation; either version 3 of the License, or
12+ (at your option) any later version.
13+
14+ This program is distributed in the hope that it will be useful,
15+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+ GNU General Public License for more details.
18+
19+ This license is contained in the file "COPYING",
20+ which is included with this source code; it is available online at
21+ http://www.gnu.org/licenses/gpl.html
22+
23+Tuesday, August 29, 1995 9:56:56 AM (Jason)
24+
25+Aug 14, 2000 (Loren Petrich):
26+ Turned collection and shading-table handles into pointers,
27+ because handles are needlessly MacOS-specific,
28+ and because these are variable-format objects.
29+*/
30+
31+/* ---------- structures */
32+
33+struct collection_header /* 32 bytes on disk */
34+{
35+ int16 status;
36+ uint16 flags;
37+
38+ int32 offset, length;
39+ int32 offset16, length16;
40+
41+ // LP: handles to pointers
42+ collection_definition *collection;
43+ byte *shading_tables;
44+};
45+const int SIZEOF_collection_header = 32;
46+
47+/* ---------- globals */
48+
49+static struct collection_header collection_headers[MAXIMUM_COLLECTIONS];
50+
51+#endif
--- marathon/trunk/Source_Files/RenderMain/OGL_Setup.cpp (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/OGL_Setup.cpp (revision 530)
@@ -1,637 +1,637 @@
1-/*
2-
3- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4- and the "Aleph One" developers.
5-
6- This program is free software; you can redistribute it and/or modify
7- it under the terms of the GNU General Public License as published by
8- the Free Software Foundation; either version 3 of the License, or
9- (at your option) any later version.
10-
11- This program is distributed in the hope that it will be useful,
12- but WITHOUT ANY WARRANTY; without even the implied warranty of
13- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14- GNU General Public License for more details.
15-
16- This license is contained in the file "COPYING",
17- which is included with this source code; it is available online at
18- http://www.gnu.org/licenses/gpl.html
19-
20- OpenGL Renderer,
21- by Loren Petrich,
22- March 12, 2000
23-
24- This contains implementations of functions intended for finding out OpenGL's presence
25- in the host system, for setting parameters for OpenGL rendering,
26- and for deciding whether to use OpenGL for rendering.
27-
28- June 11, 2000
29-
30- Had added XML parsing before that; most recently, added "opac_shift".
31-
32- Made semitransparency optional if the void is on one side of the texture
33-
34-Oct 13, 2000 (Loren Petrich)
35- Converted the OpenGL-addition accounting into Standard Template Library vectors
36-
37-Nov 12, 2000 (Loren Petrich):
38- Implemented texture substitution, also moved pixel-opacity editing into here;
39- the code is carefully constructed to assume RGBA byte order whether integers are
40- big- or little-endian.
41-
42-Nov 18, 2000 (Loren Petrich):
43- Added support for glow mapping; constrained it to only be present
44- when a normal texture is present, and to have the same size
45-
46-Nov 26, 2000 (Loren Petrich):
47- Added system for reloading textures only when their filenames change.
48-
49-Dec 17, 2000 (Loren Petrich):
50- Eliminated fog parameters from the preferences;
51- there is still a "fog present" switch, which is used to indicate
52- whether fog will not be suppressed.
53-
54-Apr 27, 2001 (Loren Petrich):
55- Modified the OpenGL fog support so as to enable below-liquid fogs
56-
57-Jul 8, 2001 (Loren Petrich):
58- Made it possible to read in silhouette bitmaps; one can now use the silhouette index
59- as a MML color-table index
60-
61-Aug 21, 2001 (Loren Petrich):
62- Adding support for 3D-model inhabitant objects
63-
64-Jan 25, 2002 (Br'fin (Jeremy Parsons)):
65- Added TARGET_API_MAC_CARBON for OpenGL.h, AGL.h
66- Removed QuickDraw3D support from Carbon
67-
68-Feb 5, 2002 (Br'fin (Jeremy Parsons)):
69- Refined OGL default preferences for Carbon
70-*/
71-
72-#include <vector>
73-#include <string.h>
74-#include <math.h>
75-#include "cseries.h"
76-
77-#ifdef HAVE_OPENGL
78-
79-#ifdef __MVCPP__
80-#include <windows.h>
81-#endif
82-
83-#include "OGL_Headers.h"
84-#include "OGL_Shader.h"
85-
86-#endif
87-
88-#include "shape_descriptors.h"
89-#include "OGL_Setup.h"
90-#include "ColorParser.h"
91-#include "OGL_LoadScreen.h"
92-#include "progress.h"
93-
94-// Whether or not OpenGL is present and usable
95-static bool _OGL_IsPresent = false;
96-
97-bool Using_sRGB = false;
98-bool Wanting_sRGB = false;
99-bool Bloom_sRGB = false;
100-bool npotTextures = false; // non-power-of-two
101-
102-// Initializer
103-bool OGL_Initialize()
104-{
105-#ifdef HAVE_OPENGL
106-#if defined(mac)
107- // Cribbed from Apple's DrawSprocket documentation;
108- // look for OpenGL function
109- return (_OGL_IsPresent = ((Ptr)aglChoosePixelFormat != (Ptr)kUnresolvedCFragSymbolAddress));
110- // return (_OGL_IsPresent = ((Ptr)glBegin != (Ptr)kUnresolvedCFragSymbolAddress));
111-#elif defined(SDL)
112- // nothing to do
113-#if defined(__WIN32__)
114-// glewInit();
115-#endif
116-
117- return _OGL_IsPresent = true;
118-#else
119-#error OGL_Initialize() not implemented for this platform
120-#endif
121-#else
122- return false;
123-#endif
124-}
125-
126-// Test for presence
127-bool OGL_IsPresent() {return _OGL_IsPresent;}
128-
129-bool OGL_CheckExtension(const std::string extension) {
130-#ifdef HAVE_OPENGL
131-#ifdef __WIN32__
132- return glewIsSupported(extension.c_str());
133-#else
134- char *extensions = (char *) glGetString(GL_EXTENSIONS);
135- if (!extensions) return false;
136-
137- while (*extensions)
138- {
139- unsigned int length = strcspn(extensions, " ");
140-
141- if (length == extension.size() &&
142- strncmp(extension.c_str(), extensions, length) == 0) {
143- return true;
144- }
145-
146- extensions += length + 1;
147- }
148-#endif
149-#endif
150- return false;
151-}
152-
153-static int ogl_progress;
154-static int total_ogl_progress;
155-static bool show_ogl_progress = false;
156-static int32 last_update_tick;
157-
158-extern bool OGL_ClearScreen();
159-
160-#ifdef HAVE_OPENGL
161-void OGL_StartProgress(int total_progress)
162-{
163- ogl_progress = 0;
164- total_ogl_progress = total_progress;
165- if (!OGL_LoadScreen::instance()->Start())
166- {
167- OGL_ClearScreen();
168- open_progress_dialog(_loading, true);
169- }
170- show_ogl_progress = true;
171- last_update_tick = SDL_GetTicks();
172-}
173-
174-void OGL_ProgressCallback(int delta_progress)
175-{
176- if (!show_ogl_progress) return;
177- ogl_progress += delta_progress;
178- {
179- int32 current_ticks = SDL_GetTicks();
180- if (current_ticks > last_update_tick + 33)
181- {
182- if (OGL_LoadScreen::instance()->Use())
183- OGL_LoadScreen::instance()->Progress(100 * ogl_progress / total_ogl_progress);
184- else
185- draw_progress_bar(ogl_progress, total_ogl_progress);
186- last_update_tick = current_ticks;
187- }
188- }
189-}
190-
191-void OGL_StopProgress()
192-{
193- show_ogl_progress = false;
194- if (OGL_LoadScreen::instance()->Use())
195- OGL_LoadScreen::instance()->Stop();
196- else
197- close_progress_dialog();
198-}
199-#endif
200-
201-// Sensible defaults for the fog:
202-static OGL_FogData FogData[OGL_NUMBER_OF_FOG_TYPES] =
203-{
204- {{0x8000,0x8000,0x8000},8,false,true},
205- {{0x8000,0x8000,0x8000},8,false,true}
206-};
207-
208-
209-// For flat landscapes:
210-const RGBColor DefaultLscpColors[4][2] =
211-{
212- {
213- {0xffff, 0xffff, 0x6666}, // Day
214- {0x3333, 0x9999, 0xffff},
215- },
216- {
217- {0x1818, 0x1818, 0x1010}, // Night
218- {0x0808, 0x0808, 0x1010},
219- },
220- {
221- {0x6666, 0x6666, 0x6666}, // Moon
222- {0x0000, 0x0000, 0x0000},
223- },
224- {
225- {0x0000, 0x0000, 0x0000}, // Outer Space
226- {0x0000, 0x0000, 0x0000},
227- },
228-};
229-
230-
231-// Set defaults
232-void OGL_SetDefaults(OGL_ConfigureData& Data)
233-{
234- for (int k=0; k<OGL_NUMBER_OF_TEXTURE_TYPES; k++)
235- {
236- OGL_Texture_Configure& TxtrData = Data.TxtrConfigList[k];
237- TxtrData.NearFilter = 1; // GL_LINEAR
238- if (k == OGL_Txtr_Wall || k == OGL_Txtr_Inhabitant)
239- TxtrData.FarFilter = 5; // GL_LINEAR_MIPMAP_LINEAR
240- else
241- TxtrData.FarFilter = 1; // GL_LINEAR
242- TxtrData.Resolution = 0; // 1x
243- TxtrData.ColorFormat = 0; // 32-bit color
244- TxtrData.MaxSize = 0; // Unlimited
245- }
246-
247- Data.ModelConfig.NearFilter = 1;
248- Data.ModelConfig.FarFilter = 5;
249- Data.ModelConfig.Resolution = 0;
250- Data.ModelConfig.ColorFormat = 0;
251- Data.ModelConfig.MaxSize = 0;
252-
253- // Reasonable default flags ("static" effect causes massive slowdown, so we turn it off)
254- Data.Flags = OGL_Flag_FlatStatic | OGL_Flag_Fader | OGL_Flag_Map |
255- OGL_Flag_HUD | OGL_Flag_LiqSeeThru | OGL_Flag_3D_Models | OGL_Flag_ZBuffer |
256- OGL_Flag_Fog;
257-
258- Data.AnisotropyLevel = 0.0; // off
259- Data.Multisamples = 0; // off
260-
261- Data.VoidColor = rgb_black; // Self-explanatory
262- for (int il=0; il<4; il++)
263- for (int ie=0; ie<2; ie++)
264- Data.LscpColors[il][ie] = DefaultLscpColors[il][ie];
265-
266- Data.GeForceFix = false;
267- Data.WaitForVSync = true;
268- Data.Use_sRGB = false;
269- Data.Use_NPOT = false;
270-}
271-
272-
273-inline bool StringPresent(vector<char>& String)
274-{
275- return (String.size() > 1);
276-}
277-
278-#ifdef HAVE_OPENGL
279-
280-GLint glMaxTextureSize = 0;
281-bool hasS3TC = false;
282-
283-void OGL_TextureOptionsBase::Load()
284-{
285- FileSpecifier File;
286-
287- GLint maxTextureSize = glMaxTextureSize;
288- if (GetMaxSize())
289- {
290- maxTextureSize = MIN(maxTextureSize, GetMaxSize());
291- }
292-
293- int flags = npotTextures ? 0 : ImageLoader_ResizeToPowersOfTwo;
294-
295- if (Type >= 0 && Type < OGL_NUMBER_OF_TEXTURE_TYPES && Get_OGL_ConfigureData().TxtrConfigList[Type].FarFilter > 1 /* GL_LINEAR */)
296- {
297- flags |= ImageLoader_LoadMipMaps;
298- }
299-
300- if (hasS3TC)
301- {
302- flags |= ImageLoader_CanUseDXTC;
303- }
304-
305- if (Get_OGL_ConfigureData().GeForceFix)
306- {
307- flags |= ImageLoader_LoadDXTC1AsDXTC3;
308- }
309-
310- // Load the normal image with alpha channel
311-
312- // Check to see if loading needs to be done;
313- // it does not need to be if an image is present.
314- if (NormalImg.IsPresent()) return;
315-
316- NormalImg.Clear();
317-
318- // Load the normal image if it has a filename specified for it
319- if (NormalColors != FileSpecifier() && NormalColors.Exists())
320- {
321- if (!NormalImg.LoadFromFile(NormalColors,ImageLoader_Colors, flags | (NormalIsPremultiplied ? ImageLoader_ImageIsAlreadyPremultiplied : 0), actual_width, actual_height, maxTextureSize))
322- {
323- // A texture must have a normal colored part
324- return;
325- }
326- }
327- else
328- {
329- return;
330- }
331-
332- // load a heightmap
333- if(OffsetMap != FileSpecifier() && OffsetMap.Exists()) {
334- if(!OffsetImg.LoadFromFile(OffsetMap, ImageLoader_Colors, flags | (NormalIsPremultiplied ? ImageLoader_ImageIsAlreadyPremultiplied : 0), actual_width, actual_height, maxTextureSize)) {
335- return;
336- }
337- }
338-
339- // Load the normal mask if it has a filename specified for it
340- if (NormalMask != FileSpecifier() && NormalMask.Exists())
341- {
342- NormalImg.LoadFromFile(NormalMask,ImageLoader_Opacity, flags, actual_width, actual_height, maxTextureSize);
343- }
344-
345- if (maxTextureSize)
346- {
347- while (NormalImg.GetWidth() > maxTextureSize || NormalImg.GetHeight() > maxTextureSize)
348- {
349- if (!NormalImg.Minify()) break;
350- }
351-
352- if(OffsetImg.IsPresent()) {
353- while (OffsetImg.GetWidth() > maxTextureSize || OffsetImg.GetHeight() > maxTextureSize) {
354- if(!OffsetImg.Minify()) { break; }
355- }
356- }
357- }
358-
359- // Load the glow image with alpha channel
360- if (!GlowImg.IsPresent())
361- {
362- GlowImg.Clear();
363-
364- // Load the glow image if it has a filename specified for it
365- if (GlowColors != FileSpecifier() && GlowColors.Exists())
366- {
367- if (GlowImg.LoadFromFile(GlowColors,ImageLoader_Colors, flags | (GlowIsPremultiplied ? ImageLoader_ImageIsAlreadyPremultiplied : 0), actual_width, actual_height, maxTextureSize))
368- {
369-
370- // Load the glow mask if it has a
371- // filename specified for it; only
372- // loaded if an image has been loaded
373- // for it
374- if (GlowMask != FileSpecifier() && GlowMask.Exists())
375- {
376- GlowImg.LoadFromFile(GlowMask,ImageLoader_Opacity, flags, actual_width, actual_height, maxTextureSize);
377- }
378- }
379- }
380- }
381-
382- if (GlowImg.IsPresent() && maxTextureSize)
383- {
384- while (GlowImg.GetWidth() > maxTextureSize || GlowImg.GetHeight() > maxTextureSize)
385- {
386- if (!GlowImg.Minify()) break;
387- }
388- }
389-
390- // The rest of the code is made simpler by these constraints:
391- // that the glow texture only be present if the normal texture is also present,
392- // and that the normal and glow textures have the same dimensions
393- if (NormalImg.IsPresent())
394- {
395- int W0 = NormalImg.GetWidth();
396- int W1 = GlowImg.GetWidth();
397- int H0 = NormalImg.GetHeight();
398- int H1 = GlowImg.GetHeight();
399- if ((W1 != W0) || (H1 != H0)) GlowImg.Clear();
400- }
401- else
402- {
403- GlowImg.Clear();
404- }
405-
406-}
407-
408-void OGL_TextureOptionsBase::Unload()
409-{
410- NormalImg.Clear();
411- GlowImg.Clear();
412- OffsetImg.Clear();
413-}
414-
415-int OGL_TextureOptionsBase::GetMaxSize()
416-{
417- if (Type >= 0 && Type < OGL_NUMBER_OF_TEXTURE_TYPES)
418- {
419- return Get_OGL_ConfigureData().TxtrConfigList[Type].MaxSize;
420- }
421- else
422- return 0; // Unlimited
423-}
424-#endif
425-
426-#ifdef HAVE_OPENGL
427-
428-int OGL_CountModelsImages(short Collection)
429-{
430- return OGL_CountTextures(Collection) + OGL_CountModels(Collection);
431-}
432-
433-// for managing the model and image loading and unloading
434-void OGL_LoadModelsImages(short Collection)
435-{
436- assert(Collection >= 0 && Collection < MAXIMUM_COLLECTIONS);
437-
438- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTextureSize);
439- hasS3TC = OGL_CheckExtension("GL_ARB_texture_compression") && OGL_CheckExtension("GL_EXT_texture_compression_s3tc");
440-
441- // For wall/sprite images
442- OGL_LoadTextures(Collection);
443-
444- // For models, skins
445- bool UseModels = TEST_FLAG(Get_OGL_ConfigureData().Flags,OGL_Flag_3D_Models) ? true : false;
446- if (UseModels)
447- OGL_LoadModels(Collection);
448- else
449- OGL_UnloadModels(Collection);
450-}
451-
452-void OGL_UnloadModelsImages(short Collection)
453-{
454- assert(Collection >= 0 && Collection < MAXIMUM_COLLECTIONS);
455-
456- // For wall/sprite images
457- OGL_UnloadTextures(Collection);
458-
459- // For models, skins
460- OGL_UnloadModels(Collection);
461-}
462-
463-#else
464-
465-void OGL_LoadModelsImages(short)
466-{
467-}
468-
469-void OGL_UnloadModelsImages(short)
470-{
471-}
472-
473-#endif // def HAVE_OPENGL
474-
475-
476-OGL_FogData *OGL_GetFogData(int Type)
477-{
478- return GetMemberWithBounds(FogData,Type,OGL_NUMBER_OF_FOG_TYPES);
479-}
480-
481-
482-// XML-parsing stuff
483-OGL_FogData *OriginalFogData = NULL;
484-class XML_FogParser: public XML_ElementParser
485-{
486- bool IsPresent[3];
487- bool FogPresent, AffectsLandscapes;
488- float Depth;
489- short Type;
490-
491-public:
492- bool Start();
493- bool HandleAttribute(const char *Tag, const char *Value);
494- bool AttributesDone();
495- bool ResetValues();
496-
497- XML_FogParser(): XML_ElementParser("fog") {}
498-};
499-
500-bool XML_FogParser::Start()
501-{
502- // back up old values first
503- if (!OriginalFogData) {
504- OriginalFogData = (OGL_FogData *) malloc(sizeof(OGL_FogData) * OGL_NUMBER_OF_FOG_TYPES);
505- assert(OriginalFogData);
506- for (unsigned i = 0; i < OGL_NUMBER_OF_FOG_TYPES; i++)
507- OriginalFogData[i] = FogData[i];
508- }
509-
510- IsPresent[0] = IsPresent[1] = IsPresent[2] = false;
511- Type = 0;
512- return true;
513-}
514-
515-bool XML_FogParser::HandleAttribute(const char *Tag, const char *Value)
516-{
517- if (StringsEqual(Tag,"on"))
518- {
519- if (ReadBooleanValueAsBool(Value,FogPresent))
520- {
521- IsPresent[0] = true;
522- return true;
523- }
524- else return false;
525- }
526- else if (StringsEqual(Tag,"depth"))
527- {
528- if (ReadFloatValue(Value,Depth))
529- {
530- IsPresent[1] = true;
531- return true;
532- }
533- else return false;
534- }
535- if (StringsEqual(Tag,"landscapes"))
536- {
537- if (ReadBooleanValueAsBool(Value,AffectsLandscapes))
538- {
539- IsPresent[2] = true;
540- return true;
541- }
542- else return false;
543- }
544- else if (StringsEqual(Tag,"type"))
545- {
546- return ReadBoundedInt16Value(Value,Type,0,OGL_NUMBER_OF_FOG_TYPES-1);
547- }
548- UnrecognizedTag();
549- return false;
550-}
551-
552-bool XML_FogParser::AttributesDone()
553-{
554- OGL_FogData& Data = FogData[Type];
555- if (IsPresent[0]) Data.IsPresent = FogPresent;
556- if (IsPresent[1]) Data.Depth = Depth;
557- if (IsPresent[2]) Data.AffectsLandscapes = AffectsLandscapes;
558- Color_SetArray(&Data.Color);
559- return true;
560-}
561-
562-bool XML_FogParser::ResetValues()
563-{
564- if (OriginalFogData) {
565- for (unsigned i = 0; i < OGL_NUMBER_OF_FOG_TYPES; i++)
566- FogData[i] = OriginalFogData[i];
567- free(OriginalFogData);
568- OriginalFogData = NULL;
569- }
570- return true;
571-}
572-
573-static XML_FogParser FogParser;
574-
575-static XML_ElementParser OpenGL_Parser("opengl");
576-
577-
578-// XML-parser support:
579-XML_ElementParser *OpenGL_GetParser()
580-{
581-#ifdef HAVE_OPENGL
582- OpenGL_Parser.AddChild(TextureOptions_GetParser());
583- OpenGL_Parser.AddChild(Shader_GetParser());
584- OpenGL_Parser.AddChild(TO_Clear_GetParser());
585-
586- OpenGL_Parser.AddChild(ModelData_GetParser());
587- OpenGL_Parser.AddChild(Mdl_Clear_GetParser());
588-#endif
589-
590- FogParser.AddChild(Color_GetParser());
591- OpenGL_Parser.AddChild(&FogParser);
592-
593- return &OpenGL_Parser;
594-}
595-
596-#ifdef HAVE_OPENGL
597-/* These don't belong here */
598-void SglColor3f(GLfloat r, GLfloat g, GLfloat b) {
599- GLfloat ov[3] = {sRGB_frob(r), sRGB_frob(g), sRGB_frob(b)};
600- glColor3fv(ov);
601-}
602-
603-void SglColor3fv(const GLfloat* iv) {
604- GLfloat ov[3] = {sRGB_frob(iv[0]), sRGB_frob(iv[1]), sRGB_frob(iv[2])};
605- glColor3fv(ov);
606-}
607-
608-void SglColor3ub(GLubyte r, GLubyte g, GLubyte b) {
609- GLfloat ov[3] = {sRGB_frob(r*(1.f/255.f)), sRGB_frob(g*(1.f/255.f)), sRGB_frob(b*(1.f/255.f))};
610- glColor3fv(ov);
611-}
612-
613-void SglColor3us(GLushort r, GLushort g, GLushort b) {
614- GLfloat ov[3] = {sRGB_frob(r*(1.f/65535.f)), sRGB_frob(g*(1.f/65535.f)), sRGB_frob(b*(1.f/65535.f))};
615- glColor3fv(ov);
616-}
617-
618-void SglColor3usv(const GLushort* iv) {
619- GLfloat ov[3] = {sRGB_frob(iv[0]*(1.f/65535.f)), sRGB_frob(iv[1]*(1.f/65535.f)), sRGB_frob(iv[2]*(1.f/65535.f))};
620- glColor3fv(ov);
621-}
622-
623-void SglColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
624- GLfloat ov[4] = {sRGB_frob(r), sRGB_frob(g), sRGB_frob(b), a};
625- glColor4fv(ov);
626-}
627-
628-void SglColor4fv(const GLfloat* iv) {
629- GLfloat ov[4] = {sRGB_frob(iv[0]), sRGB_frob(iv[1]), sRGB_frob(iv[2]), iv[3]};
630- glColor4fv(ov);
631-}
632-
633-void SglColor4usv(const GLushort* iv) {
634- GLfloat ov[4] = {sRGB_frob(iv[0]*(1.f/65535.f)), sRGB_frob(iv[1]*(1.f/65535.f)), sRGB_frob(iv[2]*(1.f/65535.f)), iv[3]*(1.f/65535.f)};
635- glColor4fv(ov);
636-}
637-#endif
1+/*
2+
3+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4+ and the "Aleph One" developers.
5+
6+ This program is free software; you can redistribute it and/or modify
7+ it under the terms of the GNU General Public License as published by
8+ the Free Software Foundation; either version 3 of the License, or
9+ (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU General Public License for more details.
15+
16+ This license is contained in the file "COPYING",
17+ which is included with this source code; it is available online at
18+ http://www.gnu.org/licenses/gpl.html
19+
20+ OpenGL Renderer,
21+ by Loren Petrich,
22+ March 12, 2000
23+
24+ This contains implementations of functions intended for finding out OpenGL's presence
25+ in the host system, for setting parameters for OpenGL rendering,
26+ and for deciding whether to use OpenGL for rendering.
27+
28+ June 11, 2000
29+
30+ Had added XML parsing before that; most recently, added "opac_shift".
31+
32+ Made semitransparency optional if the void is on one side of the texture
33+
34+Oct 13, 2000 (Loren Petrich)
35+ Converted the OpenGL-addition accounting into Standard Template Library vectors
36+
37+Nov 12, 2000 (Loren Petrich):
38+ Implemented texture substitution, also moved pixel-opacity editing into here;
39+ the code is carefully constructed to assume RGBA byte order whether integers are
40+ big- or little-endian.
41+
42+Nov 18, 2000 (Loren Petrich):
43+ Added support for glow mapping; constrained it to only be present
44+ when a normal texture is present, and to have the same size
45+
46+Nov 26, 2000 (Loren Petrich):
47+ Added system for reloading textures only when their filenames change.
48+
49+Dec 17, 2000 (Loren Petrich):
50+ Eliminated fog parameters from the preferences;
51+ there is still a "fog present" switch, which is used to indicate
52+ whether fog will not be suppressed.
53+
54+Apr 27, 2001 (Loren Petrich):
55+ Modified the OpenGL fog support so as to enable below-liquid fogs
56+
57+Jul 8, 2001 (Loren Petrich):
58+ Made it possible to read in silhouette bitmaps; one can now use the silhouette index
59+ as a MML color-table index
60+
61+Aug 21, 2001 (Loren Petrich):
62+ Adding support for 3D-model inhabitant objects
63+
64+Jan 25, 2002 (Br'fin (Jeremy Parsons)):
65+ Added TARGET_API_MAC_CARBON for OpenGL.h, AGL.h
66+ Removed QuickDraw3D support from Carbon
67+
68+Feb 5, 2002 (Br'fin (Jeremy Parsons)):
69+ Refined OGL default preferences for Carbon
70+*/
71+
72+#include <vector>
73+#include <string.h>
74+#include <math.h>
75+#include "cseries.h"
76+
77+#ifdef HAVE_OPENGL
78+
79+#ifdef __MVCPP__
80+#include <windows.h>
81+#endif
82+
83+#include "OGL_Headers.h"
84+#include "OGL_Shader.h"
85+
86+#endif
87+
88+#include "shape_descriptors.h"
89+#include "OGL_Setup.h"
90+#include "ColorParser.h"
91+#include "OGL_LoadScreen.h"
92+#include "progress.h"
93+
94+// Whether or not OpenGL is present and usable
95+static bool _OGL_IsPresent = false;
96+
97+bool Using_sRGB = false;
98+bool Wanting_sRGB = false;
99+bool Bloom_sRGB = false;
100+bool npotTextures = false; // non-power-of-two
101+
102+// Initializer
103+bool OGL_Initialize()
104+{
105+#ifdef HAVE_OPENGL
106+#if defined(mac)
107+ // Cribbed from Apple's DrawSprocket documentation;
108+ // look for OpenGL function
109+ return (_OGL_IsPresent = ((Ptr)aglChoosePixelFormat != (Ptr)kUnresolvedCFragSymbolAddress));
110+ // return (_OGL_IsPresent = ((Ptr)glBegin != (Ptr)kUnresolvedCFragSymbolAddress));
111+#elif defined(SDL)
112+ // nothing to do
113+#if defined(__WIN32__)
114+// glewInit();
115+#endif
116+
117+ return _OGL_IsPresent = true;
118+#else
119+#error OGL_Initialize() not implemented for this platform
120+#endif
121+#else
122+ return false;
123+#endif
124+}
125+
126+// Test for presence
127+bool OGL_IsPresent() {return _OGL_IsPresent;}
128+
129+bool OGL_CheckExtension(const std::string extension) {
130+#ifdef HAVE_OPENGL
131+#ifdef __WIN32__
132+ return glewIsSupported(extension.c_str());
133+#else
134+ char *extensions = (char *) glGetString(GL_EXTENSIONS);
135+ if (!extensions) return false;
136+
137+ while (*extensions)
138+ {
139+ unsigned int length = strcspn(extensions, " ");
140+
141+ if (length == extension.size() &&
142+ strncmp(extension.c_str(), extensions, length) == 0) {
143+ return true;
144+ }
145+
146+ extensions += length + 1;
147+ }
148+#endif
149+#endif
150+ return false;
151+}
152+
153+static int ogl_progress;
154+static int total_ogl_progress;
155+static bool show_ogl_progress = false;
156+static int32 last_update_tick;
157+
158+extern bool OGL_ClearScreen();
159+
160+#ifdef HAVE_OPENGL
161+void OGL_StartProgress(int total_progress)
162+{
163+ ogl_progress = 0;
164+ total_ogl_progress = total_progress;
165+ if (!OGL_LoadScreen::instance()->Start())
166+ {
167+ OGL_ClearScreen();
168+ open_progress_dialog(_loading, true);
169+ }
170+ show_ogl_progress = true;
171+ last_update_tick = SDL_GetTicks();
172+}
173+
174+void OGL_ProgressCallback(int delta_progress)
175+{
176+ if (!show_ogl_progress) return;
177+ ogl_progress += delta_progress;
178+ {
179+ int32 current_ticks = SDL_GetTicks();
180+ if (current_ticks > last_update_tick + 33)
181+ {
182+ if (OGL_LoadScreen::instance()->Use())
183+ OGL_LoadScreen::instance()->Progress(100 * ogl_progress / total_ogl_progress);
184+ else
185+ draw_progress_bar(ogl_progress, total_ogl_progress);
186+ last_update_tick = current_ticks;
187+ }
188+ }
189+}
190+
191+void OGL_StopProgress()
192+{
193+ show_ogl_progress = false;
194+ if (OGL_LoadScreen::instance()->Use())
195+ OGL_LoadScreen::instance()->Stop();
196+ else
197+ close_progress_dialog();
198+}
199+#endif
200+
201+// Sensible defaults for the fog:
202+static OGL_FogData FogData[OGL_NUMBER_OF_FOG_TYPES] =
203+{
204+ {{0x8000,0x8000,0x8000},8,false,true},
205+ {{0x8000,0x8000,0x8000},8,false,true}
206+};
207+
208+
209+// For flat landscapes:
210+const RGBColor DefaultLscpColors[4][2] =
211+{
212+ {
213+ {0xffff, 0xffff, 0x6666}, // Day
214+ {0x3333, 0x9999, 0xffff},
215+ },
216+ {
217+ {0x1818, 0x1818, 0x1010}, // Night
218+ {0x0808, 0x0808, 0x1010},
219+ },
220+ {
221+ {0x6666, 0x6666, 0x6666}, // Moon
222+ {0x0000, 0x0000, 0x0000},
223+ },
224+ {
225+ {0x0000, 0x0000, 0x0000}, // Outer Space
226+ {0x0000, 0x0000, 0x0000},
227+ },
228+};
229+
230+
231+// Set defaults
232+void OGL_SetDefaults(OGL_ConfigureData& Data)
233+{
234+ for (int k=0; k<OGL_NUMBER_OF_TEXTURE_TYPES; k++)
235+ {
236+ OGL_Texture_Configure& TxtrData = Data.TxtrConfigList[k];
237+ TxtrData.NearFilter = 1; // GL_LINEAR
238+ if (k == OGL_Txtr_Wall || k == OGL_Txtr_Inhabitant)
239+ TxtrData.FarFilter = 5; // GL_LINEAR_MIPMAP_LINEAR
240+ else
241+ TxtrData.FarFilter = 1; // GL_LINEAR
242+ TxtrData.Resolution = 0; // 1x
243+ TxtrData.ColorFormat = 0; // 32-bit color
244+ TxtrData.MaxSize = 0; // Unlimited
245+ }
246+
247+ Data.ModelConfig.NearFilter = 1;
248+ Data.ModelConfig.FarFilter = 5;
249+ Data.ModelConfig.Resolution = 0;
250+ Data.ModelConfig.ColorFormat = 0;
251+ Data.ModelConfig.MaxSize = 0;
252+
253+ // Reasonable default flags ("static" effect causes massive slowdown, so we turn it off)
254+ Data.Flags = OGL_Flag_FlatStatic | OGL_Flag_Fader | OGL_Flag_Map |
255+ OGL_Flag_HUD | OGL_Flag_LiqSeeThru | OGL_Flag_3D_Models | OGL_Flag_ZBuffer |
256+ OGL_Flag_Fog;
257+
258+ Data.AnisotropyLevel = 0.0; // off
259+ Data.Multisamples = 0; // off
260+
261+ Data.VoidColor = rgb_black; // Self-explanatory
262+ for (int il=0; il<4; il++)
263+ for (int ie=0; ie<2; ie++)
264+ Data.LscpColors[il][ie] = DefaultLscpColors[il][ie];
265+
266+ Data.GeForceFix = false;
267+ Data.WaitForVSync = true;
268+ Data.Use_sRGB = false;
269+ Data.Use_NPOT = false;
270+}
271+
272+
273+inline bool StringPresent(vector<char>& String)
274+{
275+ return (String.size() > 1);
276+}
277+
278+#ifdef HAVE_OPENGL
279+
280+GLint glMaxTextureSize = 0;
281+bool hasS3TC = false;
282+
283+void OGL_TextureOptionsBase::Load()
284+{
285+ FileSpecifier File;
286+
287+ GLint maxTextureSize = glMaxTextureSize;
288+ if (GetMaxSize())
289+ {
290+ maxTextureSize = MIN(maxTextureSize, GetMaxSize());
291+ }
292+
293+ int flags = npotTextures ? 0 : ImageLoader_ResizeToPowersOfTwo;
294+
295+ if (Type >= 0 && Type < OGL_NUMBER_OF_TEXTURE_TYPES && Get_OGL_ConfigureData().TxtrConfigList[Type].FarFilter > 1 /* GL_LINEAR */)
296+ {
297+ flags |= ImageLoader_LoadMipMaps;
298+ }
299+
300+ if (hasS3TC)
301+ {
302+ flags |= ImageLoader_CanUseDXTC;
303+ }
304+
305+ if (Get_OGL_ConfigureData().GeForceFix)
306+ {
307+ flags |= ImageLoader_LoadDXTC1AsDXTC3;
308+ }
309+
310+ // Load the normal image with alpha channel
311+
312+ // Check to see if loading needs to be done;
313+ // it does not need to be if an image is present.
314+ if (NormalImg.IsPresent()) return;
315+
316+ NormalImg.Clear();
317+
318+ // Load the normal image if it has a filename specified for it
319+ if (NormalColors != FileSpecifier() && NormalColors.Exists())
320+ {
321+ if (!NormalImg.LoadFromFile(NormalColors,ImageLoader_Colors, flags | (NormalIsPremultiplied ? ImageLoader_ImageIsAlreadyPremultiplied : 0), actual_width, actual_height, maxTextureSize))
322+ {
323+ // A texture must have a normal colored part
324+ return;
325+ }
326+ }
327+ else
328+ {
329+ return;
330+ }
331+
332+ // load a heightmap
333+ if(OffsetMap != FileSpecifier() && OffsetMap.Exists()) {
334+ if(!OffsetImg.LoadFromFile(OffsetMap, ImageLoader_Colors, flags | (NormalIsPremultiplied ? ImageLoader_ImageIsAlreadyPremultiplied : 0), actual_width, actual_height, maxTextureSize)) {
335+ return;
336+ }
337+ }
338+
339+ // Load the normal mask if it has a filename specified for it
340+ if (NormalMask != FileSpecifier() && NormalMask.Exists())
341+ {
342+ NormalImg.LoadFromFile(NormalMask,ImageLoader_Opacity, flags, actual_width, actual_height, maxTextureSize);
343+ }
344+
345+ if (maxTextureSize)
346+ {
347+ while (NormalImg.GetWidth() > maxTextureSize || NormalImg.GetHeight() > maxTextureSize)
348+ {
349+ if (!NormalImg.Minify()) break;
350+ }
351+
352+ if(OffsetImg.IsPresent()) {
353+ while (OffsetImg.GetWidth() > maxTextureSize || OffsetImg.GetHeight() > maxTextureSize) {
354+ if(!OffsetImg.Minify()) { break; }
355+ }
356+ }
357+ }
358+
359+ // Load the glow image with alpha channel
360+ if (!GlowImg.IsPresent())
361+ {
362+ GlowImg.Clear();
363+
364+ // Load the glow image if it has a filename specified for it
365+ if (GlowColors != FileSpecifier() && GlowColors.Exists())
366+ {
367+ if (GlowImg.LoadFromFile(GlowColors,ImageLoader_Colors, flags | (GlowIsPremultiplied ? ImageLoader_ImageIsAlreadyPremultiplied : 0), actual_width, actual_height, maxTextureSize))
368+ {
369+
370+ // Load the glow mask if it has a
371+ // filename specified for it; only
372+ // loaded if an image has been loaded
373+ // for it
374+ if (GlowMask != FileSpecifier() && GlowMask.Exists())
375+ {
376+ GlowImg.LoadFromFile(GlowMask,ImageLoader_Opacity, flags, actual_width, actual_height, maxTextureSize);
377+ }
378+ }
379+ }
380+ }
381+
382+ if (GlowImg.IsPresent() && maxTextureSize)
383+ {
384+ while (GlowImg.GetWidth() > maxTextureSize || GlowImg.GetHeight() > maxTextureSize)
385+ {
386+ if (!GlowImg.Minify()) break;
387+ }
388+ }
389+
390+ // The rest of the code is made simpler by these constraints:
391+ // that the glow texture only be present if the normal texture is also present,
392+ // and that the normal and glow textures have the same dimensions
393+ if (NormalImg.IsPresent())
394+ {
395+ int W0 = NormalImg.GetWidth();
396+ int W1 = GlowImg.GetWidth();
397+ int H0 = NormalImg.GetHeight();
398+ int H1 = GlowImg.GetHeight();
399+ if ((W1 != W0) || (H1 != H0)) GlowImg.Clear();
400+ }
401+ else
402+ {
403+ GlowImg.Clear();
404+ }
405+
406+}
407+
408+void OGL_TextureOptionsBase::Unload()
409+{
410+ NormalImg.Clear();
411+ GlowImg.Clear();
412+ OffsetImg.Clear();
413+}
414+
415+int OGL_TextureOptionsBase::GetMaxSize()
416+{
417+ if (Type >= 0 && Type < OGL_NUMBER_OF_TEXTURE_TYPES)
418+ {
419+ return Get_OGL_ConfigureData().TxtrConfigList[Type].MaxSize;
420+ }
421+ else
422+ return 0; // Unlimited
423+}
424+#endif
425+
426+#ifdef HAVE_OPENGL
427+
428+int OGL_CountModelsImages(short Collection)
429+{
430+ return OGL_CountTextures(Collection) + OGL_CountModels(Collection);
431+}
432+
433+// for managing the model and image loading and unloading
434+void OGL_LoadModelsImages(short Collection)
435+{
436+ assert(Collection >= 0 && Collection < MAXIMUM_COLLECTIONS);
437+
438+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTextureSize);
439+ hasS3TC = OGL_CheckExtension("GL_ARB_texture_compression") && OGL_CheckExtension("GL_EXT_texture_compression_s3tc");
440+
441+ // For wall/sprite images
442+ OGL_LoadTextures(Collection);
443+
444+ // For models, skins
445+ bool UseModels = TEST_FLAG(Get_OGL_ConfigureData().Flags,OGL_Flag_3D_Models) ? true : false;
446+ if (UseModels)
447+ OGL_LoadModels(Collection);
448+ else
449+ OGL_UnloadModels(Collection);
450+}
451+
452+void OGL_UnloadModelsImages(short Collection)
453+{
454+ assert(Collection >= 0 && Collection < MAXIMUM_COLLECTIONS);
455+
456+ // For wall/sprite images
457+ OGL_UnloadTextures(Collection);
458+
459+ // For models, skins
460+ OGL_UnloadModels(Collection);
461+}
462+
463+#else
464+
465+void OGL_LoadModelsImages(short)
466+{
467+}
468+
469+void OGL_UnloadModelsImages(short)
470+{
471+}
472+
473+#endif // def HAVE_OPENGL
474+
475+
476+OGL_FogData *OGL_GetFogData(int Type)
477+{
478+ return GetMemberWithBounds(FogData,Type,OGL_NUMBER_OF_FOG_TYPES);
479+}
480+
481+
482+// XML-parsing stuff
483+OGL_FogData *OriginalFogData = NULL;
484+class XML_FogParser: public XML_ElementParser
485+{
486+ bool IsPresent[3];
487+ bool FogPresent, AffectsLandscapes;
488+ float Depth;
489+ short Type;
490+
491+public:
492+ bool Start();
493+ bool HandleAttribute(const char *Tag, const char *Value);
494+ bool AttributesDone();
495+ bool ResetValues();
496+
497+ XML_FogParser(): XML_ElementParser("fog") {}
498+};
499+
500+bool XML_FogParser::Start()
501+{
502+ // back up old values first
503+ if (!OriginalFogData) {
504+ OriginalFogData = (OGL_FogData *) malloc(sizeof(OGL_FogData) * OGL_NUMBER_OF_FOG_TYPES);
505+ assert(OriginalFogData);
506+ for (unsigned i = 0; i < OGL_NUMBER_OF_FOG_TYPES; i++)
507+ OriginalFogData[i] = FogData[i];
508+ }
509+
510+ IsPresent[0] = IsPresent[1] = IsPresent[2] = false;
511+ Type = 0;
512+ return true;
513+}
514+
515+bool XML_FogParser::HandleAttribute(const char *Tag, const char *Value)
516+{
517+ if (StringsEqual(Tag,"on"))
518+ {
519+ if (ReadBooleanValueAsBool(Value,FogPresent))
520+ {
521+ IsPresent[0] = true;
522+ return true;
523+ }
524+ else return false;
525+ }
526+ else if (StringsEqual(Tag,"depth"))
527+ {
528+ if (ReadFloatValue(Value,Depth))
529+ {
530+ IsPresent[1] = true;
531+ return true;
532+ }
533+ else return false;
534+ }
535+ if (StringsEqual(Tag,"landscapes"))
536+ {
537+ if (ReadBooleanValueAsBool(Value,AffectsLandscapes))
538+ {
539+ IsPresent[2] = true;
540+ return true;
541+ }
542+ else return false;
543+ }
544+ else if (StringsEqual(Tag,"type"))
545+ {
546+ return ReadBoundedInt16Value(Value,Type,0,OGL_NUMBER_OF_FOG_TYPES-1);
547+ }
548+ UnrecognizedTag();
549+ return false;
550+}
551+
552+bool XML_FogParser::AttributesDone()
553+{
554+ OGL_FogData& Data = FogData[Type];
555+ if (IsPresent[0]) Data.IsPresent = FogPresent;
556+ if (IsPresent[1]) Data.Depth = Depth;
557+ if (IsPresent[2]) Data.AffectsLandscapes = AffectsLandscapes;
558+ Color_SetArray(&Data.Color);
559+ return true;
560+}
561+
562+bool XML_FogParser::ResetValues()
563+{
564+ if (OriginalFogData) {
565+ for (unsigned i = 0; i < OGL_NUMBER_OF_FOG_TYPES; i++)
566+ FogData[i] = OriginalFogData[i];
567+ free(OriginalFogData);
568+ OriginalFogData = NULL;
569+ }
570+ return true;
571+}
572+
573+static XML_FogParser FogParser;
574+
575+static XML_ElementParser OpenGL_Parser("opengl");
576+
577+
578+// XML-parser support:
579+XML_ElementParser *OpenGL_GetParser()
580+{
581+#ifdef HAVE_OPENGL
582+ OpenGL_Parser.AddChild(TextureOptions_GetParser());
583+ OpenGL_Parser.AddChild(Shader_GetParser());
584+ OpenGL_Parser.AddChild(TO_Clear_GetParser());
585+
586+ OpenGL_Parser.AddChild(ModelData_GetParser());
587+ OpenGL_Parser.AddChild(Mdl_Clear_GetParser());
588+#endif
589+
590+ FogParser.AddChild(Color_GetParser());
591+ OpenGL_Parser.AddChild(&FogParser);
592+
593+ return &OpenGL_Parser;
594+}
595+
596+#ifdef HAVE_OPENGL
597+/* These don't belong here */
598+void SglColor3f(GLfloat r, GLfloat g, GLfloat b) {
599+ GLfloat ov[3] = {sRGB_frob(r), sRGB_frob(g), sRGB_frob(b)};
600+ glColor3fv(ov);
601+}
602+
603+void SglColor3fv(const GLfloat* iv) {
604+ GLfloat ov[3] = {sRGB_frob(iv[0]), sRGB_frob(iv[1]), sRGB_frob(iv[2])};
605+ glColor3fv(ov);
606+}
607+
608+void SglColor3ub(GLubyte r, GLubyte g, GLubyte b) {
609+ GLfloat ov[3] = {sRGB_frob(r*(1.f/255.f)), sRGB_frob(g*(1.f/255.f)), sRGB_frob(b*(1.f/255.f))};
610+ glColor3fv(ov);
611+}
612+
613+void SglColor3us(GLushort r, GLushort g, GLushort b) {
614+ GLfloat ov[3] = {sRGB_frob(r*(1.f/65535.f)), sRGB_frob(g*(1.f/65535.f)), sRGB_frob(b*(1.f/65535.f))};
615+ glColor3fv(ov);
616+}
617+
618+void SglColor3usv(const GLushort* iv) {
619+ GLfloat ov[3] = {sRGB_frob(iv[0]*(1.f/65535.f)), sRGB_frob(iv[1]*(1.f/65535.f)), sRGB_frob(iv[2]*(1.f/65535.f))};
620+ glColor3fv(ov);
621+}
622+
623+void SglColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
624+ GLfloat ov[4] = {sRGB_frob(r), sRGB_frob(g), sRGB_frob(b), a};
625+ glColor4fv(ov);
626+}
627+
628+void SglColor4fv(const GLfloat* iv) {
629+ GLfloat ov[4] = {sRGB_frob(iv[0]), sRGB_frob(iv[1]), sRGB_frob(iv[2]), iv[3]};
630+ glColor4fv(ov);
631+}
632+
633+void SglColor4usv(const GLushort* iv) {
634+ GLfloat ov[4] = {sRGB_frob(iv[0]*(1.f/65535.f)), sRGB_frob(iv[1]*(1.f/65535.f)), sRGB_frob(iv[2]*(1.f/65535.f)), iv[3]*(1.f/65535.f)};
635+ glColor4fv(ov);
636+}
637+#endif
--- marathon/trunk/Source_Files/RenderMain/scottish_textures.cpp (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/scottish_textures.cpp (revision 530)
@@ -1,1396 +1,1396 @@
1-/*
2-SCOTTISH_TEXTURES.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-Wednesday, April 20, 1994 9:35:36 AM
22-
23-this is not your fatherユs texture mapping library.
24-(in fact it isnユt yours either, dillweed)
25-
26-Wednesday, April 20, 1994 3:39:21 PM
27- vertical repeats would be difficult because it would require testing repeats in the
28- innermost loop of the pixel mapper (a compare and branch we can do without).
29-Saturday, April 23, 1994 10:42:41 AM
30- (on the plane to santa clara) finished the slower version of the trapezoid mapper (we
31- need to handle stretching with a degenerate switch statement like marathon used to) but
32- the whole sampling process is now mathematically correct except for the squared function
33- we use to calculate the x texture position and the shading table (but this is accurate to
34- within 1/64k and doesn't accumulate error so who cares).
35-Sunday, April 24, 1994 10:12:47 AM
36- (waiting for the CGDC to start at 9:00 PST) added all polygon stuff. it struck me this
37- morning that clipping against the view cone must be deterministic (that is, line segments
38- of polygons and line segments of walls must be clipped in the same manner) or our
39- edges won't meet up. ordered dither darkening will look really cool but will be slow in c.
40-Sunday, April 24, 1994 11:21:47 PM
41- still need transparent trapezoids, dither darkening, faster DDA for trapezoid mapping.
42-Wednesday, April 27, 1994 9:49:55 AM
43- i'm just looking for one divine hammer (to bang it all day). solid polygons are currently
44- unaffected by darkening. i'm not entirely certain we'll even use them.
45-Sunday, May 8, 1994 8:32:11 AM
46- LISPユs lexical contours kick C firmly and painfully in the ass. everything is fast now
47- except the landscape mapper which has just been routed and is in full retreat.
48-Friday, May 13, 1994 10:05:08 AM
49- low-level unification of trapezoids and rectangles, transparent runs in shapes are run-length
50- encoded now. maintaining run tables was slower than generating d, delta_d and delta_d_prime
51- and using them on the fly.
52-Wednesday, May 18, 1994 2:16:26 PM
53- scope matters (at WWDC).
54-Sunday, May 22, 1994 12:32:02 PM
55- drawing things in column order to cached (i.e., non-screen) memory is like crapping in the
56- data cache, right? maybe drawing rectangles in column-order wasn't such a great idea after all.
57- it also occurs to me that i know nothing about how to order instructions for the ユ040 pipelines.
58-Thursday, June 16, 1994 9:56:14 PM
59- modified _render_textured_polygon_line to handle elevation.
60-Thursday, July 7, 1994 1:23:09 PM
61- changed MAXIMUM_SCRATCH_TABLE_ENTRIES from 4k to 1200. Modified render code to work as well,
62- now the problem is floor/ceiling matching with trapezoids, which should fall out with the
63- rewrite...
64-Tuesday, July 26, 1994 3:42:16 PM
65- OBSOLETEユed nearly the entire file (fixed_pixels are no more). rewriting texture_rectangle.
66- will do 16bit mapping, soon. a while ago i rewrote everything in 68k.
67-Friday, September 16, 1994 6:03:11 PM (Jason')
68- texture_rectangle() now respects top and bottom clips
69-Tuesday, September 20, 1994 9:58:30 PM (Jason')
70- if weユre so close to a rectangle that n>LARGEST_N then we donユt draw anything
71-Wednesday, October 26, 1994 3:18:59 PM (Jason)
72- for non-convex or otherwise weird lines (dx<=0, dy<=0) we donユt draw anything (somebodyユll
73- notice that for sure).
74-Friday, November 4, 1994 7:35:48 PM (Jason')
75- pretexture_horizontal_polygon_lines() now respects the (x,y) polygon origin and uses z as height.
76-
77-Jan 30, 2000 (Loren Petrich):
78- Added some typecasts
79-
80-Feb. 4, 2000 (Loren Petrich):
81- Changed halt() to assert(false) for better debugging
82-
83-Mar 24, 2000 (Loren Petrich):
84- Using a special "landscape yaw" for the landscape texturing, so that the landscape center
85- will stay put.
86-
87-May 23, 2000 (Loren Petrich):
88- Adding support for different size scales for landscapes
89-
90-Jul 6, 2000 (Loren Petrich):
91- Added some slop to MAXIMUM_SCRATCH_TABLE_ENTRIES, because displays are now bigger;
92- its size got upped by 2
93-
94-Aug 9, 2000 (Loren Petrich):
95- Rasterizer_SW object introduced (software subclass of rasterizer object)
96-
97-May 16, 2002 (Woody Zenfell):
98- MSVC doesn't like "void f(); void g() { return f(); }"... fixed.
99-*/
100-
101-/*
102-rectangle shrinking has vertical error and appears to randomly shear the bitmap
103-pretexture_horizontal_polygon_lines() has integer error in large height cases
104-
105-_static_transfer doesnユt work for ceilings and floors (because they call the wall mapper)
106-build_y_table and build_x_table could both be sped up in nearly-horizontal and nearly-vertical cases (respectively)
107-_pretexture_vertical_polygon_lines() takes up to half the time _texture_vertical_polygon_lines() does
108-not only that, but texture_horizontal_polygon() is actually faster than texture_vertical_polygon()
109-
110-//calculate_shading_table() needs to be inlined in a macro
111-*/
112-
113-#include "cseries.h"
114-#if defined(__GNUC__)
115-#ifndef DEBUG_FAST_CODE
116-#undef DEBUG
117-#undef assert
118-#define assert(x)
119-#undef vassert
120-#define vassert(x...)
121-#undef csprintf
122-#define csprintf(x...)
123-#undef vhalt
124-#define vhalt(x...)
125-#endif
126-#endif
127-#include "render.h"
128-#include "Rasterizer_SW.h"
129-
130-#include <stdlib.h>
131-#include <limits.h>
132-
133-#include "preferences.h"
134-#include "SW_Texture_Extras.h"
135-
136-
137-#ifdef env68k
138-#pragma segment texture
139-#endif
140-
141-#ifdef env68k
142-#define EXTERNAL
143-#endif
144-
145-/* ---------- constants */
146-
147-// LP change: boosted to cope with big displays
148-#define MAXIMUM_SCRATCH_TABLE_ENTRIES 2048
149-#define MAXIMUM_PRECALCULATION_TABLE_ENTRY_SIZE (MAX(sizeof(_vertical_polygon_data), sizeof(_horizontal_polygon_line_data)))
150-
151-#define SHADE_TO_SHADING_TABLE_INDEX(shade) ((shade)>>(FIXED_FRACTIONAL_BITS-shading_table_fractional_bits))
152-#define DEPTH_TO_SHADE(d) (((_fixed)(d))<<(FIXED_FRACTIONAL_BITS-WORLD_FRACTIONAL_BITS-3))
153-
154-#define LARGEST_N 24
155-
156-/* ---------- texture horizontal polygon */
157-
158-#define HORIZONTAL_WIDTH_SHIFT 7 /* 128 (8 for 256) */
159-#define HORIZONTAL_HEIGHT_SHIFT 7 /* 128 */
160-#define HORIZONTAL_FREE_BITS (32-TRIG_SHIFT-WORLD_FRACTIONAL_BITS)
161-#define HORIZONTAL_WIDTH_DOWNSHIFT (32-HORIZONTAL_WIDTH_SHIFT)
162-#define HORIZONTAL_HEIGHT_DOWNSHIFT (32-HORIZONTAL_HEIGHT_SHIFT)
163-
164-struct _horizontal_polygon_line_header
165-{
166- int32 y_downshift;
167-};
168-
169-struct _horizontal_polygon_line_data
170-{
171- uint32 source_x, source_y;
172- uint32 source_dx, source_dy;
173-
174- void *shading_table;
175-};
176-
177-/* ---------- texture vertical polygon */
178-
179-#define VERTICAL_TEXTURE_WIDTH 128
180-#define VERTICAL_TEXTURE_WIDTH_BITS 7
181-#define VERTICAL_TEXTURE_WIDTH_FRACTIONAL_BITS (FIXED_FRACTIONAL_BITS-VERTICAL_TEXTURE_WIDTH_BITS)
182-#define VERTICAL_TEXTURE_ONE (1<<VERTICAL_TEXTURE_WIDTH_FRACTIONAL_BITS)
183-#define VERTICAL_TEXTURE_FREE_BITS FIXED_FRACTIONAL_BITS
184-#define VERTICAL_TEXTURE_DOWNSHIFT (32-VERTICAL_TEXTURE_WIDTH_BITS)
185-
186-//AS: Seven! It's Everywhere!
187-#define HORIZONTAL_WIDTH_SHIFT 7 /* 128 (8 for 256) */
188-#define HORIZONTAL_HEIGHT_SHIFT 7 /* 128 */
189-#define HORIZONTAL_FREE_BITS (32-TRIG_SHIFT-WORLD_FRACTIONAL_BITS)
190-#define HORIZONTAL_WIDTH_DOWNSHIFT (32-HORIZONTAL_WIDTH_SHIFT)
191-#define HORIZONTAL_HEIGHT_DOWNSHIFT (32-HORIZONTAL_HEIGHT_SHIFT)
192-
193-struct _vertical_polygon_data
194-{
195- int16 downshift;
196- int16 x0;
197- int16 width;
198-
199- int16 pad;
200-};
201-
202-struct _vertical_polygon_line_data
203-{
204- void *shading_table;
205- pixel8 *texture;
206- int32 texture_y, texture_dy;
207-};
208-
209-/* ---------- macros */
210-
211-// i0 + i1 == MAX(i0, i1) + MIN(i0, i1)/2
212-//#define calculate_shading_table(result, view, shading_tables, depth, ambient_shade)
213-static void calculate_shading_table(void * &result,view_data *view, void *shading_tables, short depth,_fixed ambient_shade)
214-{
215- short table_index;
216- _fixed shade;
217-
218- if ((ambient_shade)<0)
219- {
220- table_index= SHADE_TO_SHADING_TABLE_INDEX(-(ambient_shade));
221- }
222- else
223- {
224- shade= (view)->maximum_depth_intensity - DEPTH_TO_SHADE(depth);
225- shade= PIN(shade, 0, FIXED_ONE);
226- table_index= SHADE_TO_SHADING_TABLE_INDEX((ambient_shade>shade) ? (ambient_shade + (shade>>1)) : (shade + (ambient_shade>>1)));
227- }
228-
229- switch (bit_depth)
230- {
231- case 8: result= ((byte*)(shading_tables)) + MAXIMUM_SHADING_TABLE_INDEXES*sizeof(pixel8)*
232- CEILING(table_index, number_of_shading_tables-1); break;
233- case 16: result= ((byte*)(shading_tables)) + MAXIMUM_SHADING_TABLE_INDEXES*sizeof(pixel16)*
234- CEILING(table_index, number_of_shading_tables-1); break;
235- case 32: result= ((byte*)(shading_tables)) + MAXIMUM_SHADING_TABLE_INDEXES*sizeof(pixel32)*
236- CEILING(table_index, number_of_shading_tables-1); break;
237- }
238-}
239-
240-/* ---------- globals */
241-
242-/* these tables are used by the polygon rasterizer (to store the x-coordinates of the left and
243- right lines of the current polygon), the trapezoid rasterizer (to store the y-coordinates
244- of the top and bottom of the current trapezoid) and the rectangle mapper (for itユs
245- vertical and if necessary horizontal distortion tables). these are not necessary as
246- globals, just as global storage. */
247-static short *scratch_table0 = NULL, *scratch_table1 = NULL;
248-static void *precalculation_table = NULL;
249-
250-static uint16 texture_random_seed= 6906;
251-
252-/* ---------- private prototypes */
253-
254-static void _pretexture_horizontal_polygon_lines(struct polygon_definition *polygon,
255- struct bitmap_definition *screen, struct view_data *view, struct _horizontal_polygon_line_data *data,
256- short y0, short *x0_table, short *x1_table, short line_count);
257-
258-static void _pretexture_vertical_polygon_lines(struct polygon_definition *polygon,
259- struct bitmap_definition *screen, struct view_data *view, struct _vertical_polygon_data *data,
260- short x0, short *y0_table, short *y1_table, short line_count);
261-
262-static short *build_x_table(short *table, short x0, short y0, short x1, short y1);
263-static short *build_y_table(short *table, short x0, short y0, short x1, short y1);
264-
265-static void _prelandscape_horizontal_polygon_lines(struct polygon_definition *polygon,
266- struct bitmap_definition *screen, struct view_data *view, struct _horizontal_polygon_line_data *data,
267- short y0, short *x0_table, short *x1_table, short line_count);
268-
269-/* ---------- code */
270-
271-
272-// LP addition:
273-// Find the next lower power of 2, and return the exponent
274-//AS: p isn't needed
275-inline int NextLowerExponent(int n)
276-{
277- int xp = 0;
278- while(n > 1) {n >>= 1; xp++;}
279- return xp;
280-}
281-
282-#include "low_level_textures.h"
283-
284-/* set aside memory at launch for two line tables (remember, we precalculate all the y-values
285- for trapezoids and two lines worth of x-values for polygons before mapping them) */
286-void allocate_texture_tables(
287- void)
288-{
289- scratch_table0= new short[MAXIMUM_SCRATCH_TABLE_ENTRIES];
290- scratch_table1= new short[MAXIMUM_SCRATCH_TABLE_ENTRIES];
291- precalculation_table= (void*)new char[MAXIMUM_PRECALCULATION_TABLE_ENTRY_SIZE*MAXIMUM_SCRATCH_TABLE_ENTRIES];
292- assert(scratch_table0&&scratch_table1&&precalculation_table);
293-}
294-
295-void Rasterizer_SW_Class::texture_horizontal_polygon(polygon_definition& textured_polygon)
296-{
297- polygon_definition *polygon = &textured_polygon; // Reference to pointer
298- short vertex, highest_vertex, lowest_vertex;
299- point2d *vertices= polygon->vertices;
300-
301- assert(polygon->vertex_count>=MINIMUM_VERTICES_PER_SCREEN_POLYGON&&polygon->vertex_count<MAXIMUM_VERTICES_PER_SCREEN_POLYGON);
302-
303- /* if we get static, tinted or landscaped transfer modes punt to the vertical polygon mapper */
304- if (polygon->transfer_mode == _static_transfer) {
305- texture_vertical_polygon(textured_polygon);
306- return;
307- }
308-
309- /* locate the vertically highest (closest to zero) and lowest (farthest from zero) vertices */
310- highest_vertex= lowest_vertex= 0;
311- for (vertex= 0; vertex<polygon->vertex_count; ++vertex)
312- {
313- if (!(vertices[vertex].x>=0&&vertices[vertex].x<=screen->width&&vertices[vertex].y>=0&&vertices[vertex].y<=screen->height))
314- {
315- // dprintf("vertex #%d/#%d out of bounds:;dm %x %x;g;", vertex, polygon->vertex_count, polygon->vertices, polygon->vertex_count*sizeof(point2d));
316- return;
317- }
318- if (vertices[vertex].y<vertices[highest_vertex].y) highest_vertex= vertex;
319- else if (vertices[vertex].y>vertices[lowest_vertex].y) lowest_vertex= vertex;
320- }
321-
322- /* if this polygon is not a horizontal line, draw it */
323- if (highest_vertex!=lowest_vertex)
324- {
325- short left_line_count, right_line_count, total_line_count;
326- short aggregate_left_line_count, aggregate_right_line_count, aggregate_total_line_count;
327- short left_vertex, right_vertex;
328- short *left_table= scratch_table0, *right_table= scratch_table1;
329-
330- left_line_count= right_line_count= 0; /* zero counts so the left and right lines get initialized */
331- aggregate_left_line_count= aggregate_right_line_count= 0; /* weユve precalculated nothing initially */
332- left_vertex= right_vertex= highest_vertex; /* both sides start at the highest vertex */
333- total_line_count= vertices[lowest_vertex].y-vertices[highest_vertex].y; /* calculate vertical line count */
334-
335- assert(total_line_count<MAXIMUM_SCRATCH_TABLE_ENTRIES); /* make sure we have enough scratch space */
336-
337- /* precalculate high and low y-coordinates for every x-coordinate */
338- aggregate_total_line_count= total_line_count;
339- while (total_line_count>0)
340- {
341-
342- /* if weユre out of scan lines on the left side, get a new vertex and build a table
343- of x-coordinates so we can walk toward the new vertex */
344- if (left_line_count<=0)
345- {
346- do /* counter-clockwise vertex search */
347- {
348- vertex= left_vertex ? (left_vertex-1) : (polygon->vertex_count-1);
349- left_line_count= vertices[vertex].y-vertices[left_vertex].y;
350- if (!build_x_table(left_table+aggregate_left_line_count, vertices[left_vertex].x, vertices[left_vertex].y, vertices[vertex].x, vertices[vertex].y)) return;
351- aggregate_left_line_count+= left_line_count;
352- left_vertex= vertex;
353-// dprintf("add %d left", left_line_count);
354- }
355- while (!left_line_count);
356- }
357-
358- /* if weユre out of scan lines on the right side, get a new vertex and build a table
359- of x-coordinates so we can walk toward the new vertex */
360- if (right_line_count<=0)
361- {
362- do /* clockwise vertex search */
363- {
364- vertex= (right_vertex==polygon->vertex_count-1) ? 0 : (right_vertex+1);
365- right_line_count= vertices[vertex].y-vertices[right_vertex].y;
366- if (!build_x_table(right_table+aggregate_right_line_count, vertices[right_vertex].x, vertices[right_vertex].y, vertices[vertex].x, vertices[vertex].y)) return;
367- aggregate_right_line_count+= right_line_count;
368- right_vertex= vertex;
369-// dprintf("add %d right", right_line_count);
370- }
371- while (!right_line_count);
372- }
373- //AS: moving delta declaration up to where it's needed. Isn't C++ wonderful?
374- /* advance by the minimum of left_line_count and right_line_count */
375- short delta= MIN(left_line_count, right_line_count);
376- assert(delta);
377-// dprintf("tc=%d lc=%d rc=%d delta=%d", total_line_count, left_line_count, right_line_count, delta);
378- total_line_count-= delta;
379- left_line_count-= delta;
380- right_line_count-= delta;
381-
382- assert(delta||!total_line_count); /* if our delta is zero, weユd better be out of lines */
383- }
384-
385- /* make sure every coordinate is accounted for in our tables */
386- assert(aggregate_right_line_count==aggregate_total_line_count);
387- assert(aggregate_left_line_count==aggregate_total_line_count);
388-
389- /* precalculate mode-specific data */
390- switch (polygon->transfer_mode)
391- {
392- case _textured_transfer:
393- _pretexture_horizontal_polygon_lines(polygon, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
394- vertices[highest_vertex].y, left_table, right_table,
395- aggregate_total_line_count);
396- break;
397-
398- case _big_landscaped_transfer:
399- _prelandscape_horizontal_polygon_lines(polygon, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
400- vertices[highest_vertex].y, left_table, right_table,
401- aggregate_total_line_count);
402- break;
403-
404- default:
405- vhalt(csprintf(temporary, "horizontal_polygons dont support mode #%d", polygon->transfer_mode));
406- }
407-
408- /* render all lines */
409- switch (bit_depth)
410- {
411- case 8:
412- switch (polygon->transfer_mode)
413- {
414-
415- case _textured_transfer:
416- texture_horizontal_polygon_lines<pixel8, _sw_alpha_off>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
417- vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
418- break;
419- case _big_landscaped_transfer:
420- landscape_horizontal_polygon_lines<pixel8>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
421- vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
422- break;
423-
424- default:
425- assert(false);
426- break;
427- }
428- break;
429-
430- case 16:
431- switch (polygon->transfer_mode)
432- {
433- case _textured_transfer:
434- {
435- SW_Texture *sw_texture = 0;
436- if (graphics_preferences->software_alpha_blending)
437- {
438- sw_texture = SW_Texture_Extras::instance()->GetTexture(polygon->ShapeDesc);
439- }
440- if (sw_texture && !polygon->VoidPresent && sw_texture->opac_type())
441- {
442- if (graphics_preferences->software_alpha_blending == _sw_alpha_fast) {
443- texture_horizontal_polygon_lines<pixel16, _sw_alpha_fast>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table, vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
444- }
445- else if (graphics_preferences->software_alpha_blending == _sw_alpha_nice) {
446- texture_horizontal_polygon_lines<pixel16, _sw_alpha_nice>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *) precalculation_table, vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count, sw_texture->opac_table());
447- }
448- } else {
449- texture_horizontal_polygon_lines<pixel16, _sw_alpha_off>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
450- vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
451- }
452- }
453- break;
454-
455- case _big_landscaped_transfer:
456- landscape_horizontal_polygon_lines<pixel16>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
457- vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
458- break;
459- default:
460- assert(false);
461- break;
462- }
463- break;
464-
465- case 32:
466- switch (polygon->transfer_mode)
467- {
468- case _textured_transfer:
469- {
470- SW_Texture *sw_texture = 0;
471- if (graphics_preferences->software_alpha_blending)
472- {
473- sw_texture = SW_Texture_Extras::instance()->GetTexture(polygon->ShapeDesc);
474- }
475- if (sw_texture && sw_texture->opac_type() && !polygon->VoidPresent)
476- {
477- if (graphics_preferences->software_alpha_blending == _sw_alpha_fast)
478- {
479- texture_horizontal_polygon_lines<pixel32, _sw_alpha_fast>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table, vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
480- }
481- else if (graphics_preferences->software_alpha_blending = _sw_alpha_nice)
482- {
483- texture_horizontal_polygon_lines<pixel32, _sw_alpha_nice>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *) precalculation_table, vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count, sw_texture->opac_table());
484- }
485- }
486- else
487- {
488- texture_horizontal_polygon_lines<pixel32, _sw_alpha_off>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
489- vertices[highest_vertex].y, left_table, right_table,
490- aggregate_total_line_count);
491- }
492- }
493- break;
494- case _big_landscaped_transfer:
495- landscape_horizontal_polygon_lines<pixel32>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
496- vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
497- break;
498-
499- default:
500- assert(false);
501- break;
502- }
503- break;
504-
505- default:
506- assert(false);
507- break;
508- }
509- }
510-}
511-
512-void Rasterizer_SW_Class::texture_vertical_polygon(polygon_definition& textured_polygon)
513-{
514- polygon_definition *polygon = &textured_polygon; // Reference to pointer
515- short vertex, highest_vertex, lowest_vertex;
516- point2d *vertices= polygon->vertices;
517-
518- assert(polygon->vertex_count>=MINIMUM_VERTICES_PER_SCREEN_POLYGON&&polygon->vertex_count<MAXIMUM_VERTICES_PER_SCREEN_POLYGON);
519-
520- if (polygon->transfer_mode == _big_landscaped_transfer) {
521- texture_horizontal_polygon(textured_polygon);
522- return;
523- }
524-
525- /* locate the horizontally highest (closest to zero) and lowest (farthest from zero) vertices */
526- highest_vertex= lowest_vertex= 0;
527- for (vertex=1;vertex<polygon->vertex_count;++vertex)
528- {
529- if (vertices[vertex].x<vertices[highest_vertex].x) highest_vertex= vertex;
530- if (vertices[vertex].x>vertices[lowest_vertex].x) lowest_vertex= vertex;
531- }
532-
533- for (vertex=0;vertex<polygon->vertex_count;++vertex)
534- {
535- if (!(vertices[vertex].x>=0&&vertices[vertex].x<=screen->width&&vertices[vertex].y>=0&&vertices[vertex].y<=screen->height))
536- {
537-// dprintf("vertex #%d/#%d out of bounds:;dm %x %x;g;", vertex, polygon->vertex_count, polygon->vertices, polygon->vertex_count*sizeof(point2d));
538- return;
539- }
540- }
541-
542- /* if this polygon is not a vertical line, draw it */
543- if (highest_vertex!=lowest_vertex)
544- {
545- short left_line_count, right_line_count, total_line_count;
546- short aggregate_left_line_count, aggregate_right_line_count, aggregate_total_line_count;
547- short left_vertex, right_vertex;
548- short *left_table= scratch_table0, *right_table= scratch_table1;
549-
550- left_line_count= right_line_count= 0; /* zero counts so the left and right lines get initialized */
551- aggregate_left_line_count= aggregate_right_line_count= 0; /* weユve precalculated nothing initially */
552- left_vertex= right_vertex= highest_vertex; /* both sides start at the highest vertex */
553- total_line_count= vertices[lowest_vertex].x-vertices[highest_vertex].x; /* calculate vertical line count */
554-
555- assert(total_line_count<MAXIMUM_SCRATCH_TABLE_ENTRIES); /* make sure we have enough scratch space */
556-
557- /* precalculate high and low y-coordinates for every x-coordinate */
558- aggregate_total_line_count= total_line_count;
559- while (total_line_count>0)
560- {
561- /* if weユre out of scan lines on the left side, get a new vertex and build a table
562- of y-coordinates so we can walk toward the new vertex */
563- if (left_line_count<=0)
564- {
565- do /* clockwise vertex search */
566- {
567- vertex= (left_vertex==polygon->vertex_count-1) ? 0 : (left_vertex+1);
568- left_line_count= vertices[vertex].x-vertices[left_vertex].x;
569-// dprintf("left line (%d,%d) to (%d,%d) for %d points", vertices[left_vertex].x, vertices[left_vertex].y, vertices[vertex].x, vertices[vertex].y, left_line_count);
570- if (!build_y_table(left_table+aggregate_left_line_count, vertices[left_vertex].x, vertices[left_vertex].y, vertices[vertex].x, vertices[vertex].y)) return;
571- aggregate_left_line_count+= left_line_count;
572- left_vertex= vertex;
573- }
574- while (!left_line_count);
575- }
576-
577- /* if weユre out of scan lines on the right side, get a new vertex and build a table
578- of y-coordinates so we can walk toward the new vertex */
579- if (right_line_count<=0)
580- {
581- do /* counter-clockwise vertex search */
582- {
583- vertex= right_vertex ? (right_vertex-1) : (polygon->vertex_count-1);
584- right_line_count= vertices[vertex].x-vertices[right_vertex].x;
585-// dprintf("right line (%d,%d) to (%d,%d) for %d points", vertices[right_vertex].x, vertices[right_vertex].y, vertices[vertex].x, vertices[vertex].y, right_line_count);
586- if (!build_y_table(right_table+aggregate_right_line_count, vertices[right_vertex].x, vertices[right_vertex].y, vertices[vertex].x, vertices[vertex].y)) return;
587- aggregate_right_line_count+= right_line_count;
588- right_vertex= vertex;
589- }
590- while (!right_line_count);
591- }
592-
593- /* advance by the minimum of left_line_count and right_line_count */
594- short delta= MIN(left_line_count, right_line_count);
595- assert(delta);
596- total_line_count-= delta;
597- left_line_count-= delta;
598- right_line_count-= delta;
599-
600- assert(delta||!total_line_count); /* if our delta is zero, weユd better be out of lines */
601- }
602-
603- /* make sure every coordinate is accounted for in our tables */
604- assert(aggregate_right_line_count==aggregate_total_line_count);
605- assert(aggregate_left_line_count==aggregate_total_line_count);
606-
607- /* precalculate mode-specific data */
608-
609- if ((polygon->transfer_mode == _textured_transfer) || (polygon->transfer_mode == _static_transfer))
610- {
611- _pretexture_vertical_polygon_lines(polygon, screen, view, (struct _vertical_polygon_data *)precalculation_table, vertices[highest_vertex].x, left_table, right_table, aggregate_total_line_count);
612- }
613- else vhalt(csprintf(temporary, "vertical_polygons dont support mode #%d", polygon->transfer_mode));
614-
615- /* render all lines */
616- switch (bit_depth)
617- {
618- case 8:
619- switch (polygon->transfer_mode)
620- {
621- case _textured_transfer:
622- if (polygon->texture->flags&_TRANSPARENT_BIT)
623- texture_vertical_polygon_lines<pixel8, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
624- else
625- texture_vertical_polygon_lines<pixel8, _sw_alpha_off, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
626- break;
627- case _static_transfer:
628- if (polygon->texture->flags&_TRANSPARENT_BIT)
629- randomize_vertical_polygon_lines<pixel8, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
630- else
631- randomize_vertical_polygon_lines<pixel8, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
632- break;
633-
634- default:
635- assert(false);
636- break;
637- }
638- break;
639-
640- case 16:
641- switch (polygon->transfer_mode)
642- {
643- case _textured_transfer:
644- {
645- SW_Texture *sw_texture =0 ;
646- if (graphics_preferences->software_alpha_blending)
647- {
648- sw_texture = SW_Texture_Extras::instance()->GetTexture(polygon->ShapeDesc);
649- }
650- if (sw_texture && !polygon->VoidPresent && sw_texture->opac_type())
651- {
652- if (graphics_preferences->software_alpha_blending == _sw_alpha_fast) {
653- if (polygon->texture->flags & _TRANSPARENT_BIT) {
654- texture_vertical_polygon_lines<pixel16, _sw_alpha_fast, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
655- } else {
656- texture_vertical_polygon_lines<pixel16, _sw_alpha_fast, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
657- }
658- }
659- else if (graphics_preferences->software_alpha_blending == _sw_alpha_nice) {
660- if (polygon->texture->flags & _TRANSPARENT_BIT) {
661- texture_vertical_polygon_lines<pixel16, _sw_alpha_nice, true>(screen, view, (struct _vertical_polygon_data *) precalculation_table, left_table, right_table, sw_texture->opac_table());
662- } else {
663- texture_vertical_polygon_lines<pixel16, _sw_alpha_nice, false>(screen, view, (struct _vertical_polygon_data *) precalculation_table, left_table, right_table, sw_texture->opac_table());
664- }
665- }
666- } else {
667- if (polygon->texture->flags & _TRANSPARENT_BIT) {
668- texture_vertical_polygon_lines<pixel16, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
669- } else {
670- texture_vertical_polygon_lines<pixel16, _sw_alpha_off, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
671- }
672- }
673- }
674- break;
675- case _static_transfer:
676- if (polygon->texture->flags & _TRANSPARENT_BIT) {
677- randomize_vertical_polygon_lines<pixel16, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
678- } else {
679- randomize_vertical_polygon_lines<pixel16, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
680- }
681- break;
682- default:
683- assert(false);
684- break;
685- }
686- break;
687-
688- case 32:
689- switch (polygon->transfer_mode)
690- {
691- case _textured_transfer:
692- {
693- SW_Texture *sw_texture = 0;
694- if (graphics_preferences->software_alpha_blending)
695- {
696- sw_texture = SW_Texture_Extras::instance()->GetTexture(polygon->ShapeDesc);
697- }
698- if (sw_texture && !polygon->VoidPresent && sw_texture->opac_type())
699- {
700- if (graphics_preferences->software_alpha_blending == _sw_alpha_fast) {
701- if (polygon->texture->flags&_TRANSPARENT_BIT)
702- texture_vertical_polygon_lines<pixel32, _sw_alpha_fast, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
703- else
704- texture_vertical_polygon_lines<pixel32, _sw_alpha_fast, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
705- }
706- else if (graphics_preferences->software_alpha_blending == _sw_alpha_nice)
707- {
708- if (polygon->texture->flags & _TRANSPARENT_BIT)
709- texture_vertical_polygon_lines<pixel32, _sw_alpha_nice, true>(screen, view, (struct _vertical_polygon_data *) precalculation_table, left_table, right_table, sw_texture->opac_table());
710- else
711- texture_vertical_polygon_lines<pixel32, _sw_alpha_nice, false>(screen, view, (struct _vertical_polygon_data *) precalculation_table, left_table, right_table, sw_texture->opac_table());
712- }
713- } else {
714- if (polygon->texture->flags & _TRANSPARENT_BIT)
715- texture_vertical_polygon_lines<pixel32, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
716- else
717- texture_vertical_polygon_lines<pixel32, _sw_alpha_off, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
718- }
719- break;
720- }
721- case _static_transfer:
722- if (polygon->texture->flags & _TRANSPARENT_BIT)
723- randomize_vertical_polygon_lines<pixel32, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
724- else
725- randomize_vertical_polygon_lines<pixel32, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
726- break;
727-
728- default:
729- assert(false);
730- break;
731- }
732- break;
733-
734- default:
735- assert(false);
736- break;
737- }
738- }
739-}
740-
741-void Rasterizer_SW_Class::texture_rectangle(rectangle_definition& textured_rectangle)
742-{
743- rectangle_definition *rectangle = &textured_rectangle; // Reference to pointer
744-
745- if (rectangle->x0<rectangle->x1 && rectangle->y0<rectangle->y1)
746- {
747- /* subsume screen boundaries into clipping parameters */
748- if (rectangle->clip_left<0) rectangle->clip_left= 0;
749- if (rectangle->clip_right>screen->width) rectangle->clip_right= screen->width;
750- if (rectangle->clip_top<0) rectangle->clip_top= 0;
751- if (rectangle->clip_bottom>screen->height) rectangle->clip_bottom= screen->height;
752-
753- /* subsume left and right sides of the rectangle into clipping parameters */
754- if (rectangle->clip_left<rectangle->x0) rectangle->clip_left= rectangle->x0;
755- if (rectangle->clip_right>rectangle->x1) rectangle->clip_right= rectangle->x1;
756- if (rectangle->clip_top<rectangle->y0) rectangle->clip_top= rectangle->y0;
757- if (rectangle->clip_bottom>rectangle->y1) rectangle->clip_bottom= rectangle->y1;
758-
759- /* only continue if we have a non-empty rectangle, at least some of which is on the screen */
760- if (rectangle->clip_left<rectangle->clip_right && rectangle->clip_top<rectangle->clip_bottom &&
761- rectangle->clip_right>0 && rectangle->clip_left<screen->width &&
762- rectangle->clip_bottom>0 && rectangle->clip_top<screen->height)
763- {
764- short delta; /* scratch */
765- short screen_width= rectangle->x1-rectangle->x0;
766- short screen_height= rectangle->y1-rectangle->y0;
767- short screen_x= rectangle->x0;
768- struct bitmap_definition *texture= rectangle->texture;
769-
770- short *y0_table= scratch_table0, *y1_table= scratch_table1;
771- struct _vertical_polygon_data *header= (struct _vertical_polygon_data *)precalculation_table;
772- struct _vertical_polygon_line_data *data= (struct _vertical_polygon_line_data *) (header+1);
773-
774- _fixed texture_dx= INTEGER_TO_FIXED(texture->width)/screen_width;
775- _fixed texture_x= texture_dx>>1;
776-
777- _fixed texture_dy= INTEGER_TO_FIXED(texture->height)/screen_height;
778- _fixed texture_y0= 0;
779- _fixed texture_y1;
780-
781- if (texture_dx&&texture_dy)
782- {
783- /* handle horizontal mirroring */
784- if (rectangle->flip_horizontal)
785- {
786- texture_dx= -texture_dx;
787- texture_x= INTEGER_TO_FIXED(texture->width)+(texture_dx>>1);
788- }
789-
790- /* left clipping */
791- if ((delta= rectangle->clip_left-rectangle->x0)>0)
792- {
793- texture_x+= delta*texture_dx;
794- screen_width-= delta;
795- screen_x= rectangle->clip_left;
796- }
797- /* right clipping */
798- if ((delta= rectangle->x1-rectangle->clip_right)>0)
799- {
800- screen_width-= delta;
801- }
802-
803- /* top clipping */
804- if ((delta= rectangle->clip_top-rectangle->y0)>0)
805- {
806- texture_y0+= delta*texture_dy;
807- screen_height-= delta;
808- }
809-
810- /* bottom clipping */
811- if ((delta= rectangle->y1-rectangle->clip_bottom)>0)
812- {
813- screen_height-= delta;
814- }
815-
816- texture_y1= texture_y0 + screen_height*texture_dy;
817-
818- header->downshift= FIXED_FRACTIONAL_BITS;
819- header->width= screen_width;
820- header->x0= screen_x;
821-
822- /* calculate shading table, once */
823- void *shading_table = NULL;
824- switch (rectangle->transfer_mode)
825- {
826- case _textured_transfer:
827- if (!(rectangle->flags&_SHADELESS_BIT))
828- {
829- // LP change:
830- // Made this more long-distance friendly
831- calculate_shading_table(shading_table, view, rectangle->shading_tables, (short)MIN(rectangle->depth, SHRT_MAX), rectangle->ambient_shade);
832- break;
833- }
834- /* if shadeless, fall through to a single shading table, ignoring depth */
835- case _tinted_transfer:
836- case _static_transfer:
837- shading_table= rectangle->shading_tables;
838- break;
839-
840- default:
841- vhalt(csprintf(temporary, "rectangles dont support mode #%d", rectangle->transfer_mode));
842- }
843-
844- for (; screen_width; --screen_width)
845- {
846- byte *read= texture->row_addresses[FIXED_INTEGERAL_PART(texture_x)];
847- // CB: first/last are stored in big-endian order
848- uint16 first = *read++ << 8;
849- first |= *read++;
850- uint16 last = *read++ << 8;
851- last |= *read++;
852- _fixed texture_y= texture_y0;
853- short y0= rectangle->clip_top, y1= rectangle->clip_bottom;
854-
855- if (FIXED_INTEGERAL_PART(texture_y0)<first)
856- {
857- delta= (INTEGER_TO_FIXED(first) - texture_y0)/texture_dy + 1;
858- vassert(delta>=0, csprintf(temporary, "[%x,%x] カ=%x (#%d,#%d)", texture_y0, texture_y1, texture_dy, first, last));
859-
860- y0= MIN(y1, y0+delta);
861- texture_y+= delta*texture_dy;
862- }
863-
864- if (FIXED_INTEGERAL_PART(texture_y1)>last)
865- {
866- delta= (texture_y1 - INTEGER_TO_FIXED(last))/texture_dy + 1;
867- vassert(delta>=0, csprintf(temporary, "[%x,%x] カ=%x (#%d,#%d)", texture_y0, texture_y1, texture_dy, first, last));
868-
869- y1= MAX(y0, y1-delta);
870- }
871-
872- data->texture_y= texture_y - INTEGER_TO_FIXED(first);
873- data->texture_dy= texture_dy;
874- data->shading_table= shading_table;
875- data->texture= (unsigned char *)read;
876-
877- texture_x+= texture_dx;
878- data+= 1;
879-
880- *y0_table++= y0;
881- *y1_table++= y1;
882-
883- assert(y0<=y1);
884- assert(y0>=0 && y1>=0);
885- assert(y0<=screen->height);
886- assert(y1<=screen->height);
887- }
888-
889- switch (bit_depth)
890- {
891- case 8:
892- switch (rectangle->transfer_mode)
893- {
894- case _textured_transfer:
895- texture_vertical_polygon_lines<pixel8, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
896- scratch_table0, scratch_table1);
897- break;
898-
899- case _static_transfer:
900- randomize_vertical_polygon_lines<pixel8, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
901- scratch_table0, scratch_table1, rectangle->transfer_data);
902- break;
903-
904- case _tinted_transfer:
905- tint_vertical_polygon_lines<pixel8>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
906- scratch_table0, scratch_table1, rectangle->transfer_data);
907- break;
908-
909- default:
910- assert(false);
911- break;
912- }
913- break;
914-
915- case 16:
916- switch (rectangle->transfer_mode)
917- {
918- case _textured_transfer:
919- texture_vertical_polygon_lines<pixel16, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, scratch_table0, scratch_table1);
920- break;
921-
922- case _static_transfer:
923- randomize_vertical_polygon_lines<pixel16, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
924- scratch_table0, scratch_table1, rectangle->transfer_data);
925- break;
926-
927- case _tinted_transfer:
928- tint_vertical_polygon_lines<pixel16>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
929- scratch_table0, scratch_table1, rectangle->transfer_data);
930- break;
931-
932- default:
933- assert(false);
934- break;
935- }
936- break;
937-
938- case 32:
939- switch (rectangle->transfer_mode)
940- {
941- case _textured_transfer:
942- texture_vertical_polygon_lines<pixel32, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
943- scratch_table0, scratch_table1);
944- break;
945-
946- case _static_transfer:
947- randomize_vertical_polygon_lines<pixel32, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
948- scratch_table0, scratch_table1, rectangle->transfer_data);
949- break;
950-
951- case _tinted_transfer:
952- tint_vertical_polygon_lines<pixel32>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
953- scratch_table0, scratch_table1, rectangle->transfer_data);
954- break;
955-
956- default:
957- assert(false);
958- break;
959- }
960- break;
961-
962- default:
963- assert(false);
964- break;
965- }
966- }
967- }
968- }
969-}
970-
971-/* ---------- private code */
972-
973-#if 0
974-
975-#define LANDSCAPE_REPEATS 12
976-static void preprocess_landscaped_polygon(
977- struct polygon_definition *polygon,
978- struct view_data *view)
979-{
980- polygon->origin.x= (world_distance) ((10000*LANDSCAPE_REPEATS*WORLD_ONE)/(2*31415));
981- polygon->origin.y= -(((LANDSCAPE_REPEATS*WORLD_ONE*view->yaw)>>ANGULAR_BITS)&(WORLD_ONE-1));
982- polygon->origin.z= 0;
983-
984- polygon->vector.i= 0;
985- polygon->vector.j= WORLD_ONE;
986- polygon->vector.k= -WORLD_ONE;
987-
988- polygon->ambient_shade= FIXED_ONE;
989-}
990-
991-#endif
992-
993-/* starting at x0 and for line_count vertical lines between *y0 and *y1, precalculate all the
994- information _texture_vertical_polygon_lines will need to work */
995-static void _pretexture_vertical_polygon_lines(
996- struct polygon_definition *polygon,
997- struct bitmap_definition *screen,
998- struct view_data *view,
999- struct _vertical_polygon_data *data,
1000- short x0,
1001- short *y0_table,
1002- short *y1_table,
1003- short line_count)
1004-{
1005- short screen_x= x0-view->half_screen_width;
1006- int32 dz0= view->world_to_screen_y*polygon->origin.z;
1007- int32 unadjusted_ty_denominator= view->world_to_screen_y*polygon->vector.k;
1008- int32 tx_numerator, tx_denominator, tx_numerator_delta, tx_denominator_delta;
1009- struct _vertical_polygon_line_data *line= (struct _vertical_polygon_line_data *) (data+1);
1010-
1011- (void) (screen);
1012-
1013- assert(sizeof(struct _vertical_polygon_line_data)<=MAXIMUM_PRECALCULATION_TABLE_ENTRY_SIZE);
1014-
1015- data->downshift= VERTICAL_TEXTURE_DOWNSHIFT;
1016- data->x0= x0;
1017- data->width= line_count;
1018-
1019- /* calculate and rescale tx_numerator, tx_denominator, etc. */
1020- tx_numerator= view->world_to_screen_x*polygon->origin.y - screen_x*polygon->origin.x;
1021- tx_denominator= screen_x*polygon->vector.i - view->world_to_screen_x*polygon->vector.j;
1022- tx_numerator_delta= -polygon->origin.x;
1023- tx_denominator_delta= polygon->vector.i;
1024-
1025- while (--line_count>=0)
1026- {
1027- _fixed tx;
1028- // LP change: made this quantity more long-distance friendly;
1029- // have to avoid doing INTEGER_TO_FIXED on this one, however
1030- int32 world_x;
1031- short x0, y0= *y0_table++;
1032- short screen_y0= view->half_screen_height-y0+view->dtanpitch;
1033- int32 ty_numerator, ty_denominator;
1034- _fixed ty, ty_delta;
1035-
1036- /* would our precision be greater here if we shifted the numerator up to $7FFFFFFF and
1037- then downshifted only the numerator? too bad we canユt use BFFFO in 68k */
1038- {
1039- int32 adjusted_tx_denominator= tx_denominator;
1040- int32 adjusted_tx_numerator= tx_numerator;
1041-
1042- while (adjusted_tx_numerator>((1<<(31-VERTICAL_TEXTURE_WIDTH_BITS))-1) ||
1043- adjusted_tx_numerator<((-1)<<(31-VERTICAL_TEXTURE_WIDTH_BITS)))
1044- {
1045- adjusted_tx_numerator>>= 1, adjusted_tx_denominator>>= 1;
1046- }
1047- if (!adjusted_tx_denominator) adjusted_tx_denominator= 1; /* -1 will still be -1 */
1048- x0= ((adjusted_tx_numerator<<VERTICAL_TEXTURE_WIDTH_BITS)/adjusted_tx_denominator)&(VERTICAL_TEXTURE_WIDTH-1);
1049-
1050- while (adjusted_tx_numerator>INT16_MAX||adjusted_tx_numerator<INT16_MIN)
1051- {
1052- adjusted_tx_numerator>>= 1, adjusted_tx_denominator>>= 1;
1053- }
1054- if (!adjusted_tx_denominator) adjusted_tx_denominator= 1; /* -1 will still be -1 */
1055- tx= INTEGER_TO_FIXED(adjusted_tx_numerator)/adjusted_tx_denominator;
1056- }
1057-
1058- world_x= polygon->origin.x + ((tx*polygon->vector.i)>>FIXED_FRACTIONAL_BITS);
1059- if (world_x<0) world_x= -world_x; /* it is mostly unclear what weユre supposed to do with negative x values */
1060-
1061- /* calculate and rescale ty_numerator, ty_denominator and calculate ty */
1062- ty_numerator= world_x*screen_y0 - dz0;
1063- ty_denominator= unadjusted_ty_denominator;
1064- while (ty_numerator>INT16_MAX||ty_numerator<INT16_MIN)
1065- {
1066- ty_numerator>>= 1, ty_denominator>>= 1;
1067- }
1068- if (!ty_denominator) ty_denominator= 1; /* -1 will still be -1 */
1069- ty= INTEGER_TO_FIXED(ty_numerator)/ty_denominator;
1070-
1071- // LP change:
1072- // Use the same reduction hack used earlier,
1073- // because otherwise, INTEGER_TO_FIXED would cause world_x to wrap around.
1074- int32 adjusted_world_x = world_x;
1075- int32 adjusted_ty_denominator = unadjusted_ty_denominator>>8;
1076-
1077- // LP: remember that world_x is always >= 0
1078- while(adjusted_world_x > INT16_MAX)
1079- {
1080- adjusted_world_x >>= 1; adjusted_ty_denominator >>= 1;
1081- }
1082- if (!adjusted_ty_denominator) adjusted_ty_denominator= 1; /* -1 will still be -1 */
1083- ty_delta= - INTEGER_TO_FIXED(adjusted_world_x)/adjusted_ty_denominator;
1084-
1085- vassert(ty_delta>=0, csprintf(temporary, "ty_delta=W2F(%d)/%d=%d", world_x, unadjusted_ty_denominator, ty_delta));
1086-
1087- /* calculate the shading table for this column */
1088- if (polygon->flags&_SHADELESS_BIT)
1089- {
1090- line->shading_table= polygon->shading_tables;
1091- }
1092- else
1093- {
1094- // LP change: made this more long-distance friendly
1095- calculate_shading_table(line->shading_table, view, polygon->shading_tables, (short)MIN(world_x, SHRT_MAX), polygon->ambient_shade);
1096- // calculate_shading_table(line->shading_table, view, polygon->shading_tables, world_x, polygon->ambient_shade);
1097- }
1098-
1099-// if (ty_delta)
1100- {
1101- /* calculate texture_y and texture_dy (floor-mapper style) */
1102-// data->n= VERTICAL_TEXTURE_DOWNSHIFT;
1103- line->texture_y= ty<<VERTICAL_TEXTURE_FREE_BITS;
1104- line->texture_dy= ty_delta<<(VERTICAL_TEXTURE_FREE_BITS-8);
1105- line->texture= polygon->texture->row_addresses[x0];
1106-
1107- line+= 1;
1108- }
1109-
1110- tx_numerator+= tx_numerator_delta;
1111- tx_denominator+= tx_denominator_delta;
1112-
1113- screen_x+= 1;
1114- }
1115-}
1116-
1117-static void _pretexture_horizontal_polygon_lines(
1118- struct polygon_definition *polygon,
1119- struct bitmap_definition *screen,
1120- struct view_data *view,
1121- struct _horizontal_polygon_line_data *data,
1122- short y0,
1123- short *x0_table,
1124- short *x1_table,
1125- short line_count)
1126-{
1127- int32 hcosine, dhcosine;
1128- int32 hsine, dhsine;
1129- int32 hworld_to_screen;
1130- bool higher_precision= polygon->origin.z>-WORLD_ONE && polygon->origin.z<WORLD_ONE;
1131-
1132- (void) (screen);
1133-
1134- /* precalculate a bunch of multiplies */
1135- hcosine= cosine_table[view->yaw];
1136- hsine= sine_table[view->yaw];
1137- if (higher_precision)
1138- {
1139- hcosine*= polygon->origin.z;
1140- hsine*= polygon->origin.z;
1141- }
1142- hworld_to_screen= polygon->origin.z*view->world_to_screen_y;
1143- dhcosine= view->world_to_screen_y*hcosine;
1144- dhsine= view->world_to_screen_y*hsine;
1145-
1146- while ((line_count-=1)>=0)
1147- {
1148- // LP change: made this more long-distance-friendly
1149- int32 depth;
1150- // world_distance depth;
1151- short screen_x, screen_y;
1152- short x0= *x0_table++;
1153-
1154- /* calculate screen_x,screen_y */
1155- screen_x= x0-view->half_screen_width;
1156- screen_y= view->half_screen_height-y0+view->dtanpitch;
1157- if (!screen_y) screen_y= 1; /* this will avoid division by zero and won't change rendering */
1158-
1159- /* calculate source_x, source_y, source_dx, source_dy */
1160-
1161- int32 source_x, source_y, source_dx, source_dy;
1162-
1163- /* calculate texture origins and deltas (source_x,source_dx,source_y,source_dy) */
1164- if (higher_precision)
1165- {
1166- source_x= (dhcosine - screen_x*hsine)/screen_y + (polygon->origin.x<<TRIG_SHIFT);
1167- source_dx= - hsine/screen_y;
1168- source_y= (screen_x*hcosine + dhsine)/screen_y + (polygon->origin.y<<TRIG_SHIFT);
1169- source_dy= hcosine/screen_y;
1170- }
1171- else
1172- {
1173- source_x= ((dhcosine - screen_x*hsine)/screen_y)*polygon->origin.z + (polygon->origin.x<<TRIG_SHIFT);
1174- source_dx= - (hsine*polygon->origin.z)/screen_y;
1175- source_y= ((screen_x*hcosine + dhsine)/screen_y)*polygon->origin.z + (polygon->origin.y<<TRIG_SHIFT);
1176- source_dy= (hcosine*polygon->origin.z)/screen_y;
1177- }
1178-
1179- /* voodoo so x,y texture wrapping is handled automatically by downshifting
1180- (subtract one from HORIZONTAL_FREE_BITS to double scale) */
1181- data->source_x= source_x<<HORIZONTAL_FREE_BITS, data->source_dx= source_dx<<HORIZONTAL_FREE_BITS;
1182- data->source_y= source_y<<HORIZONTAL_FREE_BITS, data->source_dy= source_dy<<HORIZONTAL_FREE_BITS;
1183-
1184-
1185- /* get shading table (with absolute value of depth) */
1186- if ((depth= hworld_to_screen/screen_y)<0) depth= -depth;
1187- if (polygon->flags&_SHADELESS_BIT)
1188- {
1189- data->shading_table= polygon->shading_tables;
1190- }
1191- else
1192- {
1193- calculate_shading_table(data->shading_table, view, polygon->shading_tables, (short)MIN(depth, SHRT_MAX), polygon->ambient_shade);
1194- }
1195-
1196- data++;
1197- y0++;
1198- }
1199-}
1200-
1201-
1202-// height must be determined emperically (texture is vertically centered at 0。)
1203-// #define LANDSCAPE_REPEAT_BITS 1
1204-static void _prelandscape_horizontal_polygon_lines(
1205- struct polygon_definition *polygon,
1206- struct bitmap_definition *screen,
1207- struct view_data *view,
1208- struct _horizontal_polygon_line_data *data,
1209- short y0,
1210- short *x0_table,
1211- short *x1_table,
1212- short line_count)
1213-{
1214- // LP change: made this more general:
1215- short landscape_width_bits= NextLowerExponent(polygon->texture->height);
1216- short texture_height= polygon->texture->width;
1217- _fixed ambient_shade= FIXED_ONE; // MPW C died if we passed the constant directly to the macro
1218-
1219- // Get the landscape-texturing options
1220- LandscapeOptions *LandOpts = View_GetLandscapeOptions(polygon->ShapeDesc);
1221-
1222- // LP change: separate horizontal and vertical pixel deltas:
1223- // LP change: using a "landscape yaw" that's at the left edge of the screen.
1224- _fixed first_horizontal_pixel= (view->landscape_yaw + LandOpts->Azimuth)<<(landscape_width_bits+(LandOpts->HorizExp)+FIXED_FRACTIONAL_BITS-ANGULAR_BITS);
1225- _fixed horizontal_pixel_delta= (view->half_cone<<(1+landscape_width_bits+(LandOpts->HorizExp)+FIXED_FRACTIONAL_BITS-ANGULAR_BITS))/view->standard_screen_width;
1226- _fixed vertical_pixel_delta= (view->half_cone<<(1+landscape_width_bits+(LandOpts->VertExp)+FIXED_FRACTIONAL_BITS-ANGULAR_BITS))/view->standard_screen_width;
1227- short landscape_free_bits= 32-FIXED_FRACTIONAL_BITS-landscape_width_bits;
1228-
1229- (void) (screen);
1230-
1231- /* calculate the shading table */
1232- void *shading_table = NULL;
1233- if (polygon->flags&_SHADELESS_BIT)
1234- {
1235- shading_table= polygon->shading_tables;
1236- }
1237- else
1238- {
1239- calculate_shading_table(shading_table, view, polygon->shading_tables, 0, ambient_shade);
1240- }
1241-
1242- // Find the height to repeat over; use value used for OpenGL texture setup
1243- short texture_width= polygon->texture->height;
1244- short repeat_texture_height = texture_width >> LandOpts->OGL_AspRatExp;
1245-
1246- short height_reduced = texture_height - 1;
1247- short height_shift = texture_height >> 1;
1248- short height_repeat_mask = repeat_texture_height - 1;
1249- short height_repeat_shift = repeat_texture_height >> 1;
1250-
1251- y0-= view->half_screen_height + view->dtanpitch; /* back to virtual screen coordinates */
1252- while ((line_count-= 1)>=0)
1253- {
1254- short x0= *x0_table++;
1255-
1256- data->shading_table= shading_table;
1257- // LP change: using vertical pixel delta
1258- // Also using vertical repeat if selected;
1259- // fold the height into the range (-repeat_height/2, repeat_height)
1260- short y_txtr_offset= FIXED_INTEGERAL_PART(y0*vertical_pixel_delta);
1261- if (LandOpts->VertRepeat)
1262- y_txtr_offset = ((y_txtr_offset + height_repeat_shift) & height_repeat_mask) -
1263- height_repeat_shift;
1264- data->source_y= texture_height - PIN(y_txtr_offset + height_shift, 0, height_reduced) - 1;
1265- // LP change: using horizontal pixel delta
1266- data->source_x= (first_horizontal_pixel + x0*horizontal_pixel_delta)<<landscape_free_bits;
1267- data->source_dx= horizontal_pixel_delta<<landscape_free_bits;
1268-
1269- data+= 1;
1270- y0+= 1;
1271- }
1272-}
1273-
1274-/* y0<y1; this is for vertical polygons */
1275-static short *build_x_table(
1276- short *table,
1277- short x0,
1278- short y0,
1279- short x1,
1280- short y1)
1281-{
1282- short dx, dy, adx, ady; /* 'a' prefix means absolute value */
1283- short x, y; /* x,y screen positions */
1284- short d, delta_d, d_max; /* descriminator, delta_descriminator, descriminator_maximum */
1285- short *record;
1286-
1287- /* calculate SGN(dx),SGN(dy) and the absolute values of dx,dy */
1288- dx= x1-x0, adx= ABS(dx), dx= SGN(dx);
1289- dy= y1-y0, ady= ABS(dy), dy= SGN(dy);
1290-
1291- assert(ady<MAXIMUM_SCRATCH_TABLE_ENTRIES); /* can't overflow table */
1292- if (dy>0)
1293- {
1294- /* setup initial (x,y) location and initialize a pointer to our table */
1295- x= x0, y= y0;
1296- record= table;
1297-
1298- if (adx>=ady)
1299- {
1300- /* x-dominant line (we need to record x every time y changes) */
1301-
1302- d= adx-ady, delta_d= - 2*ady, d_max= 2*adx;
1303- while ((adx-=1)>=0)
1304- {
1305- if (d<0) y+= 1, d+= d_max, *record++= x, ady-= 1;
1306- x+= dx, d+= delta_d;
1307- }
1308- if (ady==1) *record++= x; else assert(!ady);
1309- }
1310- else
1311- {
1312- /* y-dominant line (we need to record x every iteration) */
1313-
1314- d= ady-adx, delta_d= - 2*adx, d_max= 2*ady;
1315- while ((ady-=1)>=0)
1316- {
1317- if (d<0) x+= dx, d+= d_max;
1318- *record++= x;
1319- y+= 1, d+= delta_d;
1320- }
1321- }
1322- }
1323- else
1324- {
1325- /* canユt build a table for negative dy */
1326- if (dy<0) return NULL;
1327- }
1328-
1329- return table;
1330-}
1331-
1332-/* x0<x1; this is for horizontal polygons */
1333-static short *build_y_table(
1334- short *table,
1335- short x0,
1336- short y0,
1337- short x1,
1338- short y1)
1339-{
1340- short dx, dy, adx, ady; /* 'a' prefix means absolute value */
1341- short x, y; /* x,y screen positions */
1342- short d, delta_d, d_max; /* descriminator, delta_descriminator, descriminator_maximum */
1343- short *record;
1344-
1345- /* calculate SGN(dx),SGN(dy) and the absolute values of dx,dy */
1346- dx= x1-x0, adx= ABS(dx), dx= SGN(dx);
1347- dy= y1-y0, ady= ABS(dy), dy= SGN(dy);
1348-
1349- assert(adx<MAXIMUM_SCRATCH_TABLE_ENTRIES); /* can't overflow table */
1350- if (dx>=0) /* vertical lines allowed */
1351- {
1352- /* setup initial (x,y) location and initialize a pointer to our table */
1353- if (dy>=0)
1354- {
1355- x= x0, y= y0;
1356- record= table;
1357- }
1358- else
1359- {
1360- x= x1, y= y1;
1361- record= table+adx;
1362- }
1363-
1364- if (adx>=ady)
1365- {
1366- /* x-dominant line (we need to record y every iteration) */
1367-
1368- d= adx-ady, delta_d= - 2*ady, d_max= 2*adx;
1369- while ((adx-=1)>=0)
1370- {
1371- if (d<0) y+= 1, d+= d_max;
1372- if (dy>=0) *record++= y; else *--record= y;
1373- x+= dx, d+= delta_d;
1374- }
1375- }
1376- else
1377- {
1378- /* y-dominant line (we need to record y every time x changes) */
1379-
1380- d= ady-adx, delta_d= - 2*adx, d_max= 2*ady;
1381- while ((ady-=1)>=0)
1382- {
1383- if (d<0) { x+= dx, d+= d_max, adx-= 1; if (dy>=0) *record++= y; else *--record= y; }
1384- y+= 1, d+= delta_d;
1385- }
1386- if (adx==1) if (dy>=0) *record++= y; else *--record= y; else assert(!adx);
1387- }
1388- }
1389- else
1390- {
1391- /* canユt build a table for a negative dx */
1392- return NULL;
1393- }
1394-
1395- return table;
1396-}
1+/*
2+SCOTTISH_TEXTURES.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+Wednesday, April 20, 1994 9:35:36 AM
22+
23+this is not your fatherユs texture mapping library.
24+(in fact it isnユt yours either, dillweed)
25+
26+Wednesday, April 20, 1994 3:39:21 PM
27+ vertical repeats would be difficult because it would require testing repeats in the
28+ innermost loop of the pixel mapper (a compare and branch we can do without).
29+Saturday, April 23, 1994 10:42:41 AM
30+ (on the plane to santa clara) finished the slower version of the trapezoid mapper (we
31+ need to handle stretching with a degenerate switch statement like marathon used to) but
32+ the whole sampling process is now mathematically correct except for the squared function
33+ we use to calculate the x texture position and the shading table (but this is accurate to
34+ within 1/64k and doesn't accumulate error so who cares).
35+Sunday, April 24, 1994 10:12:47 AM
36+ (waiting for the CGDC to start at 9:00 PST) added all polygon stuff. it struck me this
37+ morning that clipping against the view cone must be deterministic (that is, line segments
38+ of polygons and line segments of walls must be clipped in the same manner) or our
39+ edges won't meet up. ordered dither darkening will look really cool but will be slow in c.
40+Sunday, April 24, 1994 11:21:47 PM
41+ still need transparent trapezoids, dither darkening, faster DDA for trapezoid mapping.
42+Wednesday, April 27, 1994 9:49:55 AM
43+ i'm just looking for one divine hammer (to bang it all day). solid polygons are currently
44+ unaffected by darkening. i'm not entirely certain we'll even use them.
45+Sunday, May 8, 1994 8:32:11 AM
46+ LISPユs lexical contours kick C firmly and painfully in the ass. everything is fast now
47+ except the landscape mapper which has just been routed and is in full retreat.
48+Friday, May 13, 1994 10:05:08 AM
49+ low-level unification of trapezoids and rectangles, transparent runs in shapes are run-length
50+ encoded now. maintaining run tables was slower than generating d, delta_d and delta_d_prime
51+ and using them on the fly.
52+Wednesday, May 18, 1994 2:16:26 PM
53+ scope matters (at WWDC).
54+Sunday, May 22, 1994 12:32:02 PM
55+ drawing things in column order to cached (i.e., non-screen) memory is like crapping in the
56+ data cache, right? maybe drawing rectangles in column-order wasn't such a great idea after all.
57+ it also occurs to me that i know nothing about how to order instructions for the ユ040 pipelines.
58+Thursday, June 16, 1994 9:56:14 PM
59+ modified _render_textured_polygon_line to handle elevation.
60+Thursday, July 7, 1994 1:23:09 PM
61+ changed MAXIMUM_SCRATCH_TABLE_ENTRIES from 4k to 1200. Modified render code to work as well,
62+ now the problem is floor/ceiling matching with trapezoids, which should fall out with the
63+ rewrite...
64+Tuesday, July 26, 1994 3:42:16 PM
65+ OBSOLETEユed nearly the entire file (fixed_pixels are no more). rewriting texture_rectangle.
66+ will do 16bit mapping, soon. a while ago i rewrote everything in 68k.
67+Friday, September 16, 1994 6:03:11 PM (Jason')
68+ texture_rectangle() now respects top and bottom clips
69+Tuesday, September 20, 1994 9:58:30 PM (Jason')
70+ if weユre so close to a rectangle that n>LARGEST_N then we donユt draw anything
71+Wednesday, October 26, 1994 3:18:59 PM (Jason)
72+ for non-convex or otherwise weird lines (dx<=0, dy<=0) we donユt draw anything (somebodyユll
73+ notice that for sure).
74+Friday, November 4, 1994 7:35:48 PM (Jason')
75+ pretexture_horizontal_polygon_lines() now respects the (x,y) polygon origin and uses z as height.
76+
77+Jan 30, 2000 (Loren Petrich):
78+ Added some typecasts
79+
80+Feb. 4, 2000 (Loren Petrich):
81+ Changed halt() to assert(false) for better debugging
82+
83+Mar 24, 2000 (Loren Petrich):
84+ Using a special "landscape yaw" for the landscape texturing, so that the landscape center
85+ will stay put.
86+
87+May 23, 2000 (Loren Petrich):
88+ Adding support for different size scales for landscapes
89+
90+Jul 6, 2000 (Loren Petrich):
91+ Added some slop to MAXIMUM_SCRATCH_TABLE_ENTRIES, because displays are now bigger;
92+ its size got upped by 2
93+
94+Aug 9, 2000 (Loren Petrich):
95+ Rasterizer_SW object introduced (software subclass of rasterizer object)
96+
97+May 16, 2002 (Woody Zenfell):
98+ MSVC doesn't like "void f(); void g() { return f(); }"... fixed.
99+*/
100+
101+/*
102+rectangle shrinking has vertical error and appears to randomly shear the bitmap
103+pretexture_horizontal_polygon_lines() has integer error in large height cases
104+
105+_static_transfer doesnユt work for ceilings and floors (because they call the wall mapper)
106+build_y_table and build_x_table could both be sped up in nearly-horizontal and nearly-vertical cases (respectively)
107+_pretexture_vertical_polygon_lines() takes up to half the time _texture_vertical_polygon_lines() does
108+not only that, but texture_horizontal_polygon() is actually faster than texture_vertical_polygon()
109+
110+//calculate_shading_table() needs to be inlined in a macro
111+*/
112+
113+#include "cseries.h"
114+#if defined(__GNUC__)
115+#ifndef DEBUG_FAST_CODE
116+#undef DEBUG
117+#undef assert
118+#define assert(x)
119+#undef vassert
120+#define vassert(x...)
121+#undef csprintf
122+#define csprintf(x...)
123+#undef vhalt
124+#define vhalt(x...)
125+#endif
126+#endif
127+#include "render.h"
128+#include "Rasterizer_SW.h"
129+
130+#include <stdlib.h>
131+#include <limits.h>
132+
133+#include "preferences.h"
134+#include "SW_Texture_Extras.h"
135+
136+
137+#ifdef env68k
138+#pragma segment texture
139+#endif
140+
141+#ifdef env68k
142+#define EXTERNAL
143+#endif
144+
145+/* ---------- constants */
146+
147+// LP change: boosted to cope with big displays
148+#define MAXIMUM_SCRATCH_TABLE_ENTRIES 2048
149+#define MAXIMUM_PRECALCULATION_TABLE_ENTRY_SIZE (MAX(sizeof(_vertical_polygon_data), sizeof(_horizontal_polygon_line_data)))
150+
151+#define SHADE_TO_SHADING_TABLE_INDEX(shade) ((shade)>>(FIXED_FRACTIONAL_BITS-shading_table_fractional_bits))
152+#define DEPTH_TO_SHADE(d) (((_fixed)(d))<<(FIXED_FRACTIONAL_BITS-WORLD_FRACTIONAL_BITS-3))
153+
154+#define LARGEST_N 24
155+
156+/* ---------- texture horizontal polygon */
157+
158+#define HORIZONTAL_WIDTH_SHIFT 7 /* 128 (8 for 256) */
159+#define HORIZONTAL_HEIGHT_SHIFT 7 /* 128 */
160+#define HORIZONTAL_FREE_BITS (32-TRIG_SHIFT-WORLD_FRACTIONAL_BITS)
161+#define HORIZONTAL_WIDTH_DOWNSHIFT (32-HORIZONTAL_WIDTH_SHIFT)
162+#define HORIZONTAL_HEIGHT_DOWNSHIFT (32-HORIZONTAL_HEIGHT_SHIFT)
163+
164+struct _horizontal_polygon_line_header
165+{
166+ int32 y_downshift;
167+};
168+
169+struct _horizontal_polygon_line_data
170+{
171+ uint32 source_x, source_y;
172+ uint32 source_dx, source_dy;
173+
174+ void *shading_table;
175+};
176+
177+/* ---------- texture vertical polygon */
178+
179+#define VERTICAL_TEXTURE_WIDTH 128
180+#define VERTICAL_TEXTURE_WIDTH_BITS 7
181+#define VERTICAL_TEXTURE_WIDTH_FRACTIONAL_BITS (FIXED_FRACTIONAL_BITS-VERTICAL_TEXTURE_WIDTH_BITS)
182+#define VERTICAL_TEXTURE_ONE (1<<VERTICAL_TEXTURE_WIDTH_FRACTIONAL_BITS)
183+#define VERTICAL_TEXTURE_FREE_BITS FIXED_FRACTIONAL_BITS
184+#define VERTICAL_TEXTURE_DOWNSHIFT (32-VERTICAL_TEXTURE_WIDTH_BITS)
185+
186+//AS: Seven! It's Everywhere!
187+#define HORIZONTAL_WIDTH_SHIFT 7 /* 128 (8 for 256) */
188+#define HORIZONTAL_HEIGHT_SHIFT 7 /* 128 */
189+#define HORIZONTAL_FREE_BITS (32-TRIG_SHIFT-WORLD_FRACTIONAL_BITS)
190+#define HORIZONTAL_WIDTH_DOWNSHIFT (32-HORIZONTAL_WIDTH_SHIFT)
191+#define HORIZONTAL_HEIGHT_DOWNSHIFT (32-HORIZONTAL_HEIGHT_SHIFT)
192+
193+struct _vertical_polygon_data
194+{
195+ int16 downshift;
196+ int16 x0;
197+ int16 width;
198+
199+ int16 pad;
200+};
201+
202+struct _vertical_polygon_line_data
203+{
204+ void *shading_table;
205+ pixel8 *texture;
206+ int32 texture_y, texture_dy;
207+};
208+
209+/* ---------- macros */
210+
211+// i0 + i1 == MAX(i0, i1) + MIN(i0, i1)/2
212+//#define calculate_shading_table(result, view, shading_tables, depth, ambient_shade)
213+static void calculate_shading_table(void * &result,view_data *view, void *shading_tables, short depth,_fixed ambient_shade)
214+{
215+ short table_index;
216+ _fixed shade;
217+
218+ if ((ambient_shade)<0)
219+ {
220+ table_index= SHADE_TO_SHADING_TABLE_INDEX(-(ambient_shade));
221+ }
222+ else
223+ {
224+ shade= (view)->maximum_depth_intensity - DEPTH_TO_SHADE(depth);
225+ shade= PIN(shade, 0, FIXED_ONE);
226+ table_index= SHADE_TO_SHADING_TABLE_INDEX((ambient_shade>shade) ? (ambient_shade + (shade>>1)) : (shade + (ambient_shade>>1)));
227+ }
228+
229+ switch (bit_depth)
230+ {
231+ case 8: result= ((byte*)(shading_tables)) + MAXIMUM_SHADING_TABLE_INDEXES*sizeof(pixel8)*
232+ CEILING(table_index, number_of_shading_tables-1); break;
233+ case 16: result= ((byte*)(shading_tables)) + MAXIMUM_SHADING_TABLE_INDEXES*sizeof(pixel16)*
234+ CEILING(table_index, number_of_shading_tables-1); break;
235+ case 32: result= ((byte*)(shading_tables)) + MAXIMUM_SHADING_TABLE_INDEXES*sizeof(pixel32)*
236+ CEILING(table_index, number_of_shading_tables-1); break;
237+ }
238+}
239+
240+/* ---------- globals */
241+
242+/* these tables are used by the polygon rasterizer (to store the x-coordinates of the left and
243+ right lines of the current polygon), the trapezoid rasterizer (to store the y-coordinates
244+ of the top and bottom of the current trapezoid) and the rectangle mapper (for itユs
245+ vertical and if necessary horizontal distortion tables). these are not necessary as
246+ globals, just as global storage. */
247+static short *scratch_table0 = NULL, *scratch_table1 = NULL;
248+static void *precalculation_table = NULL;
249+
250+static uint16 texture_random_seed= 6906;
251+
252+/* ---------- private prototypes */
253+
254+static void _pretexture_horizontal_polygon_lines(struct polygon_definition *polygon,
255+ struct bitmap_definition *screen, struct view_data *view, struct _horizontal_polygon_line_data *data,
256+ short y0, short *x0_table, short *x1_table, short line_count);
257+
258+static void _pretexture_vertical_polygon_lines(struct polygon_definition *polygon,
259+ struct bitmap_definition *screen, struct view_data *view, struct _vertical_polygon_data *data,
260+ short x0, short *y0_table, short *y1_table, short line_count);
261+
262+static short *build_x_table(short *table, short x0, short y0, short x1, short y1);
263+static short *build_y_table(short *table, short x0, short y0, short x1, short y1);
264+
265+static void _prelandscape_horizontal_polygon_lines(struct polygon_definition *polygon,
266+ struct bitmap_definition *screen, struct view_data *view, struct _horizontal_polygon_line_data *data,
267+ short y0, short *x0_table, short *x1_table, short line_count);
268+
269+/* ---------- code */
270+
271+
272+// LP addition:
273+// Find the next lower power of 2, and return the exponent
274+//AS: p isn't needed
275+inline int NextLowerExponent(int n)
276+{
277+ int xp = 0;
278+ while(n > 1) {n >>= 1; xp++;}
279+ return xp;
280+}
281+
282+#include "low_level_textures.h"
283+
284+/* set aside memory at launch for two line tables (remember, we precalculate all the y-values
285+ for trapezoids and two lines worth of x-values for polygons before mapping them) */
286+void allocate_texture_tables(
287+ void)
288+{
289+ scratch_table0= new short[MAXIMUM_SCRATCH_TABLE_ENTRIES];
290+ scratch_table1= new short[MAXIMUM_SCRATCH_TABLE_ENTRIES];
291+ precalculation_table= (void*)new char[MAXIMUM_PRECALCULATION_TABLE_ENTRY_SIZE*MAXIMUM_SCRATCH_TABLE_ENTRIES];
292+ assert(scratch_table0&&scratch_table1&&precalculation_table);
293+}
294+
295+void Rasterizer_SW_Class::texture_horizontal_polygon(polygon_definition& textured_polygon)
296+{
297+ polygon_definition *polygon = &textured_polygon; // Reference to pointer
298+ short vertex, highest_vertex, lowest_vertex;
299+ point2d *vertices= polygon->vertices;
300+
301+ assert(polygon->vertex_count>=MINIMUM_VERTICES_PER_SCREEN_POLYGON&&polygon->vertex_count<MAXIMUM_VERTICES_PER_SCREEN_POLYGON);
302+
303+ /* if we get static, tinted or landscaped transfer modes punt to the vertical polygon mapper */
304+ if (polygon->transfer_mode == _static_transfer) {
305+ texture_vertical_polygon(textured_polygon);
306+ return;
307+ }
308+
309+ /* locate the vertically highest (closest to zero) and lowest (farthest from zero) vertices */
310+ highest_vertex= lowest_vertex= 0;
311+ for (vertex= 0; vertex<polygon->vertex_count; ++vertex)
312+ {
313+ if (!(vertices[vertex].x>=0&&vertices[vertex].x<=screen->width&&vertices[vertex].y>=0&&vertices[vertex].y<=screen->height))
314+ {
315+ // dprintf("vertex #%d/#%d out of bounds:;dm %x %x;g;", vertex, polygon->vertex_count, polygon->vertices, polygon->vertex_count*sizeof(point2d));
316+ return;
317+ }
318+ if (vertices[vertex].y<vertices[highest_vertex].y) highest_vertex= vertex;
319+ else if (vertices[vertex].y>vertices[lowest_vertex].y) lowest_vertex= vertex;
320+ }
321+
322+ /* if this polygon is not a horizontal line, draw it */
323+ if (highest_vertex!=lowest_vertex)
324+ {
325+ short left_line_count, right_line_count, total_line_count;
326+ short aggregate_left_line_count, aggregate_right_line_count, aggregate_total_line_count;
327+ short left_vertex, right_vertex;
328+ short *left_table= scratch_table0, *right_table= scratch_table1;
329+
330+ left_line_count= right_line_count= 0; /* zero counts so the left and right lines get initialized */
331+ aggregate_left_line_count= aggregate_right_line_count= 0; /* weユve precalculated nothing initially */
332+ left_vertex= right_vertex= highest_vertex; /* both sides start at the highest vertex */
333+ total_line_count= vertices[lowest_vertex].y-vertices[highest_vertex].y; /* calculate vertical line count */
334+
335+ assert(total_line_count<MAXIMUM_SCRATCH_TABLE_ENTRIES); /* make sure we have enough scratch space */
336+
337+ /* precalculate high and low y-coordinates for every x-coordinate */
338+ aggregate_total_line_count= total_line_count;
339+ while (total_line_count>0)
340+ {
341+
342+ /* if weユre out of scan lines on the left side, get a new vertex and build a table
343+ of x-coordinates so we can walk toward the new vertex */
344+ if (left_line_count<=0)
345+ {
346+ do /* counter-clockwise vertex search */
347+ {
348+ vertex= left_vertex ? (left_vertex-1) : (polygon->vertex_count-1);
349+ left_line_count= vertices[vertex].y-vertices[left_vertex].y;
350+ if (!build_x_table(left_table+aggregate_left_line_count, vertices[left_vertex].x, vertices[left_vertex].y, vertices[vertex].x, vertices[vertex].y)) return;
351+ aggregate_left_line_count+= left_line_count;
352+ left_vertex= vertex;
353+// dprintf("add %d left", left_line_count);
354+ }
355+ while (!left_line_count);
356+ }
357+
358+ /* if weユre out of scan lines on the right side, get a new vertex and build a table
359+ of x-coordinates so we can walk toward the new vertex */
360+ if (right_line_count<=0)
361+ {
362+ do /* clockwise vertex search */
363+ {
364+ vertex= (right_vertex==polygon->vertex_count-1) ? 0 : (right_vertex+1);
365+ right_line_count= vertices[vertex].y-vertices[right_vertex].y;
366+ if (!build_x_table(right_table+aggregate_right_line_count, vertices[right_vertex].x, vertices[right_vertex].y, vertices[vertex].x, vertices[vertex].y)) return;
367+ aggregate_right_line_count+= right_line_count;
368+ right_vertex= vertex;
369+// dprintf("add %d right", right_line_count);
370+ }
371+ while (!right_line_count);
372+ }
373+ //AS: moving delta declaration up to where it's needed. Isn't C++ wonderful?
374+ /* advance by the minimum of left_line_count and right_line_count */
375+ short delta= MIN(left_line_count, right_line_count);
376+ assert(delta);
377+// dprintf("tc=%d lc=%d rc=%d delta=%d", total_line_count, left_line_count, right_line_count, delta);
378+ total_line_count-= delta;
379+ left_line_count-= delta;
380+ right_line_count-= delta;
381+
382+ assert(delta||!total_line_count); /* if our delta is zero, weユd better be out of lines */
383+ }
384+
385+ /* make sure every coordinate is accounted for in our tables */
386+ assert(aggregate_right_line_count==aggregate_total_line_count);
387+ assert(aggregate_left_line_count==aggregate_total_line_count);
388+
389+ /* precalculate mode-specific data */
390+ switch (polygon->transfer_mode)
391+ {
392+ case _textured_transfer:
393+ _pretexture_horizontal_polygon_lines(polygon, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
394+ vertices[highest_vertex].y, left_table, right_table,
395+ aggregate_total_line_count);
396+ break;
397+
398+ case _big_landscaped_transfer:
399+ _prelandscape_horizontal_polygon_lines(polygon, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
400+ vertices[highest_vertex].y, left_table, right_table,
401+ aggregate_total_line_count);
402+ break;
403+
404+ default:
405+ vhalt(csprintf(temporary, "horizontal_polygons dont support mode #%d", polygon->transfer_mode));
406+ }
407+
408+ /* render all lines */
409+ switch (bit_depth)
410+ {
411+ case 8:
412+ switch (polygon->transfer_mode)
413+ {
414+
415+ case _textured_transfer:
416+ texture_horizontal_polygon_lines<pixel8, _sw_alpha_off>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
417+ vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
418+ break;
419+ case _big_landscaped_transfer:
420+ landscape_horizontal_polygon_lines<pixel8>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
421+ vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
422+ break;
423+
424+ default:
425+ assert(false);
426+ break;
427+ }
428+ break;
429+
430+ case 16:
431+ switch (polygon->transfer_mode)
432+ {
433+ case _textured_transfer:
434+ {
435+ SW_Texture *sw_texture = 0;
436+ if (graphics_preferences->software_alpha_blending)
437+ {
438+ sw_texture = SW_Texture_Extras::instance()->GetTexture(polygon->ShapeDesc);
439+ }
440+ if (sw_texture && !polygon->VoidPresent && sw_texture->opac_type())
441+ {
442+ if (graphics_preferences->software_alpha_blending == _sw_alpha_fast) {
443+ texture_horizontal_polygon_lines<pixel16, _sw_alpha_fast>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table, vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
444+ }
445+ else if (graphics_preferences->software_alpha_blending == _sw_alpha_nice) {
446+ texture_horizontal_polygon_lines<pixel16, _sw_alpha_nice>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *) precalculation_table, vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count, sw_texture->opac_table());
447+ }
448+ } else {
449+ texture_horizontal_polygon_lines<pixel16, _sw_alpha_off>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
450+ vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
451+ }
452+ }
453+ break;
454+
455+ case _big_landscaped_transfer:
456+ landscape_horizontal_polygon_lines<pixel16>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
457+ vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
458+ break;
459+ default:
460+ assert(false);
461+ break;
462+ }
463+ break;
464+
465+ case 32:
466+ switch (polygon->transfer_mode)
467+ {
468+ case _textured_transfer:
469+ {
470+ SW_Texture *sw_texture = 0;
471+ if (graphics_preferences->software_alpha_blending)
472+ {
473+ sw_texture = SW_Texture_Extras::instance()->GetTexture(polygon->ShapeDesc);
474+ }
475+ if (sw_texture && sw_texture->opac_type() && !polygon->VoidPresent)
476+ {
477+ if (graphics_preferences->software_alpha_blending == _sw_alpha_fast)
478+ {
479+ texture_horizontal_polygon_lines<pixel32, _sw_alpha_fast>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table, vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
480+ }
481+ else if (graphics_preferences->software_alpha_blending = _sw_alpha_nice)
482+ {
483+ texture_horizontal_polygon_lines<pixel32, _sw_alpha_nice>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *) precalculation_table, vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count, sw_texture->opac_table());
484+ }
485+ }
486+ else
487+ {
488+ texture_horizontal_polygon_lines<pixel32, _sw_alpha_off>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
489+ vertices[highest_vertex].y, left_table, right_table,
490+ aggregate_total_line_count);
491+ }
492+ }
493+ break;
494+ case _big_landscaped_transfer:
495+ landscape_horizontal_polygon_lines<pixel32>(polygon->texture, screen, view, (struct _horizontal_polygon_line_data *)precalculation_table,
496+ vertices[highest_vertex].y, left_table, right_table, aggregate_total_line_count);
497+ break;
498+
499+ default:
500+ assert(false);
501+ break;
502+ }
503+ break;
504+
505+ default:
506+ assert(false);
507+ break;
508+ }
509+ }
510+}
511+
512+void Rasterizer_SW_Class::texture_vertical_polygon(polygon_definition& textured_polygon)
513+{
514+ polygon_definition *polygon = &textured_polygon; // Reference to pointer
515+ short vertex, highest_vertex, lowest_vertex;
516+ point2d *vertices= polygon->vertices;
517+
518+ assert(polygon->vertex_count>=MINIMUM_VERTICES_PER_SCREEN_POLYGON&&polygon->vertex_count<MAXIMUM_VERTICES_PER_SCREEN_POLYGON);
519+
520+ if (polygon->transfer_mode == _big_landscaped_transfer) {
521+ texture_horizontal_polygon(textured_polygon);
522+ return;
523+ }
524+
525+ /* locate the horizontally highest (closest to zero) and lowest (farthest from zero) vertices */
526+ highest_vertex= lowest_vertex= 0;
527+ for (vertex=1;vertex<polygon->vertex_count;++vertex)
528+ {
529+ if (vertices[vertex].x<vertices[highest_vertex].x) highest_vertex= vertex;
530+ if (vertices[vertex].x>vertices[lowest_vertex].x) lowest_vertex= vertex;
531+ }
532+
533+ for (vertex=0;vertex<polygon->vertex_count;++vertex)
534+ {
535+ if (!(vertices[vertex].x>=0&&vertices[vertex].x<=screen->width&&vertices[vertex].y>=0&&vertices[vertex].y<=screen->height))
536+ {
537+// dprintf("vertex #%d/#%d out of bounds:;dm %x %x;g;", vertex, polygon->vertex_count, polygon->vertices, polygon->vertex_count*sizeof(point2d));
538+ return;
539+ }
540+ }
541+
542+ /* if this polygon is not a vertical line, draw it */
543+ if (highest_vertex!=lowest_vertex)
544+ {
545+ short left_line_count, right_line_count, total_line_count;
546+ short aggregate_left_line_count, aggregate_right_line_count, aggregate_total_line_count;
547+ short left_vertex, right_vertex;
548+ short *left_table= scratch_table0, *right_table= scratch_table1;
549+
550+ left_line_count= right_line_count= 0; /* zero counts so the left and right lines get initialized */
551+ aggregate_left_line_count= aggregate_right_line_count= 0; /* weユve precalculated nothing initially */
552+ left_vertex= right_vertex= highest_vertex; /* both sides start at the highest vertex */
553+ total_line_count= vertices[lowest_vertex].x-vertices[highest_vertex].x; /* calculate vertical line count */
554+
555+ assert(total_line_count<MAXIMUM_SCRATCH_TABLE_ENTRIES); /* make sure we have enough scratch space */
556+
557+ /* precalculate high and low y-coordinates for every x-coordinate */
558+ aggregate_total_line_count= total_line_count;
559+ while (total_line_count>0)
560+ {
561+ /* if weユre out of scan lines on the left side, get a new vertex and build a table
562+ of y-coordinates so we can walk toward the new vertex */
563+ if (left_line_count<=0)
564+ {
565+ do /* clockwise vertex search */
566+ {
567+ vertex= (left_vertex==polygon->vertex_count-1) ? 0 : (left_vertex+1);
568+ left_line_count= vertices[vertex].x-vertices[left_vertex].x;
569+// dprintf("left line (%d,%d) to (%d,%d) for %d points", vertices[left_vertex].x, vertices[left_vertex].y, vertices[vertex].x, vertices[vertex].y, left_line_count);
570+ if (!build_y_table(left_table+aggregate_left_line_count, vertices[left_vertex].x, vertices[left_vertex].y, vertices[vertex].x, vertices[vertex].y)) return;
571+ aggregate_left_line_count+= left_line_count;
572+ left_vertex= vertex;
573+ }
574+ while (!left_line_count);
575+ }
576+
577+ /* if weユre out of scan lines on the right side, get a new vertex and build a table
578+ of y-coordinates so we can walk toward the new vertex */
579+ if (right_line_count<=0)
580+ {
581+ do /* counter-clockwise vertex search */
582+ {
583+ vertex= right_vertex ? (right_vertex-1) : (polygon->vertex_count-1);
584+ right_line_count= vertices[vertex].x-vertices[right_vertex].x;
585+// dprintf("right line (%d,%d) to (%d,%d) for %d points", vertices[right_vertex].x, vertices[right_vertex].y, vertices[vertex].x, vertices[vertex].y, right_line_count);
586+ if (!build_y_table(right_table+aggregate_right_line_count, vertices[right_vertex].x, vertices[right_vertex].y, vertices[vertex].x, vertices[vertex].y)) return;
587+ aggregate_right_line_count+= right_line_count;
588+ right_vertex= vertex;
589+ }
590+ while (!right_line_count);
591+ }
592+
593+ /* advance by the minimum of left_line_count and right_line_count */
594+ short delta= MIN(left_line_count, right_line_count);
595+ assert(delta);
596+ total_line_count-= delta;
597+ left_line_count-= delta;
598+ right_line_count-= delta;
599+
600+ assert(delta||!total_line_count); /* if our delta is zero, weユd better be out of lines */
601+ }
602+
603+ /* make sure every coordinate is accounted for in our tables */
604+ assert(aggregate_right_line_count==aggregate_total_line_count);
605+ assert(aggregate_left_line_count==aggregate_total_line_count);
606+
607+ /* precalculate mode-specific data */
608+
609+ if ((polygon->transfer_mode == _textured_transfer) || (polygon->transfer_mode == _static_transfer))
610+ {
611+ _pretexture_vertical_polygon_lines(polygon, screen, view, (struct _vertical_polygon_data *)precalculation_table, vertices[highest_vertex].x, left_table, right_table, aggregate_total_line_count);
612+ }
613+ else vhalt(csprintf(temporary, "vertical_polygons dont support mode #%d", polygon->transfer_mode));
614+
615+ /* render all lines */
616+ switch (bit_depth)
617+ {
618+ case 8:
619+ switch (polygon->transfer_mode)
620+ {
621+ case _textured_transfer:
622+ if (polygon->texture->flags&_TRANSPARENT_BIT)
623+ texture_vertical_polygon_lines<pixel8, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
624+ else
625+ texture_vertical_polygon_lines<pixel8, _sw_alpha_off, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
626+ break;
627+ case _static_transfer:
628+ if (polygon->texture->flags&_TRANSPARENT_BIT)
629+ randomize_vertical_polygon_lines<pixel8, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
630+ else
631+ randomize_vertical_polygon_lines<pixel8, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
632+ break;
633+
634+ default:
635+ assert(false);
636+ break;
637+ }
638+ break;
639+
640+ case 16:
641+ switch (polygon->transfer_mode)
642+ {
643+ case _textured_transfer:
644+ {
645+ SW_Texture *sw_texture =0 ;
646+ if (graphics_preferences->software_alpha_blending)
647+ {
648+ sw_texture = SW_Texture_Extras::instance()->GetTexture(polygon->ShapeDesc);
649+ }
650+ if (sw_texture && !polygon->VoidPresent && sw_texture->opac_type())
651+ {
652+ if (graphics_preferences->software_alpha_blending == _sw_alpha_fast) {
653+ if (polygon->texture->flags & _TRANSPARENT_BIT) {
654+ texture_vertical_polygon_lines<pixel16, _sw_alpha_fast, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
655+ } else {
656+ texture_vertical_polygon_lines<pixel16, _sw_alpha_fast, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
657+ }
658+ }
659+ else if (graphics_preferences->software_alpha_blending == _sw_alpha_nice) {
660+ if (polygon->texture->flags & _TRANSPARENT_BIT) {
661+ texture_vertical_polygon_lines<pixel16, _sw_alpha_nice, true>(screen, view, (struct _vertical_polygon_data *) precalculation_table, left_table, right_table, sw_texture->opac_table());
662+ } else {
663+ texture_vertical_polygon_lines<pixel16, _sw_alpha_nice, false>(screen, view, (struct _vertical_polygon_data *) precalculation_table, left_table, right_table, sw_texture->opac_table());
664+ }
665+ }
666+ } else {
667+ if (polygon->texture->flags & _TRANSPARENT_BIT) {
668+ texture_vertical_polygon_lines<pixel16, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
669+ } else {
670+ texture_vertical_polygon_lines<pixel16, _sw_alpha_off, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
671+ }
672+ }
673+ }
674+ break;
675+ case _static_transfer:
676+ if (polygon->texture->flags & _TRANSPARENT_BIT) {
677+ randomize_vertical_polygon_lines<pixel16, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
678+ } else {
679+ randomize_vertical_polygon_lines<pixel16, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
680+ }
681+ break;
682+ default:
683+ assert(false);
684+ break;
685+ }
686+ break;
687+
688+ case 32:
689+ switch (polygon->transfer_mode)
690+ {
691+ case _textured_transfer:
692+ {
693+ SW_Texture *sw_texture = 0;
694+ if (graphics_preferences->software_alpha_blending)
695+ {
696+ sw_texture = SW_Texture_Extras::instance()->GetTexture(polygon->ShapeDesc);
697+ }
698+ if (sw_texture && !polygon->VoidPresent && sw_texture->opac_type())
699+ {
700+ if (graphics_preferences->software_alpha_blending == _sw_alpha_fast) {
701+ if (polygon->texture->flags&_TRANSPARENT_BIT)
702+ texture_vertical_polygon_lines<pixel32, _sw_alpha_fast, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
703+ else
704+ texture_vertical_polygon_lines<pixel32, _sw_alpha_fast, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
705+ }
706+ else if (graphics_preferences->software_alpha_blending == _sw_alpha_nice)
707+ {
708+ if (polygon->texture->flags & _TRANSPARENT_BIT)
709+ texture_vertical_polygon_lines<pixel32, _sw_alpha_nice, true>(screen, view, (struct _vertical_polygon_data *) precalculation_table, left_table, right_table, sw_texture->opac_table());
710+ else
711+ texture_vertical_polygon_lines<pixel32, _sw_alpha_nice, false>(screen, view, (struct _vertical_polygon_data *) precalculation_table, left_table, right_table, sw_texture->opac_table());
712+ }
713+ } else {
714+ if (polygon->texture->flags & _TRANSPARENT_BIT)
715+ texture_vertical_polygon_lines<pixel32, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
716+ else
717+ texture_vertical_polygon_lines<pixel32, _sw_alpha_off, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table);
718+ }
719+ break;
720+ }
721+ case _static_transfer:
722+ if (polygon->texture->flags & _TRANSPARENT_BIT)
723+ randomize_vertical_polygon_lines<pixel32, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
724+ else
725+ randomize_vertical_polygon_lines<pixel32, false>(screen, view, (struct _vertical_polygon_data *)precalculation_table, left_table, right_table, polygon->transfer_data);
726+ break;
727+
728+ default:
729+ assert(false);
730+ break;
731+ }
732+ break;
733+
734+ default:
735+ assert(false);
736+ break;
737+ }
738+ }
739+}
740+
741+void Rasterizer_SW_Class::texture_rectangle(rectangle_definition& textured_rectangle)
742+{
743+ rectangle_definition *rectangle = &textured_rectangle; // Reference to pointer
744+
745+ if (rectangle->x0<rectangle->x1 && rectangle->y0<rectangle->y1)
746+ {
747+ /* subsume screen boundaries into clipping parameters */
748+ if (rectangle->clip_left<0) rectangle->clip_left= 0;
749+ if (rectangle->clip_right>screen->width) rectangle->clip_right= screen->width;
750+ if (rectangle->clip_top<0) rectangle->clip_top= 0;
751+ if (rectangle->clip_bottom>screen->height) rectangle->clip_bottom= screen->height;
752+
753+ /* subsume left and right sides of the rectangle into clipping parameters */
754+ if (rectangle->clip_left<rectangle->x0) rectangle->clip_left= rectangle->x0;
755+ if (rectangle->clip_right>rectangle->x1) rectangle->clip_right= rectangle->x1;
756+ if (rectangle->clip_top<rectangle->y0) rectangle->clip_top= rectangle->y0;
757+ if (rectangle->clip_bottom>rectangle->y1) rectangle->clip_bottom= rectangle->y1;
758+
759+ /* only continue if we have a non-empty rectangle, at least some of which is on the screen */
760+ if (rectangle->clip_left<rectangle->clip_right && rectangle->clip_top<rectangle->clip_bottom &&
761+ rectangle->clip_right>0 && rectangle->clip_left<screen->width &&
762+ rectangle->clip_bottom>0 && rectangle->clip_top<screen->height)
763+ {
764+ short delta; /* scratch */
765+ short screen_width= rectangle->x1-rectangle->x0;
766+ short screen_height= rectangle->y1-rectangle->y0;
767+ short screen_x= rectangle->x0;
768+ struct bitmap_definition *texture= rectangle->texture;
769+
770+ short *y0_table= scratch_table0, *y1_table= scratch_table1;
771+ struct _vertical_polygon_data *header= (struct _vertical_polygon_data *)precalculation_table;
772+ struct _vertical_polygon_line_data *data= (struct _vertical_polygon_line_data *) (header+1);
773+
774+ _fixed texture_dx= INTEGER_TO_FIXED(texture->width)/screen_width;
775+ _fixed texture_x= texture_dx>>1;
776+
777+ _fixed texture_dy= INTEGER_TO_FIXED(texture->height)/screen_height;
778+ _fixed texture_y0= 0;
779+ _fixed texture_y1;
780+
781+ if (texture_dx&&texture_dy)
782+ {
783+ /* handle horizontal mirroring */
784+ if (rectangle->flip_horizontal)
785+ {
786+ texture_dx= -texture_dx;
787+ texture_x= INTEGER_TO_FIXED(texture->width)+(texture_dx>>1);
788+ }
789+
790+ /* left clipping */
791+ if ((delta= rectangle->clip_left-rectangle->x0)>0)
792+ {
793+ texture_x+= delta*texture_dx;
794+ screen_width-= delta;
795+ screen_x= rectangle->clip_left;
796+ }
797+ /* right clipping */
798+ if ((delta= rectangle->x1-rectangle->clip_right)>0)
799+ {
800+ screen_width-= delta;
801+ }
802+
803+ /* top clipping */
804+ if ((delta= rectangle->clip_top-rectangle->y0)>0)
805+ {
806+ texture_y0+= delta*texture_dy;
807+ screen_height-= delta;
808+ }
809+
810+ /* bottom clipping */
811+ if ((delta= rectangle->y1-rectangle->clip_bottom)>0)
812+ {
813+ screen_height-= delta;
814+ }
815+
816+ texture_y1= texture_y0 + screen_height*texture_dy;
817+
818+ header->downshift= FIXED_FRACTIONAL_BITS;
819+ header->width= screen_width;
820+ header->x0= screen_x;
821+
822+ /* calculate shading table, once */
823+ void *shading_table = NULL;
824+ switch (rectangle->transfer_mode)
825+ {
826+ case _textured_transfer:
827+ if (!(rectangle->flags&_SHADELESS_BIT))
828+ {
829+ // LP change:
830+ // Made this more long-distance friendly
831+ calculate_shading_table(shading_table, view, rectangle->shading_tables, (short)MIN(rectangle->depth, SHRT_MAX), rectangle->ambient_shade);
832+ break;
833+ }
834+ /* if shadeless, fall through to a single shading table, ignoring depth */
835+ case _tinted_transfer:
836+ case _static_transfer:
837+ shading_table= rectangle->shading_tables;
838+ break;
839+
840+ default:
841+ vhalt(csprintf(temporary, "rectangles dont support mode #%d", rectangle->transfer_mode));
842+ }
843+
844+ for (; screen_width; --screen_width)
845+ {
846+ byte *read= texture->row_addresses[FIXED_INTEGERAL_PART(texture_x)];
847+ // CB: first/last are stored in big-endian order
848+ uint16 first = *read++ << 8;
849+ first |= *read++;
850+ uint16 last = *read++ << 8;
851+ last |= *read++;
852+ _fixed texture_y= texture_y0;
853+ short y0= rectangle->clip_top, y1= rectangle->clip_bottom;
854+
855+ if (FIXED_INTEGERAL_PART(texture_y0)<first)
856+ {
857+ delta= (INTEGER_TO_FIXED(first) - texture_y0)/texture_dy + 1;
858+ vassert(delta>=0, csprintf(temporary, "[%x,%x] カ=%x (#%d,#%d)", texture_y0, texture_y1, texture_dy, first, last));
859+
860+ y0= MIN(y1, y0+delta);
861+ texture_y+= delta*texture_dy;
862+ }
863+
864+ if (FIXED_INTEGERAL_PART(texture_y1)>last)
865+ {
866+ delta= (texture_y1 - INTEGER_TO_FIXED(last))/texture_dy + 1;
867+ vassert(delta>=0, csprintf(temporary, "[%x,%x] カ=%x (#%d,#%d)", texture_y0, texture_y1, texture_dy, first, last));
868+
869+ y1= MAX(y0, y1-delta);
870+ }
871+
872+ data->texture_y= texture_y - INTEGER_TO_FIXED(first);
873+ data->texture_dy= texture_dy;
874+ data->shading_table= shading_table;
875+ data->texture= (unsigned char *)read;
876+
877+ texture_x+= texture_dx;
878+ data+= 1;
879+
880+ *y0_table++= y0;
881+ *y1_table++= y1;
882+
883+ assert(y0<=y1);
884+ assert(y0>=0 && y1>=0);
885+ assert(y0<=screen->height);
886+ assert(y1<=screen->height);
887+ }
888+
889+ switch (bit_depth)
890+ {
891+ case 8:
892+ switch (rectangle->transfer_mode)
893+ {
894+ case _textured_transfer:
895+ texture_vertical_polygon_lines<pixel8, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
896+ scratch_table0, scratch_table1);
897+ break;
898+
899+ case _static_transfer:
900+ randomize_vertical_polygon_lines<pixel8, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
901+ scratch_table0, scratch_table1, rectangle->transfer_data);
902+ break;
903+
904+ case _tinted_transfer:
905+ tint_vertical_polygon_lines<pixel8>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
906+ scratch_table0, scratch_table1, rectangle->transfer_data);
907+ break;
908+
909+ default:
910+ assert(false);
911+ break;
912+ }
913+ break;
914+
915+ case 16:
916+ switch (rectangle->transfer_mode)
917+ {
918+ case _textured_transfer:
919+ texture_vertical_polygon_lines<pixel16, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table, scratch_table0, scratch_table1);
920+ break;
921+
922+ case _static_transfer:
923+ randomize_vertical_polygon_lines<pixel16, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
924+ scratch_table0, scratch_table1, rectangle->transfer_data);
925+ break;
926+
927+ case _tinted_transfer:
928+ tint_vertical_polygon_lines<pixel16>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
929+ scratch_table0, scratch_table1, rectangle->transfer_data);
930+ break;
931+
932+ default:
933+ assert(false);
934+ break;
935+ }
936+ break;
937+
938+ case 32:
939+ switch (rectangle->transfer_mode)
940+ {
941+ case _textured_transfer:
942+ texture_vertical_polygon_lines<pixel32, _sw_alpha_off, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
943+ scratch_table0, scratch_table1);
944+ break;
945+
946+ case _static_transfer:
947+ randomize_vertical_polygon_lines<pixel32, true>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
948+ scratch_table0, scratch_table1, rectangle->transfer_data);
949+ break;
950+
951+ case _tinted_transfer:
952+ tint_vertical_polygon_lines<pixel32>(screen, view, (struct _vertical_polygon_data *)precalculation_table,
953+ scratch_table0, scratch_table1, rectangle->transfer_data);
954+ break;
955+
956+ default:
957+ assert(false);
958+ break;
959+ }
960+ break;
961+
962+ default:
963+ assert(false);
964+ break;
965+ }
966+ }
967+ }
968+ }
969+}
970+
971+/* ---------- private code */
972+
973+#if 0
974+
975+#define LANDSCAPE_REPEATS 12
976+static void preprocess_landscaped_polygon(
977+ struct polygon_definition *polygon,
978+ struct view_data *view)
979+{
980+ polygon->origin.x= (world_distance) ((10000*LANDSCAPE_REPEATS*WORLD_ONE)/(2*31415));
981+ polygon->origin.y= -(((LANDSCAPE_REPEATS*WORLD_ONE*view->yaw)>>ANGULAR_BITS)&(WORLD_ONE-1));
982+ polygon->origin.z= 0;
983+
984+ polygon->vector.i= 0;
985+ polygon->vector.j= WORLD_ONE;
986+ polygon->vector.k= -WORLD_ONE;
987+
988+ polygon->ambient_shade= FIXED_ONE;
989+}
990+
991+#endif
992+
993+/* starting at x0 and for line_count vertical lines between *y0 and *y1, precalculate all the
994+ information _texture_vertical_polygon_lines will need to work */
995+static void _pretexture_vertical_polygon_lines(
996+ struct polygon_definition *polygon,
997+ struct bitmap_definition *screen,
998+ struct view_data *view,
999+ struct _vertical_polygon_data *data,
1000+ short x0,
1001+ short *y0_table,
1002+ short *y1_table,
1003+ short line_count)
1004+{
1005+ short screen_x= x0-view->half_screen_width;
1006+ int32 dz0= view->world_to_screen_y*polygon->origin.z;
1007+ int32 unadjusted_ty_denominator= view->world_to_screen_y*polygon->vector.k;
1008+ int32 tx_numerator, tx_denominator, tx_numerator_delta, tx_denominator_delta;
1009+ struct _vertical_polygon_line_data *line= (struct _vertical_polygon_line_data *) (data+1);
1010+
1011+ (void) (screen);
1012+
1013+ assert(sizeof(struct _vertical_polygon_line_data)<=MAXIMUM_PRECALCULATION_TABLE_ENTRY_SIZE);
1014+
1015+ data->downshift= VERTICAL_TEXTURE_DOWNSHIFT;
1016+ data->x0= x0;
1017+ data->width= line_count;
1018+
1019+ /* calculate and rescale tx_numerator, tx_denominator, etc. */
1020+ tx_numerator= view->world_to_screen_x*polygon->origin.y - screen_x*polygon->origin.x;
1021+ tx_denominator= screen_x*polygon->vector.i - view->world_to_screen_x*polygon->vector.j;
1022+ tx_numerator_delta= -polygon->origin.x;
1023+ tx_denominator_delta= polygon->vector.i;
1024+
1025+ while (--line_count>=0)
1026+ {
1027+ _fixed tx;
1028+ // LP change: made this quantity more long-distance friendly;
1029+ // have to avoid doing INTEGER_TO_FIXED on this one, however
1030+ int32 world_x;
1031+ short x0, y0= *y0_table++;
1032+ short screen_y0= view->half_screen_height-y0+view->dtanpitch;
1033+ int32 ty_numerator, ty_denominator;
1034+ _fixed ty, ty_delta;
1035+
1036+ /* would our precision be greater here if we shifted the numerator up to $7FFFFFFF and
1037+ then downshifted only the numerator? too bad we canユt use BFFFO in 68k */
1038+ {
1039+ int32 adjusted_tx_denominator= tx_denominator;
1040+ int32 adjusted_tx_numerator= tx_numerator;
1041+
1042+ while (adjusted_tx_numerator>((1<<(31-VERTICAL_TEXTURE_WIDTH_BITS))-1) ||
1043+ adjusted_tx_numerator<((-1)<<(31-VERTICAL_TEXTURE_WIDTH_BITS)))
1044+ {
1045+ adjusted_tx_numerator>>= 1, adjusted_tx_denominator>>= 1;
1046+ }
1047+ if (!adjusted_tx_denominator) adjusted_tx_denominator= 1; /* -1 will still be -1 */
1048+ x0= ((adjusted_tx_numerator<<VERTICAL_TEXTURE_WIDTH_BITS)/adjusted_tx_denominator)&(VERTICAL_TEXTURE_WIDTH-1);
1049+
1050+ while (adjusted_tx_numerator>INT16_MAX||adjusted_tx_numerator<INT16_MIN)
1051+ {
1052+ adjusted_tx_numerator>>= 1, adjusted_tx_denominator>>= 1;
1053+ }
1054+ if (!adjusted_tx_denominator) adjusted_tx_denominator= 1; /* -1 will still be -1 */
1055+ tx= INTEGER_TO_FIXED(adjusted_tx_numerator)/adjusted_tx_denominator;
1056+ }
1057+
1058+ world_x= polygon->origin.x + ((tx*polygon->vector.i)>>FIXED_FRACTIONAL_BITS);
1059+ if (world_x<0) world_x= -world_x; /* it is mostly unclear what weユre supposed to do with negative x values */
1060+
1061+ /* calculate and rescale ty_numerator, ty_denominator and calculate ty */
1062+ ty_numerator= world_x*screen_y0 - dz0;
1063+ ty_denominator= unadjusted_ty_denominator;
1064+ while (ty_numerator>INT16_MAX||ty_numerator<INT16_MIN)
1065+ {
1066+ ty_numerator>>= 1, ty_denominator>>= 1;
1067+ }
1068+ if (!ty_denominator) ty_denominator= 1; /* -1 will still be -1 */
1069+ ty= INTEGER_TO_FIXED(ty_numerator)/ty_denominator;
1070+
1071+ // LP change:
1072+ // Use the same reduction hack used earlier,
1073+ // because otherwise, INTEGER_TO_FIXED would cause world_x to wrap around.
1074+ int32 adjusted_world_x = world_x;
1075+ int32 adjusted_ty_denominator = unadjusted_ty_denominator>>8;
1076+
1077+ // LP: remember that world_x is always >= 0
1078+ while(adjusted_world_x > INT16_MAX)
1079+ {
1080+ adjusted_world_x >>= 1; adjusted_ty_denominator >>= 1;
1081+ }
1082+ if (!adjusted_ty_denominator) adjusted_ty_denominator= 1; /* -1 will still be -1 */
1083+ ty_delta= - INTEGER_TO_FIXED(adjusted_world_x)/adjusted_ty_denominator;
1084+
1085+ vassert(ty_delta>=0, csprintf(temporary, "ty_delta=W2F(%d)/%d=%d", world_x, unadjusted_ty_denominator, ty_delta));
1086+
1087+ /* calculate the shading table for this column */
1088+ if (polygon->flags&_SHADELESS_BIT)
1089+ {
1090+ line->shading_table= polygon->shading_tables;
1091+ }
1092+ else
1093+ {
1094+ // LP change: made this more long-distance friendly
1095+ calculate_shading_table(line->shading_table, view, polygon->shading_tables, (short)MIN(world_x, SHRT_MAX), polygon->ambient_shade);
1096+ // calculate_shading_table(line->shading_table, view, polygon->shading_tables, world_x, polygon->ambient_shade);
1097+ }
1098+
1099+// if (ty_delta)
1100+ {
1101+ /* calculate texture_y and texture_dy (floor-mapper style) */
1102+// data->n= VERTICAL_TEXTURE_DOWNSHIFT;
1103+ line->texture_y= ty<<VERTICAL_TEXTURE_FREE_BITS;
1104+ line->texture_dy= ty_delta<<(VERTICAL_TEXTURE_FREE_BITS-8);
1105+ line->texture= polygon->texture->row_addresses[x0];
1106+
1107+ line+= 1;
1108+ }
1109+
1110+ tx_numerator+= tx_numerator_delta;
1111+ tx_denominator+= tx_denominator_delta;
1112+
1113+ screen_x+= 1;
1114+ }
1115+}
1116+
1117+static void _pretexture_horizontal_polygon_lines(
1118+ struct polygon_definition *polygon,
1119+ struct bitmap_definition *screen,
1120+ struct view_data *view,
1121+ struct _horizontal_polygon_line_data *data,
1122+ short y0,
1123+ short *x0_table,
1124+ short *x1_table,
1125+ short line_count)
1126+{
1127+ int32 hcosine, dhcosine;
1128+ int32 hsine, dhsine;
1129+ int32 hworld_to_screen;
1130+ bool higher_precision= polygon->origin.z>-WORLD_ONE && polygon->origin.z<WORLD_ONE;
1131+
1132+ (void) (screen);
1133+
1134+ /* precalculate a bunch of multiplies */
1135+ hcosine= cosine_table[view->yaw];
1136+ hsine= sine_table[view->yaw];
1137+ if (higher_precision)
1138+ {
1139+ hcosine*= polygon->origin.z;
1140+ hsine*= polygon->origin.z;
1141+ }
1142+ hworld_to_screen= polygon->origin.z*view->world_to_screen_y;
1143+ dhcosine= view->world_to_screen_y*hcosine;
1144+ dhsine= view->world_to_screen_y*hsine;
1145+
1146+ while ((line_count-=1)>=0)
1147+ {
1148+ // LP change: made this more long-distance-friendly
1149+ int32 depth;
1150+ // world_distance depth;
1151+ short screen_x, screen_y;
1152+ short x0= *x0_table++;
1153+
1154+ /* calculate screen_x,screen_y */
1155+ screen_x= x0-view->half_screen_width;
1156+ screen_y= view->half_screen_height-y0+view->dtanpitch;
1157+ if (!screen_y) screen_y= 1; /* this will avoid division by zero and won't change rendering */
1158+
1159+ /* calculate source_x, source_y, source_dx, source_dy */
1160+
1161+ int32 source_x, source_y, source_dx, source_dy;
1162+
1163+ /* calculate texture origins and deltas (source_x,source_dx,source_y,source_dy) */
1164+ if (higher_precision)
1165+ {
1166+ source_x= (dhcosine - screen_x*hsine)/screen_y + (polygon->origin.x<<TRIG_SHIFT);
1167+ source_dx= - hsine/screen_y;
1168+ source_y= (screen_x*hcosine + dhsine)/screen_y + (polygon->origin.y<<TRIG_SHIFT);
1169+ source_dy= hcosine/screen_y;
1170+ }
1171+ else
1172+ {
1173+ source_x= ((dhcosine - screen_x*hsine)/screen_y)*polygon->origin.z + (polygon->origin.x<<TRIG_SHIFT);
1174+ source_dx= - (hsine*polygon->origin.z)/screen_y;
1175+ source_y= ((screen_x*hcosine + dhsine)/screen_y)*polygon->origin.z + (polygon->origin.y<<TRIG_SHIFT);
1176+ source_dy= (hcosine*polygon->origin.z)/screen_y;
1177+ }
1178+
1179+ /* voodoo so x,y texture wrapping is handled automatically by downshifting
1180+ (subtract one from HORIZONTAL_FREE_BITS to double scale) */
1181+ data->source_x= source_x<<HORIZONTAL_FREE_BITS, data->source_dx= source_dx<<HORIZONTAL_FREE_BITS;
1182+ data->source_y= source_y<<HORIZONTAL_FREE_BITS, data->source_dy= source_dy<<HORIZONTAL_FREE_BITS;
1183+
1184+
1185+ /* get shading table (with absolute value of depth) */
1186+ if ((depth= hworld_to_screen/screen_y)<0) depth= -depth;
1187+ if (polygon->flags&_SHADELESS_BIT)
1188+ {
1189+ data->shading_table= polygon->shading_tables;
1190+ }
1191+ else
1192+ {
1193+ calculate_shading_table(data->shading_table, view, polygon->shading_tables, (short)MIN(depth, SHRT_MAX), polygon->ambient_shade);
1194+ }
1195+
1196+ data++;
1197+ y0++;
1198+ }
1199+}
1200+
1201+
1202+// height must be determined emperically (texture is vertically centered at 0。)
1203+// #define LANDSCAPE_REPEAT_BITS 1
1204+static void _prelandscape_horizontal_polygon_lines(
1205+ struct polygon_definition *polygon,
1206+ struct bitmap_definition *screen,
1207+ struct view_data *view,
1208+ struct _horizontal_polygon_line_data *data,
1209+ short y0,
1210+ short *x0_table,
1211+ short *x1_table,
1212+ short line_count)
1213+{
1214+ // LP change: made this more general:
1215+ short landscape_width_bits= NextLowerExponent(polygon->texture->height);
1216+ short texture_height= polygon->texture->width;
1217+ _fixed ambient_shade= FIXED_ONE; // MPW C died if we passed the constant directly to the macro
1218+
1219+ // Get the landscape-texturing options
1220+ LandscapeOptions *LandOpts = View_GetLandscapeOptions(polygon->ShapeDesc);
1221+
1222+ // LP change: separate horizontal and vertical pixel deltas:
1223+ // LP change: using a "landscape yaw" that's at the left edge of the screen.
1224+ _fixed first_horizontal_pixel= (view->landscape_yaw + LandOpts->Azimuth)<<(landscape_width_bits+(LandOpts->HorizExp)+FIXED_FRACTIONAL_BITS-ANGULAR_BITS);
1225+ _fixed horizontal_pixel_delta= (view->half_cone<<(1+landscape_width_bits+(LandOpts->HorizExp)+FIXED_FRACTIONAL_BITS-ANGULAR_BITS))/view->standard_screen_width;
1226+ _fixed vertical_pixel_delta= (view->half_cone<<(1+landscape_width_bits+(LandOpts->VertExp)+FIXED_FRACTIONAL_BITS-ANGULAR_BITS))/view->standard_screen_width;
1227+ short landscape_free_bits= 32-FIXED_FRACTIONAL_BITS-landscape_width_bits;
1228+
1229+ (void) (screen);
1230+
1231+ /* calculate the shading table */
1232+ void *shading_table = NULL;
1233+ if (polygon->flags&_SHADELESS_BIT)
1234+ {
1235+ shading_table= polygon->shading_tables;
1236+ }
1237+ else
1238+ {
1239+ calculate_shading_table(shading_table, view, polygon->shading_tables, 0, ambient_shade);
1240+ }
1241+
1242+ // Find the height to repeat over; use value used for OpenGL texture setup
1243+ short texture_width= polygon->texture->height;
1244+ short repeat_texture_height = texture_width >> LandOpts->OGL_AspRatExp;
1245+
1246+ short height_reduced = texture_height - 1;
1247+ short height_shift = texture_height >> 1;
1248+ short height_repeat_mask = repeat_texture_height - 1;
1249+ short height_repeat_shift = repeat_texture_height >> 1;
1250+
1251+ y0-= view->half_screen_height + view->dtanpitch; /* back to virtual screen coordinates */
1252+ while ((line_count-= 1)>=0)
1253+ {
1254+ short x0= *x0_table++;
1255+
1256+ data->shading_table= shading_table;
1257+ // LP change: using vertical pixel delta
1258+ // Also using vertical repeat if selected;
1259+ // fold the height into the range (-repeat_height/2, repeat_height)
1260+ short y_txtr_offset= FIXED_INTEGERAL_PART(y0*vertical_pixel_delta);
1261+ if (LandOpts->VertRepeat)
1262+ y_txtr_offset = ((y_txtr_offset + height_repeat_shift) & height_repeat_mask) -
1263+ height_repeat_shift;
1264+ data->source_y= texture_height - PIN(y_txtr_offset + height_shift, 0, height_reduced) - 1;
1265+ // LP change: using horizontal pixel delta
1266+ data->source_x= (first_horizontal_pixel + x0*horizontal_pixel_delta)<<landscape_free_bits;
1267+ data->source_dx= horizontal_pixel_delta<<landscape_free_bits;
1268+
1269+ data+= 1;
1270+ y0+= 1;
1271+ }
1272+}
1273+
1274+/* y0<y1; this is for vertical polygons */
1275+static short *build_x_table(
1276+ short *table,
1277+ short x0,
1278+ short y0,
1279+ short x1,
1280+ short y1)
1281+{
1282+ short dx, dy, adx, ady; /* 'a' prefix means absolute value */
1283+ short x, y; /* x,y screen positions */
1284+ short d, delta_d, d_max; /* descriminator, delta_descriminator, descriminator_maximum */
1285+ short *record;
1286+
1287+ /* calculate SGN(dx),SGN(dy) and the absolute values of dx,dy */
1288+ dx= x1-x0, adx= ABS(dx), dx= SGN(dx);
1289+ dy= y1-y0, ady= ABS(dy), dy= SGN(dy);
1290+
1291+ assert(ady<MAXIMUM_SCRATCH_TABLE_ENTRIES); /* can't overflow table */
1292+ if (dy>0)
1293+ {
1294+ /* setup initial (x,y) location and initialize a pointer to our table */
1295+ x= x0, y= y0;
1296+ record= table;
1297+
1298+ if (adx>=ady)
1299+ {
1300+ /* x-dominant line (we need to record x every time y changes) */
1301+
1302+ d= adx-ady, delta_d= - 2*ady, d_max= 2*adx;
1303+ while ((adx-=1)>=0)
1304+ {
1305+ if (d<0) y+= 1, d+= d_max, *record++= x, ady-= 1;
1306+ x+= dx, d+= delta_d;
1307+ }
1308+ if (ady==1) *record++= x; else assert(!ady);
1309+ }
1310+ else
1311+ {
1312+ /* y-dominant line (we need to record x every iteration) */
1313+
1314+ d= ady-adx, delta_d= - 2*adx, d_max= 2*ady;
1315+ while ((ady-=1)>=0)
1316+ {
1317+ if (d<0) x+= dx, d+= d_max;
1318+ *record++= x;
1319+ y+= 1, d+= delta_d;
1320+ }
1321+ }
1322+ }
1323+ else
1324+ {
1325+ /* canユt build a table for negative dy */
1326+ if (dy<0) return NULL;
1327+ }
1328+
1329+ return table;
1330+}
1331+
1332+/* x0<x1; this is for horizontal polygons */
1333+static short *build_y_table(
1334+ short *table,
1335+ short x0,
1336+ short y0,
1337+ short x1,
1338+ short y1)
1339+{
1340+ short dx, dy, adx, ady; /* 'a' prefix means absolute value */
1341+ short x, y; /* x,y screen positions */
1342+ short d, delta_d, d_max; /* descriminator, delta_descriminator, descriminator_maximum */
1343+ short *record;
1344+
1345+ /* calculate SGN(dx),SGN(dy) and the absolute values of dx,dy */
1346+ dx= x1-x0, adx= ABS(dx), dx= SGN(dx);
1347+ dy= y1-y0, ady= ABS(dy), dy= SGN(dy);
1348+
1349+ assert(adx<MAXIMUM_SCRATCH_TABLE_ENTRIES); /* can't overflow table */
1350+ if (dx>=0) /* vertical lines allowed */
1351+ {
1352+ /* setup initial (x,y) location and initialize a pointer to our table */
1353+ if (dy>=0)
1354+ {
1355+ x= x0, y= y0;
1356+ record= table;
1357+ }
1358+ else
1359+ {
1360+ x= x1, y= y1;
1361+ record= table+adx;
1362+ }
1363+
1364+ if (adx>=ady)
1365+ {
1366+ /* x-dominant line (we need to record y every iteration) */
1367+
1368+ d= adx-ady, delta_d= - 2*ady, d_max= 2*adx;
1369+ while ((adx-=1)>=0)
1370+ {
1371+ if (d<0) y+= 1, d+= d_max;
1372+ if (dy>=0) *record++= y; else *--record= y;
1373+ x+= dx, d+= delta_d;
1374+ }
1375+ }
1376+ else
1377+ {
1378+ /* y-dominant line (we need to record y every time x changes) */
1379+
1380+ d= ady-adx, delta_d= - 2*adx, d_max= 2*ady;
1381+ while ((ady-=1)>=0)
1382+ {
1383+ if (d<0) { x+= dx, d+= d_max, adx-= 1; if (dy>=0) *record++= y; else *--record= y; }
1384+ y+= 1, d+= delta_d;
1385+ }
1386+ if (adx==1) if (dy>=0) *record++= y; else *--record= y; else assert(!adx);
1387+ }
1388+ }
1389+ else
1390+ {
1391+ /* canユt build a table for a negative dx */
1392+ return NULL;
1393+ }
1394+
1395+ return table;
1396+}
--- marathon/trunk/Source_Files/RenderMain/SW_Texture_Extras.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/SW_Texture_Extras.h (revision 530)
@@ -1,82 +1,82 @@
1-#ifndef __SW_TEXTURE_EXTRAS_H
2-#define __SW_TEXTURE_EXTRAS_H
3-
4-/*
5-SW_TEXTURE_EXTRAS.H
6-
7- Copyright (C) 2007 Gregory Smith
8-
9- This program is free software; you can redistribute it and/or modify
10- it under the terms of the GNU General Public License as published by
11- the Free Software Foundation; either version 3 of the License, or
12- (at your option) any later version.
13-
14- This program is distributed in the hope that it will be useful,
15- but WITHOUT ANY WARRANTY; without even the implied warranty of
16- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17- GNU General Public License for more details.
18-
19- This license is contained in the file "COPYING",
20- which is included with this source code; it is available online at
21- http://www.gnu.org/licenses/gpl.html
22-
23-*/
24-
25-#include "cseries.h"
26-#include "cstypes.h"
27-#include "shape_descriptors.h"
28-#include "XML_ElementParser.h"
29-#include <vector>
30-
31-class SW_Texture
32-{
33-public:
34- SW_Texture() : m_opac_type(0), m_shape_descriptor(0), m_opac_scale(1.0), m_opac_shift(0.0) { }
35- void descriptor(shape_descriptor ShapeDesc) { m_shape_descriptor = ShapeDesc; }
36- int opac_type() { return m_opac_type; }
37- void opac_type(int new_opac_type) { m_opac_type = new_opac_type; }
38-
39- uint8 *opac_table() {
40- if (m_opac_table.size() == 0)
41- return 0;
42- else
43- return &m_opac_table.front();
44- }
45-
46- void opac_shift(float new_opac_shift) { m_opac_shift = new_opac_shift; }
47- void opac_scale(float new_opac_scale) { m_opac_scale = new_opac_scale; }
48-
49- void build_opac_table();
50-
51- void clear_opac_table() {
52- m_opac_table.clear();
53- }
54-
55-private:
56- shape_descriptor m_shape_descriptor;
57- int m_opac_type;
58- float m_opac_scale;
59- float m_opac_shift;
60- std::vector<uint8> m_opac_table;
61-};
62-
63-class SW_Texture_Extras
64-{
65-public:
66- static SW_Texture_Extras *instance() { if (!m_instance) m_instance = new SW_Texture_Extras(); return m_instance; }
67-
68- SW_Texture *GetTexture(shape_descriptor ShapeDesc);
69- SW_Texture *AddTexture(shape_descriptor ShapeDesc);
70- void Load(short Collection);
71- void Unload(short Collection);
72-
73-private:
74- SW_Texture_Extras() { }
75- static SW_Texture_Extras *m_instance;
76-
77- std::vector<SW_Texture> texture_list[NUMBER_OF_COLLECTIONS];
78-};
79-
80-XML_ElementParser *SW_Texture_Extras_GetParser();
81-
82-#endif
1+#ifndef __SW_TEXTURE_EXTRAS_H
2+#define __SW_TEXTURE_EXTRAS_H
3+
4+/*
5+SW_TEXTURE_EXTRAS.H
6+
7+ Copyright (C) 2007 Gregory Smith
8+
9+ This program is free software; you can redistribute it and/or modify
10+ it under the terms of the GNU General Public License as published by
11+ the Free Software Foundation; either version 3 of the License, or
12+ (at your option) any later version.
13+
14+ This program is distributed in the hope that it will be useful,
15+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+ GNU General Public License for more details.
18+
19+ This license is contained in the file "COPYING",
20+ which is included with this source code; it is available online at
21+ http://www.gnu.org/licenses/gpl.html
22+
23+*/
24+
25+#include "cseries.h"
26+#include "cstypes.h"
27+#include "shape_descriptors.h"
28+#include "XML_ElementParser.h"
29+#include <vector>
30+
31+class SW_Texture
32+{
33+public:
34+ SW_Texture() : m_opac_type(0), m_shape_descriptor(0), m_opac_scale(1.0), m_opac_shift(0.0) { }
35+ void descriptor(shape_descriptor ShapeDesc) { m_shape_descriptor = ShapeDesc; }
36+ int opac_type() { return m_opac_type; }
37+ void opac_type(int new_opac_type) { m_opac_type = new_opac_type; }
38+
39+ uint8 *opac_table() {
40+ if (m_opac_table.size() == 0)
41+ return 0;
42+ else
43+ return &m_opac_table.front();
44+ }
45+
46+ void opac_shift(float new_opac_shift) { m_opac_shift = new_opac_shift; }
47+ void opac_scale(float new_opac_scale) { m_opac_scale = new_opac_scale; }
48+
49+ void build_opac_table();
50+
51+ void clear_opac_table() {
52+ m_opac_table.clear();
53+ }
54+
55+private:
56+ shape_descriptor m_shape_descriptor;
57+ int m_opac_type;
58+ float m_opac_scale;
59+ float m_opac_shift;
60+ std::vector<uint8> m_opac_table;
61+};
62+
63+class SW_Texture_Extras
64+{
65+public:
66+ static SW_Texture_Extras *instance() { if (!m_instance) m_instance = new SW_Texture_Extras(); return m_instance; }
67+
68+ SW_Texture *GetTexture(shape_descriptor ShapeDesc);
69+ SW_Texture *AddTexture(shape_descriptor ShapeDesc);
70+ void Load(short Collection);
71+ void Unload(short Collection);
72+
73+private:
74+ SW_Texture_Extras() { }
75+ static SW_Texture_Extras *m_instance;
76+
77+ std::vector<SW_Texture> texture_list[NUMBER_OF_COLLECTIONS];
78+};
79+
80+XML_ElementParser *SW_Texture_Extras_GetParser();
81+
82+#endif
--- marathon/trunk/Source_Files/RenderMain/RenderPlaceObjs.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/RenderPlaceObjs.h (revision 530)
@@ -1,99 +1,99 @@
1-#ifndef _RENDER_PLACE_OBJECTS_CLASS_
2-#define _RENDER_PLACE_OBJECTS_CLASS_
3-/*
4-
5- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6- and the "Aleph One" developers.
7-
8- This program is free software; you can redistribute it and/or modify
9- it under the terms of the GNU General Public License as published by
10- the Free Software Foundation; either version 3 of the License, or
11- (at your option) any later version.
12-
13- This program is distributed in the hope that it will be useful,
14- but WITHOUT ANY WARRANTY; without even the implied warranty of
15- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16- GNU General Public License for more details.
17-
18- This license is contained in the file "COPYING",
19- which is included with this source code; it is available online at
20- http://www.gnu.org/licenses/gpl.html
21-
22- Rendering Object-Placement Class
23- by Loren Petrich,
24- August 6, 2000
25-
26- Defines a class for placing inhabitants in appropriate rendering order; from render.c
27- Works from RenderSortPoly stuff.
28-
29- Made [view_data *view] a member and removed it as an argument
30-
31-Oct 13, 2000
32- LP: replaced GrowableLists and ResizableLists with STL vectors
33-*/
34-
35-#include <vector>
36-#include "world.h"
37-#include "interface.h"
38-#include "render.h"
39-#include "RenderSortPoly.h"
40-
41-
42-/* ---------- render objects */
43-
44-struct render_object_data
45-{
46- struct sorted_node_data *node; /* node we are being drawn inside */
47- struct clipping_window_data *clipping_windows; /* our privately calculated clipping window */
48-
49- struct render_object_data *next_object; /* the next object in this chain */
50-
51- struct rectangle_definition rectangle;
52-
53- int16 ymedia;
54-};
55-
56-
57-class RenderPlaceObjsClass
58-{
59- // Auxiliary data and routines:
60-
61- void initialize_render_object_list();
62-
63- render_object_data *build_render_object(long_point3d *origin,
64- _fixed floor_intensity, _fixed ceiling_intensity,
65- sorted_node_data **base_nodes, short *base_node_count,
66- short object_index, float Opacity, long_point3d *rel_origin);
67-
68- void sort_render_object_into_tree(render_object_data *new_render_object,
69- sorted_node_data **base_nodes, short base_node_count);
70-
71- short build_base_node_list(short origin_polygon_index,
72- world_point3d *origin, world_distance left_distance, world_distance right_distance,
73- sorted_node_data **base_nodes);
74-
75- void build_aggregate_render_object_clipping_window(render_object_data *render_object,
76- sorted_node_data **base_nodes, short base_node_count);
77-
78- shape_information_data *rescale_shape_information(shape_information_data *unscaled,
79- shape_information_data *scaled, uint16 flags);
80-
81-public:
82-
83- // LP additions: growable list of render objects; these are all the inhabitants
84- // Length changed in build_render_object()
85- // keep SortedNodes in sync
86- vector<render_object_data> RenderObjects;
87-
88- // Pointers to view and calculated visibility tree and sorted polygons
89- view_data *view;
90- RenderVisTreeClass *RVPtr;
91- RenderSortPolyClass *RSPtr;
92-
93- void build_render_object_list();
94-
95- // Inits everything
96- RenderPlaceObjsClass();
97-};
98-
99-#endif
1+#ifndef _RENDER_PLACE_OBJECTS_CLASS_
2+#define _RENDER_PLACE_OBJECTS_CLASS_
3+/*
4+
5+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6+ and the "Aleph One" developers.
7+
8+ This program is free software; you can redistribute it and/or modify
9+ it under the terms of the GNU General Public License as published by
10+ the Free Software Foundation; either version 3 of the License, or
11+ (at your option) any later version.
12+
13+ This program is distributed in the hope that it will be useful,
14+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU General Public License for more details.
17+
18+ This license is contained in the file "COPYING",
19+ which is included with this source code; it is available online at
20+ http://www.gnu.org/licenses/gpl.html
21+
22+ Rendering Object-Placement Class
23+ by Loren Petrich,
24+ August 6, 2000
25+
26+ Defines a class for placing inhabitants in appropriate rendering order; from render.c
27+ Works from RenderSortPoly stuff.
28+
29+ Made [view_data *view] a member and removed it as an argument
30+
31+Oct 13, 2000
32+ LP: replaced GrowableLists and ResizableLists with STL vectors
33+*/
34+
35+#include <vector>
36+#include "world.h"
37+#include "interface.h"
38+#include "render.h"
39+#include "RenderSortPoly.h"
40+
41+
42+/* ---------- render objects */
43+
44+struct render_object_data
45+{
46+ struct sorted_node_data *node; /* node we are being drawn inside */
47+ struct clipping_window_data *clipping_windows; /* our privately calculated clipping window */
48+
49+ struct render_object_data *next_object; /* the next object in this chain */
50+
51+ struct rectangle_definition rectangle;
52+
53+ int16 ymedia;
54+};
55+
56+
57+class RenderPlaceObjsClass
58+{
59+ // Auxiliary data and routines:
60+
61+ void initialize_render_object_list();
62+
63+ render_object_data *build_render_object(long_point3d *origin,
64+ _fixed floor_intensity, _fixed ceiling_intensity,
65+ sorted_node_data **base_nodes, short *base_node_count,
66+ short object_index, float Opacity, long_point3d *rel_origin);
67+
68+ void sort_render_object_into_tree(render_object_data *new_render_object,
69+ sorted_node_data **base_nodes, short base_node_count);
70+
71+ short build_base_node_list(short origin_polygon_index,
72+ world_point3d *origin, world_distance left_distance, world_distance right_distance,
73+ sorted_node_data **base_nodes);
74+
75+ void build_aggregate_render_object_clipping_window(render_object_data *render_object,
76+ sorted_node_data **base_nodes, short base_node_count);
77+
78+ shape_information_data *rescale_shape_information(shape_information_data *unscaled,
79+ shape_information_data *scaled, uint16 flags);
80+
81+public:
82+
83+ // LP additions: growable list of render objects; these are all the inhabitants
84+ // Length changed in build_render_object()
85+ // keep SortedNodes in sync
86+ vector<render_object_data> RenderObjects;
87+
88+ // Pointers to view and calculated visibility tree and sorted polygons
89+ view_data *view;
90+ RenderVisTreeClass *RVPtr;
91+ RenderSortPolyClass *RSPtr;
92+
93+ void build_render_object_list();
94+
95+ // Inits everything
96+ RenderPlaceObjsClass();
97+};
98+
99+#endif
--- marathon/trunk/Source_Files/RenderMain/Rasterizer_SW.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/Rasterizer_SW.h (revision 530)
@@ -1,55 +1,55 @@
1-#ifndef _RASTERIZER_SOFTWARE_CLASS_
2-#define _RASTERIZER_SOFTWARE_CLASS_
3-/*
4-
5- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6- and the "Aleph One" developers.
7-
8- This program is free software; you can redistribute it and/or modify
9- it under the terms of the GNU General Public License as published by
10- the Free Software Foundation; either version 3 of the License, or
11- (at your option) any later version.
12-
13- This program is distributed in the hope that it will be useful,
14- but WITHOUT ANY WARRANTY; without even the implied warranty of
15- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16- GNU General Public License for more details.
17-
18- This license is contained in the file "COPYING",
19- which is included with this source code; it is available online at
20- http://www.gnu.org/licenses/gpl.html
21-
22- Rasterizer software impementation (plugs into scottish_textures files)
23- by Loren Petrich,
24- August 7, 2000
25-
26-*/
27-
28-#include "Rasterizer.h"
29-
30-
31-class Rasterizer_SW_Class: public RasterizerClass
32-{
33-public:
34-
35- // Pointers to stuff used in scottish_textures:
36- view_data *view;
37- // Calling this one "screen" for scottish_textures convenience:
38- bitmap_definition *screen;
39-
40- // Sets the rasterizer's view data;
41- // be sure to call it before doing any rendering
42- void SetView(view_data& View) {view = &View;}
43-
44- // Rendering calls
45- // These are defined in scottish_textures.c (too great a name to change)
46-
47- void texture_horizontal_polygon(polygon_definition& textured_polygon);
48-
49- void texture_vertical_polygon(polygon_definition& textured_polygon);
50-
51- void texture_rectangle(rectangle_definition& textured_rectangle);
52-};
53-
54-
55-#endif
1+#ifndef _RASTERIZER_SOFTWARE_CLASS_
2+#define _RASTERIZER_SOFTWARE_CLASS_
3+/*
4+
5+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6+ and the "Aleph One" developers.
7+
8+ This program is free software; you can redistribute it and/or modify
9+ it under the terms of the GNU General Public License as published by
10+ the Free Software Foundation; either version 3 of the License, or
11+ (at your option) any later version.
12+
13+ This program is distributed in the hope that it will be useful,
14+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU General Public License for more details.
17+
18+ This license is contained in the file "COPYING",
19+ which is included with this source code; it is available online at
20+ http://www.gnu.org/licenses/gpl.html
21+
22+ Rasterizer software impementation (plugs into scottish_textures files)
23+ by Loren Petrich,
24+ August 7, 2000
25+
26+*/
27+
28+#include "Rasterizer.h"
29+
30+
31+class Rasterizer_SW_Class: public RasterizerClass
32+{
33+public:
34+
35+ // Pointers to stuff used in scottish_textures:
36+ view_data *view;
37+ // Calling this one "screen" for scottish_textures convenience:
38+ bitmap_definition *screen;
39+
40+ // Sets the rasterizer's view data;
41+ // be sure to call it before doing any rendering
42+ void SetView(view_data& View) {view = &View;}
43+
44+ // Rendering calls
45+ // These are defined in scottish_textures.c (too great a name to change)
46+
47+ void texture_horizontal_polygon(polygon_definition& textured_polygon);
48+
49+ void texture_vertical_polygon(polygon_definition& textured_polygon);
50+
51+ void texture_rectangle(rectangle_definition& textured_rectangle);
52+};
53+
54+
55+#endif
--- marathon/trunk/Source_Files/RenderMain/RenderRasterize.cpp (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/RenderRasterize.cpp (revision 530)
@@ -1,1328 +1,1328 @@
1-/*
2-
3- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4- and the "Aleph One" developers.
5-
6- This program is free software; you can redistribute it and/or modify
7- it under the terms of the GNU General Public License as published by
8- the Free Software Foundation; either version 3 of the License, or
9- (at your option) any later version.
10-
11- This program is distributed in the hope that it will be useful,
12- but WITHOUT ANY WARRANTY; without even the implied warranty of
13- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14- GNU General Public License for more details.
15-
16- This license is contained in the file "COPYING",
17- which is included with this source code; it is available online at
18- http://www.gnu.org/licenses/gpl.html
19-
20- Rendering Clipping/Rasterization Class
21- by Loren Petrich,
22- August 7, 2000
23-
24- Contains the calculation of clipping and rasterization; from render.c
25-
26- Made [view_data *view] a member and removed it as an argument
27- Also removed [bitmap_definition *destination] as superfluous,
28- now that there is a special rasterizer object that can contain it.
29-
30-Sep 2, 2000 (Loren Petrich):
31- Added some idiot-proofing, since the shapes accessor now returns NULL for nonexistent bitmaps
32-
33- If a polygon has a "full_side" texture, and there is another polgyon on the other side,
34- then suppress the void for the boundary's texture.
35-*/
36-
37-#include "cseries.h"
38-
39-#include "map.h"
40-#include "lightsource.h"
41-#include "media.h"
42-#include "RenderRasterize.h"
43-#include "AnimatedTextures.h"
44-#include "OGL_Setup.h"
45-#include "preferences.h"
46-#include "screen.h"
47-
48-#include <string.h>
49-
50-
51-/* maximum number of vertices a polygon can be world-clipped into (one per clip line) */
52-#define MAXIMUM_VERTICES_PER_WORLD_POLYGON (MAXIMUM_VERTICES_PER_POLYGON+4)
53-
54-
55-RenderRasterizerClass::RenderRasterizerClass():
56- view(NULL), // Idiot-proofing
57- RSPtr(NULL),
58- RasPtr(NULL)
59-{}
60-
61-
62-/* ---------- rendering the tree */
63-
64-void RenderRasterizerClass::render_tree()
65-{
66- render_tree(kDiffuse);
67-}
68-
69-void RenderRasterizerClass::render_tree(RenderStep renderStep)
70-{
71- assert(view); // Idiot-proofing
72- assert(RSPtr);
73- assert(RasPtr);
74- vector<sorted_node_data>::iterator node;
75- // LP: reference to simplify the code
76- vector<sorted_node_data>& SortedNodes = RSPtr->SortedNodes;
77-
78- // LP change: added support for semitransparent liquids
79- bool SeeThruLiquids = get_screen_mode()->acceleration != _no_acceleration ? TEST_FLAG(Get_OGL_ConfigureData().Flags,OGL_Flag_LiqSeeThru) : graphics_preferences->software_alpha_blending != _sw_alpha_off;
80-
81- /* walls, ceilings, interior objects, floors, exterior objects for all nodes, back to front */
82- for (node= SortedNodes.begin(); node != SortedNodes.end(); ++node)
83- render_node(&*node, SeeThruLiquids, renderStep);
84-}
85-
86-void RenderRasterizerClass::render_node(
87- sorted_node_data *node,
88- bool SeeThruLiquids,
89- RenderStep renderStep)
90-{
91- polygon_data *polygon= get_polygon_data(node->polygon_index);
92- clipping_window_data *window;
93- render_object_data *object;
94-
95- // LP change: moved this stuff out here because it only has to be calculated
96- // once per polygon.
97- horizontal_surface_data floor_surface, ceiling_surface;
98- short i;
99-
100- ceiling_surface.origin= polygon->ceiling_origin;
101- ceiling_surface.height= polygon->ceiling_height;
102- ceiling_surface.texture= polygon->ceiling_texture;
103- ceiling_surface.lightsource_index= polygon->ceiling_lightsource_index;
104- ceiling_surface.transfer_mode= polygon->ceiling_transfer_mode;
105- ceiling_surface.transfer_mode_data= 0;
106-
107- floor_surface.origin= polygon->floor_origin;
108- floor_surface.height= polygon->floor_height;
109- floor_surface.texture= polygon->floor_texture;
110- floor_surface.lightsource_index= polygon->floor_lightsource_index;
111- floor_surface.transfer_mode= polygon->floor_transfer_mode;
112- floor_surface.transfer_mode_data= 0;
113-
114- // The "continue" conditions are OK to move out here, because a non-drawn polygon's
115- // inhabitants will be clipped away.
116-
117- // LP: get liquid data here for convenience;
118- // pointer to it being NULL means no liquid in the polygon
119- media_data *media = NULL;
120- if (polygon->media_index!=NONE)
121- media = get_media_data(polygon->media_index);
122-
123- /* if necessary, replace the ceiling or floor surfaces with the media surface */
124- // LP change: don't do this step if liquids are semitransparent
125- if (media && !SeeThruLiquids)
126- {
127- // LP change: moved this get upwards
128- // struct media_data *media= get_media_data(polygon->media_index);
129- horizontal_surface_data *media_surface= NULL;
130-
131- if (view->under_media_boundary)
132- {
133- // LP change: skip if high and dry
134- if (media->height <= polygon->floor_height)
135- return;
136-
137- if (media->height<polygon->ceiling_height) media_surface= &ceiling_surface;
138- }
139- else
140- {
141- // LP change: skip if submerged
142- if (media->height >= polygon->ceiling_height)
143- return;
144-
145- if (media->height>polygon->floor_height) media_surface= &floor_surface;
146- }
147-
148- if (media_surface)
149- {
150- media_surface->origin= media->origin;
151- media_surface->height= media->height;
152- media_surface->texture= media->texture;
153- media_surface->lightsource_index= polygon->media_lightsource_index;
154- media_surface->transfer_mode= media->transfer_mode;
155- media_surface->transfer_mode_data= 0;
156- }
157- }
158- // LP change: always render liquids that are semitransparent
159- else if (!SeeThruLiquids)
160- {
161- // if weユre trying to draw a polygon without media from under a polygon with media, donユt
162- if (view->under_media_boundary) return;
163- }
164-
165- // LP: this loop renders the walls
166- for (window= node->clipping_windows; window; window= window->next_window)
167- {
168- if (ceiling_surface.height>floor_surface.height)
169- {
170- /* render ceiling if above viewer */
171- if (ceiling_surface.height>view->origin.z)
172- {
173- // LP change: indicated that the void is on other side
174- render_node_floor_or_ceiling(window, polygon, &ceiling_surface, true, true, renderStep);
175- }
176-
177- /* render visible sides */
178- for (i= 0; i<polygon->vertex_count; ++i)
179- {
180- short side_index= polygon->side_indexes[i];
181-
182- if (side_index!=NONE && TEST_RENDER_FLAG(side_index, _side_is_visible))
183- {
184- line_data *line= get_line_data(polygon->line_indexes[i]);
185- side_data *side= get_side_data(side_index);
186- vertical_surface_data surface;
187-
188- surface.length= line->length;
189- store_endpoint(get_endpoint_data(polygon->endpoint_indexes[i]), surface.p0);
190- store_endpoint(get_endpoint_data(polygon->endpoint_indexes[WRAP_HIGH(i, polygon->vertex_count-1)]), surface.p1);
191- surface.ambient_delta= side->ambient_delta;
192-
193- // LP change: indicate in all cases whether the void is on the other side;
194- // added a workaround for full-side textures with a polygon on the other side
195- bool void_present;
196-
197- switch (side->type)
198- {
199- case _full_side:
200- void_present = true;
201- // Suppress the void if there is a polygon on the other side.
202- if (polygon->adjacent_polygon_indexes[i] != NONE) void_present = false;
203-
204- surface.lightsource_index= side->primary_lightsource_index;
205- surface.h0= floor_surface.height - view->origin.z;
206- surface.hmax= ceiling_surface.height - view->origin.z;
207- surface.h1= polygon->ceiling_height - view->origin.z;
208- surface.texture_definition= &side->primary_texture;
209- surface.transfer_mode= side->primary_transfer_mode;
210- render_node_side(window, &surface, void_present, renderStep);
211- break;
212- case _split_side: /* render _low_side first */
213- surface.lightsource_index= side->secondary_lightsource_index;
214- surface.h0= floor_surface.height - view->origin.z;
215- surface.h1= MAX(line->highest_adjacent_floor, floor_surface.height) - view->origin.z;
216- surface.hmax= ceiling_surface.height - view->origin.z;
217- surface.texture_definition= &side->secondary_texture;
218- surface.transfer_mode= side->secondary_transfer_mode;
219- render_node_side(window, &surface, true, renderStep);
220- /* fall through and render high side */
221- case _high_side:
222- surface.lightsource_index= side->primary_lightsource_index;
223- surface.h0= MIN(line->lowest_adjacent_ceiling, ceiling_surface.height) - view->origin.z;
224- surface.hmax= ceiling_surface.height - view->origin.z;
225- surface.h1= polygon->ceiling_height - view->origin.z;
226- surface.texture_definition= &side->primary_texture;
227- surface.transfer_mode= side->primary_transfer_mode;
228- render_node_side(window, &surface, true, renderStep);
229- // render_node_side(view, destination, window, &surface);
230- break;
231- case _low_side:
232- surface.lightsource_index= side->primary_lightsource_index;
233- surface.h0= floor_surface.height - view->origin.z;
234- surface.h1= MAX(line->highest_adjacent_floor, floor_surface.height) - view->origin.z;
235- surface.hmax= ceiling_surface.height - view->origin.z;
236- surface.texture_definition= &side->primary_texture;
237- surface.transfer_mode= side->primary_transfer_mode;
238- render_node_side(window, &surface, true, renderStep);
239- // render_node_side(view, destination, window, &surface);
240- break;
241-
242- default:
243- assert(false);
244- break;
245- }
246-
247- if (side->transparent_texture.texture!=UNONE)
248- {
249- surface.lightsource_index= side->transparent_lightsource_index;
250- surface.h0= MAX(line->highest_adjacent_floor, floor_surface.height) - view->origin.z;
251- surface.h1= line->lowest_adjacent_ceiling - view->origin.z;
252- surface.hmax= ceiling_surface.height - view->origin.z;
253- surface.texture_definition= &side->transparent_texture;
254- surface.transfer_mode= side->transparent_transfer_mode;
255- render_node_side(window, &surface, false, renderStep);
256- }
257- }
258- }
259-
260- /* render floor if below viewer */
261- if (floor_surface.height<view->origin.z)
262- {
263- // LP change: indicated that the void is on other side
264- render_node_floor_or_ceiling(window, polygon, &floor_surface, true, false, renderStep);
265- }
266- }
267- }
268-
269- // LP: this is for objects on the other side of the liquids;
270- // render them out here if one can see through the liquids
271- if (SeeThruLiquids)
272- {
273- /* render exterior objects (with their own clipping windows) */
274- for (object= node->exterior_objects; object; object= object->next_object)
275- {
276- render_node_object(object, true, renderStep);
277- }
278- }
279-
280- // LP: render the liquid surface after the walls and the stuff behind it
281- // and before the stuff before it.
282- if (media && SeeThruLiquids)
283- {
284-
285- // Render only if between the floor and the ceiling:
286- if (media->height > polygon->floor_height && media->height < polygon->ceiling_height)
287- {
288-
289- // Render the liquids
290- bool ceil = (media->height > view->origin.z);
291- horizontal_surface_data LiquidSurface;
292-
293- LiquidSurface.origin= media->origin;
294- LiquidSurface.height= media->height;
295- LiquidSurface.texture= media->texture;
296- LiquidSurface.lightsource_index= polygon->media_lightsource_index;
297- LiquidSurface.transfer_mode= media->transfer_mode;
298- LiquidSurface.transfer_mode_data= 0;
299-
300- for (window= node->clipping_windows; window; window= window->next_window)
301- {
302- render_node_floor_or_ceiling(window, polygon, &LiquidSurface, false, ceil, renderStep);
303- }
304- }
305- }
306-
307- // LP: this is for objects on the view side of the liquids
308- /* render exterior objects (with their own clipping windows) */
309- for (object= node->exterior_objects; object; object= object->next_object)
310- {
311- render_node_object(object, false, renderStep);
312- }
313-}
314-
315-void RenderRasterizerClass::store_endpoint(
316- endpoint_data *endpoint,
317- long_vector2d& p)
318-{
319- overflow_short_to_long_2d(endpoint->transformed, endpoint->flags, p);
320-}
321-
322-
323-/* ---------- rendering ceilings and floors */
324-
325-// LP change: added "void present on other side" flag
326-void RenderRasterizerClass::render_node_floor_or_ceiling(
327- clipping_window_data *window,
328- polygon_data *polygon,
329- horizontal_surface_data *surface,
330- bool void_present,
331- bool ceil,
332- RenderStep renderStep)
333-{
334- // LP addition: animated-texture support
335- // Extra variable defined so as not to edit the original texture
336- shape_descriptor Texture = AnimTxtr_Translate(surface->texture);
337- if (Texture!=UNONE)
338- {
339- struct polygon_definition textured_polygon;
340- flagged_world_point2d vertices[MAXIMUM_VERTICES_PER_WORLD_POLYGON];
341- world_distance adjusted_height= surface->height-view->origin.z;
342- int32 transformed_height= adjusted_height*view->world_to_screen_y;
343- short vertex_count;
344- short i;
345-
346- /* build transformed vertex list */
347- vertex_count= polygon->vertex_count;
348- for (i=0;i<vertex_count;++i)
349- {
350- // LP change: expanded the transformed-endpoint access
351- long_vector2d temp_vertex;
352- endpoint_data *endpoint = get_endpoint_data(polygon->endpoint_indexes[i]);
353- overflow_short_to_long_2d(endpoint->transformed,endpoint->flags,temp_vertex);
354- vertices[i].x = temp_vertex.i;
355- vertices[i].y = temp_vertex.j;
356- vertices[i].flags= 0;
357- }
358-
359- /* reversing the order in which these two were clipped caused weird problems */
360-
361- /* clip to left and right sides of the window */
362- vertex_count= xy_clip_horizontal_polygon(vertices, vertex_count, &window->left, _clip_left);
363- vertex_count= xy_clip_horizontal_polygon(vertices, vertex_count, &window->right, _clip_right);
364-
365- /* clip to top and bottom sides of the window */
366- vertex_count= z_clip_horizontal_polygon(vertices, vertex_count, &window->top, adjusted_height, _clip_up);
367- vertex_count= z_clip_horizontal_polygon(vertices, vertex_count, &window->bottom, adjusted_height, _clip_down);
368-
369- if (vertex_count)
370- {
371- /* transform the points we have into screen-space (backwards for ceiling polygons) */
372- for (i=0;i<vertex_count;++i)
373- {
374- flagged_world_point2d *world= vertices + (adjusted_height>0 ? vertex_count-i-1 : i);
375- point2d *screen= textured_polygon.vertices + i;
376-
377- switch (world->flags&(_clip_left|_clip_right))
378- {
379- case 0:
380- // LP change: making it long-distance friendly
381- {
382- int32 world_x = world->x ? world->x : 1; // fix for division by zero error
383- int32 screen_x= view->half_screen_width + (world->y*view->world_to_screen_x)/world_x;
384- screen->x= PIN(screen_x, 0, view->screen_width);
385- }
386- break;
387- case _clip_left: screen->x= window->x0; break;
388- case _clip_right: screen->x= window->x1; break;
389- default:
390- screen->x= window->x0;
391- break;
392- }
393-
394- switch (world->flags&(_clip_up|_clip_down))
395- {
396- case 0:
397- // LP change: making it long-distance friendly
398- {
399- int32 world_x = world->x ? world->x : 1; // fix for division by zero error
400- int32 screen_y= view->half_screen_height - transformed_height/world_x + view->dtanpitch;
401- screen->y= PIN(screen_y, 0, view->screen_height);
402- }
403- break;
404- case _clip_up: screen->y= window->y0; break;
405- case _clip_down: screen->y= window->y1; break;
406- default:
407- screen->y= window->y0;
408- break;
409- }
410- // vassert(screen->y>=0&&screen->y<=view->screen_height, csprintf(temporary, "horizontal: flags==%x, window @ %p", world->flags, window));
411- }
412-
413- /* setup the other parameters of the textured polygon */
414- textured_polygon.flags= 0;
415- textured_polygon.origin.x= view->origin.x + surface->origin.x;
416- textured_polygon.origin.y= view->origin.y + surface->origin.y;
417- textured_polygon.origin.z= adjusted_height;
418- get_shape_bitmap_and_shading_table(Texture, &textured_polygon.texture, &textured_polygon.shading_tables, view->shading_mode);
419- // Bug out if bitmap is nonexistent
420- if (!textured_polygon.texture) return;
421-
422- textured_polygon.ShapeDesc = Texture;
423- textured_polygon.ambient_shade= get_light_intensity(surface->lightsource_index);
424- textured_polygon.vertex_count= vertex_count;
425- instantiate_polygon_transfer_mode(view, &textured_polygon, surface->transfer_mode, true);
426- if (view->shading_mode==_shading_infravision) textured_polygon.flags|= _SHADELESS_BIT;
427-
428- /* and, finally, map it */
429- // LP: added OpenGL support; also presence of void on other side
430- textured_polygon.VoidPresent = void_present;
431- // LP: using rasterizer object
432- RasPtr->texture_horizontal_polygon(textured_polygon);
433- }
434- }
435-}
436-
437-/* ---------- rendering sides (walls) */
438-
439-// LP change: added "void present on other side" flag
440-void RenderRasterizerClass::render_node_side(
441- clipping_window_data *window,
442- vertical_surface_data *surface,
443- bool void_present,
444- RenderStep renderStep)
445-{
446- world_distance h= MIN(surface->h1, surface->hmax);
447-
448- // LP addition: animated-texture support
449- // Extra variable defined so as not to edit the original texture
450- shape_descriptor Texture = AnimTxtr_Translate(surface->texture_definition->texture);
451- if (h>surface->h0 && Texture!=UNONE)
452- {
453- struct polygon_definition textured_polygon;
454- flagged_world_point2d posts[2];
455- flagged_world_point3d vertices[MAXIMUM_VERTICES_PER_WORLD_POLYGON];
456- short vertex_count;
457- short i;
458-
459- /* initialize the two posts of our trapezoid */
460- vertex_count= 2;
461- posts[0].x= surface->p0.i; posts[0].y= surface->p0.j; posts[0].flags= 0;
462- posts[1].x= surface->p1.i; posts[1].y= surface->p1.j; posts[1].flags= 0;
463-
464- /* clip to left and right sides of the cone (must happen in the same order as horizontal polygons) */
465- vertex_count= xy_clip_line(posts, vertex_count, &window->left, _clip_left);
466- vertex_count= xy_clip_line(posts, vertex_count, &window->right, _clip_right);
467-
468- if (vertex_count)
469- {
470- /* build a polygon out of the two posts */
471- vertex_count= 4;
472- vertices[0].z= vertices[1].z= h;
473- vertices[2].z= vertices[3].z= surface->h0;
474- vertices[0].x= vertices[3].x= posts[0].x, vertices[0].y= vertices[3].y= posts[0].y;
475- vertices[1].x= vertices[2].x= posts[1].x, vertices[1].y= vertices[2].y= posts[1].y;
476- vertices[0].flags= vertices[3].flags= posts[0].flags;
477- vertices[1].flags= vertices[2].flags= posts[1].flags;
478-
479- /* clip to top and bottom sides of the window; because xz_clip_vertical_polygon accepts
480- vertices in clockwise or counterclockwise order, we can set our vertex list up to be
481- clockwise on the screen and never worry about it after that */
482- vertex_count= xz_clip_vertical_polygon(vertices, vertex_count, &window->top, _clip_up);
483- vertex_count= xz_clip_vertical_polygon(vertices, vertex_count, &window->bottom, _clip_down);
484-
485- if (vertex_count)
486- {
487- world_distance dx= surface->p1.i - surface->p0.i;
488- world_distance dy= surface->p1.j - surface->p0.j;
489- world_distance x0= WORLD_FRACTIONAL_PART(surface->texture_definition->x0);
490- world_distance y0= WORLD_FRACTIONAL_PART(surface->texture_definition->y0);
491-
492- /* calculate texture origin and direction */
493- world_distance divisor = surface->length;
494- if (divisor == 0)
495- divisor = 1;
496- textured_polygon.vector.i= (WORLD_ONE*dx)/divisor;
497- textured_polygon.vector.j= (WORLD_ONE*dy)/divisor;
498- textured_polygon.vector.k= -WORLD_ONE;
499- textured_polygon.origin.x= surface->p0.i - (x0*dx)/divisor;
500- textured_polygon.origin.y= surface->p0.j - (x0*dy)/divisor;
501- textured_polygon.origin.z= surface->h1 + y0;
502-
503- /* transform the points we have into screen-space */
504- for (i=0;i<vertex_count;++i)
505- {
506- flagged_world_point3d *world= vertices + i;
507- point2d *screen= textured_polygon.vertices + i;
508-
509- switch (world->flags&(_clip_left|_clip_right))
510- {
511- case 0:
512- // LP change: making it long-distance friendly
513- {
514- int32 screen_x= view->half_screen_width + (world->x ? (world->y*view->world_to_screen_x)/world->x : 0);
515- screen->x= PIN(screen_x, 0, view->screen_width);
516- }
517- break;
518- case _clip_left: screen->x= window->x0; break;
519- case _clip_right: screen->x= window->x1; break;
520- default:
521- screen->x= window->x0;
522- break;
523- }
524-
525- switch (world->flags&(_clip_up|_clip_down))
526- {
527- case 0:
528- // LP change: making it long-distance friendly
529- {
530- int32 screen_y= view->half_screen_height - (world->x ? (world->z*view->world_to_screen_y)/world->x : 0) + view->dtanpitch;
531- screen->y= PIN(screen_y, 0, view->screen_height);
532- }
533- break;
534- case _clip_up: screen->y= window->y0; break;
535- case _clip_down: screen->y= window->y1; break;
536- default:
537- screen->y= window->y0;
538- break;
539- }
540- // vassert(screen->y>=0&&screen->y<=view->screen_height, csprintf(temporary, "#%d!in[#0,#%d]: flags==%x, wind@%p #%d w@%p s@%p", screen->y, view->screen_height, world->flags, window, vertex_count, world, screen));
541- }
542-
543- /* setup the other parameters of the textured polygon */
544- textured_polygon.flags= 0;
545- get_shape_bitmap_and_shading_table(Texture, &textured_polygon.texture, &textured_polygon.shading_tables, view->shading_mode);
546- // Bug out if bitmap is nonexistent
547- if (!textured_polygon.texture) return;
548-
549- textured_polygon.ShapeDesc = Texture;
550- textured_polygon.ambient_shade= get_light_intensity(surface->lightsource_index) + surface->ambient_delta;
551- textured_polygon.ambient_shade= PIN(textured_polygon.ambient_shade, 0, FIXED_ONE);
552- textured_polygon.vertex_count= vertex_count;
553- instantiate_polygon_transfer_mode(view, &textured_polygon, surface->transfer_mode, false);
554- if (view->shading_mode==_shading_infravision) textured_polygon.flags|= _SHADELESS_BIT;
555-
556- /* and, finally, map it */
557- // LP: added OpenGL support; also presence of void on other side
558- textured_polygon.VoidPresent = void_present;
559- // LP: using rasterizer object
560- RasPtr->texture_vertical_polygon(textured_polygon);
561- }
562- }
563- }
564-}
565-
566-/* ---------- rendering objects */
567-
568-void RenderRasterizerClass::render_node_object(
569- render_object_data *object,
570- bool other_side_of_media,
571- RenderStep renderStep)
572-{
573- struct clipping_window_data *window;
574-
575- for (window= object->clipping_windows; window; window= window->next_window)
576- {
577- object->rectangle.clip_left= window->x0;
578- object->rectangle.clip_right= window->x1;
579- object->rectangle.clip_top= window->y0;
580- object->rectangle.clip_bottom= window->y1;
581-
582- // Models will have their own liquid-surface clipping,
583- // so don't edit their clip rects
584- // This is bitwise XOR, but is presumably OK here
585- if (view->under_media_boundary ^ other_side_of_media)
586- {
587- // Clipping: below a liquid surface
588- if (object->rectangle.ModelPtr)
589- object->rectangle.BelowLiquid = true;
590- else
591- object->rectangle.clip_top= MAX(object->rectangle.clip_top, object->ymedia);
592- }
593- else
594- {
595- // Clipping: above a liquid surface
596- if (object->rectangle.ModelPtr)
597- object->rectangle.BelowLiquid = false;
598- else
599- object->rectangle.clip_bottom= MIN(object->rectangle.clip_bottom, object->ymedia);
600- }
601-
602- // LP: added OpenGL support
603- // LP: using rasterizer object
604- RasPtr->texture_rectangle(object->rectangle);
605- }
606-}
607-
608-
609-/* ---------- horizontal polygon clipping */
610-
611-enum /* xy_clip_horizontal_polygon() states */
612-{
613- _testing_first_vertex, /* are we in or out? */
614- _searching_cw_for_in_out_transition,
615- _searching_ccw_for_out_in_transition,
616- _searching_cw_for_out_in_transition
617-};
618-
619-// LP change: make it better able to do long-distance views
620-short RenderRasterizerClass::xy_clip_horizontal_polygon(
621- flagged_world_point2d *vertices,
622- short vertex_count,
623- long_vector2d *line,
624- uint16 flag)
625-{
626-#ifdef QUICKDRAW_DEBUG
627- debug_flagged_points(vertices, vertex_count);
628- debug_vector(line);
629-#endif
630-// dprintf("clipping %p (#%d vertices) to vector %x,%x (slope==%x)", vertices, vertex_count, line->i, line->j, slope);
631-
632- if (vertex_count)
633- {
634- short state= _testing_first_vertex;
635- short vertex_index= 0, vertex_delta= 1, first_vertex= 0;
636- short entrance_vertex= NONE, exit_vertex= NONE; /* exiting the clipped area and entering the clipped area */
637- bool clipped_exit_vertex= true, clipped_entrance_vertex= true; /* will be false if these points lie directly on a vertex */
638-
639- do
640- {
641- // LP change:
642- CROSSPROD_TYPE cross_product= CROSSPROD_TYPE(line->i)*vertices[vertex_index].y - CROSSPROD_TYPE(line->j)*vertices[vertex_index].x;
643- // int32 cross_product= line->i*vertices[vertex_index].y - line->j*vertices[vertex_index].x;
644-
645- switch (SGN(cross_product))
646- {
647- case -1: /* inside (i.e., will be clipped) */
648-// dprintf("vertex#%d is inside s==#%d", vertex_index, state);
649- switch (state)
650- {
651- case _testing_first_vertex:
652- first_vertex= vertex_index;
653- state= _searching_cw_for_in_out_transition; /* the exit point from the clip area */
654- break;
655-
656- case _searching_ccw_for_out_in_transition: /* found exit point from clip area */
657- state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
658- vertex_delta= 1;
659- if (exit_vertex==NONE) exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
660- vertex_index= first_vertex; /* skip vertices we already know are out */
661- break;
662-
663- case _searching_cw_for_out_in_transition: /* found entrance point to clipped area */
664- if (entrance_vertex==NONE) entrance_vertex= vertex_index;
665- state= NONE;
666- break;
667- }
668- break;
669-
670- case 0: /* clip line passed directly through a vertex */
671-// dprintf("vertex#%d is on the clip line s==#%d", vertex_index, state);
672- switch (state)
673- {
674- /* if weユre testing the first vertex, this tells us nothing */
675-
676- case _searching_cw_for_out_in_transition:
677- entrance_vertex= vertex_index;
678- clipped_entrance_vertex= false; /* remember if this passes through vertex */
679- break;
680-
681- case _searching_cw_for_in_out_transition:
682- exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
683- clipped_exit_vertex= false;
684- break;
685- case _searching_ccw_for_out_in_transition:
686- exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
687- clipped_exit_vertex= false; /* remember if this passes through vertex */
688- break;
689- }
690- break;
691-
692- case 1: /* outside (i.e., will not be clipped) */
693-// dprintf("vertex#%d is outside s==#%d", vertex_index, state);
694- switch (state)
695- {
696- case _testing_first_vertex:
697- first_vertex= vertex_index;
698- state= _searching_ccw_for_out_in_transition; /* the exit point from the clipped area */
699- vertex_delta= -1;
700- break;
701-
702- case _searching_cw_for_in_out_transition: /* found exit point from clipped area */
703- state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
704- if (exit_vertex==NONE) exit_vertex= vertex_index;
705- break;
706- }
707- break;
708- }
709-
710- /* adjust vertex_index (clockwise or counterclockwise, depending on vertex_delta)
711- if weユve come back to the first vertex without finding an entrance point weユre
712- either all the way in or all the way out */
713- vertex_index= (vertex_delta<0) ? WRAP_LOW(vertex_index, vertex_count-1) :
714- WRAP_HIGH(vertex_index, vertex_count-1);
715- if (vertex_index==first_vertex) /* we came full-circle without hitting anything */
716- {
717- switch (state)
718- {
719- case _searching_cw_for_in_out_transition: /* never found a way out: clipped into nothing */
720- vertex_count= 0;
721- case _testing_first_vertex: /* is this the right thing to do? */
722- case _searching_ccw_for_out_in_transition: /* never found a way in: no clipping */
723- exit_vertex= NONE;
724- state= NONE;
725- break;
726- }
727- }
728- }
729- while (state!=NONE);
730-
731- if (exit_vertex!=NONE) /* weユve got clipping to do */
732- {
733- flagged_world_point2d new_entrance_point, new_exit_point;
734-
735-// dprintf("entrance_vertex==#%d (%s), exit_vertex==#%d (%s)", entrance_vertex, clipped_entrance_vertex ? "clipped" : "unclipped", exit_vertex, clipped_exit_vertex ? "clipped" : "unclipped");
736-
737- /* clip the entrance to the clipped area */
738- if (clipped_entrance_vertex)
739- {
740- xy_clip_flagged_world_points(vertices + WRAP_LOW(entrance_vertex, vertex_count-1), vertices + entrance_vertex,
741- &new_entrance_point, line);
742- }
743- else
744- {
745- new_entrance_point= vertices[entrance_vertex];
746- }
747- new_entrance_point.flags|= flag;
748-
749- /* clip the exit from the clipped area */
750- if (clipped_exit_vertex)
751- {
752- xy_clip_flagged_world_points(vertices + WRAP_LOW(exit_vertex, vertex_count-1), vertices + exit_vertex,
753- &new_exit_point, line);
754- }
755- else
756- {
757- new_exit_point= vertices[WRAP_LOW(exit_vertex, vertex_count-1)];
758- }
759- new_exit_point.flags|= flag;
760-
761- /* adjust for the change in number of vertices */
762- vertex_delta= entrance_vertex - exit_vertex;
763- if (vertex_delta<0)
764- {
765- if (vertex_delta!=-2) memmove(vertices+entrance_vertex+2, vertices+exit_vertex, (vertex_count-exit_vertex)*sizeof(flagged_world_point2d));
766- vertex_delta= vertex_count+vertex_delta;
767- }
768- else
769- {
770- /* move down by exit_vertex, add new vertices to end */
771- assert(vertex_delta);
772- if (exit_vertex)
773- {
774- memmove(vertices, vertices+exit_vertex, vertex_delta*sizeof(flagged_world_point2d));
775- entrance_vertex-= exit_vertex;
776- }
777- }
778-
779- vertex_count= vertex_delta+2;
780- vwarn(vertex_count>=3 && vertex_count<=MAXIMUM_VERTICES_PER_WORLD_POLYGON,
781- csprintf(temporary, "vertex overflow or underflow (#%d);g;", vertex_count));
782-
783- if (vertex_count<3 || vertex_count>MAXIMUM_VERTICES_PER_WORLD_POLYGON)
784- {
785- vertex_count= 0;
786- }
787- else
788- {
789- /* and, finally, add the new vertices */
790- vertices[entrance_vertex]= new_entrance_point;
791- vertices[entrance_vertex+1]= new_exit_point;
792- }
793- }
794- }
795-
796-#ifdef QUICKDRAW_DEBUG
797- debug_flagged_points(vertices, vertex_count);
798- debug_vector(line);
799-#endif
800-// dprintf("result == %p (#%d vertices)", vertices, vertex_count);
801-
802- return vertex_count;
803-}
804-
805-/* sort points before clipping to assure consistency; there is a way to make this more accurate
806- but it requires the downshifting game, as played in SCOTTISH_TEXTURES.C. itユs tempting to
807- think that having a smaller scale for our world coordinates would help here (i.e., less bits
808- per distance) but then wouldnユt we be screwed when we tried to rotate? */
809-// LP change: make it better able to do long-distance views
810-void RenderRasterizerClass::xy_clip_flagged_world_points(
811- flagged_world_point2d *p0,
812- flagged_world_point2d *p1,
813- flagged_world_point2d *clipped,
814- long_vector2d *line)
815-{
816- bool swap= (p1->y>p0->y) ? false : ((p0->y==p1->y) ? (p1->x<p0->x) : true);
817- flagged_world_point2d *local_p0= swap ? p1 : p0;
818- flagged_world_point2d *local_p1= swap ? p0 : p1;
819- world_distance dx= local_p1->x - local_p0->x;
820- world_distance dy= local_p1->y - local_p0->y;
821- int32 numerator= line->j*local_p0->x - line->i*local_p0->y;
822- int32 denominator= line->i*dy - line->j*dx;
823- short shift_count= FIXED_FRACTIONAL_BITS;
824- _fixed t;
825-
826- /* give numerator 16 significant bits over denominator and then calculate t==n/d; MPWユs PPCC
827- didnユt seem to like (INT32_MIN>>1) and i had to substitute 0xc0000000 instead (hmmm) */
828- while (numerator<=(int32)0x3fffffff && numerator>=(int32)0xc0000000 && shift_count--) numerator<<= 1;
829- if (shift_count>0) denominator>>= shift_count;
830- t= numerator;
831- if (denominator)
832- t /= denominator;
833-
834- /* calculate the clipped point */
835- clipped->x= local_p0->x + FIXED_INTEGERAL_PART(t*dx);
836- clipped->y= local_p0->y + FIXED_INTEGERAL_PART(t*dy);
837- clipped->flags= local_p0->flags&local_p1->flags;
838-}
839-
840-/* almost wholly identical to xz_clip_vertical_polygon() except that this works off 2d points
841- in the xy-plane and a height */
842-// LP change: make it better able to do long-distance views
843-short RenderRasterizerClass::z_clip_horizontal_polygon(
844- flagged_world_point2d *vertices,
845- short vertex_count,
846- long_vector2d *line, /* i==x, j==z */
847- world_distance height,
848- uint16 flag)
849-{
850- CROSSPROD_TYPE heighti= CROSSPROD_TYPE(line->i)*height;
851-
852-#ifdef QUICKDRAW_DEBUG
853- debug_flagged_points(vertices, vertex_count);
854- debug_x_line(line->j ? (line->i*height)/line->j : (height<0 ? INT32_MIN : INT32_MAX));
855-#endif
856-// dprintf("clipping %p (#%d vertices) to vector %x,%x", vertices, vertex_count, line->i, line->j);
857-
858- if (vertex_count)
859- {
860- short state= _testing_first_vertex;
861- short vertex_index= 0, vertex_delta= 1, first_vertex= 0;
862- short entrance_vertex= NONE, exit_vertex= NONE; /* exiting the clipped area and entering the clipped area */
863- bool clipped_exit_vertex= true, clipped_entrance_vertex= true; /* will be false if these points lie directly on a vertex */
864-
865- do
866- {
867- CROSSPROD_TYPE cross_product= heighti - CROSSPROD_TYPE(line->j)*vertices[vertex_index].x;
868-
869- if (cross_product<0) /* inside (i.e., will be clipped) */
870- {
871- switch (state)
872- {
873- case _testing_first_vertex:
874- first_vertex= vertex_index;
875- state= _searching_cw_for_in_out_transition; /* the exit point from the clip area */
876- break;
877-
878- case _searching_ccw_for_out_in_transition: /* found exit point from clip area */
879- state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
880- vertex_delta= 1;
881- if (exit_vertex==NONE) exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
882- vertex_index= first_vertex; /* skip vertices we already know are out */
883- break;
884-
885- case _searching_cw_for_out_in_transition: /* found entrance point to clipped area */
886- if (entrance_vertex==NONE) entrance_vertex= vertex_index;
887- state= NONE;
888- break;
889- }
890- }
891- else
892- {
893- if (cross_product>0) /* outside (i.e., will not be clipped) */
894- {
895- switch (state)
896- {
897- case _testing_first_vertex:
898- first_vertex= vertex_index;
899- state= _searching_ccw_for_out_in_transition; /* the exit point from the clipped area */
900- vertex_delta= -1;
901- break;
902-
903- case _searching_cw_for_in_out_transition: /* found exit point from clipped area */
904- state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
905- if (exit_vertex==NONE) exit_vertex= vertex_index;
906- break;
907- }
908- }
909- else /* clip line passed directly through a vertex */
910- {
911- switch (state)
912- {
913- /* if weユre testing the first vertex (_testing_first_vertex), this tells us nothing */
914-
915- case _searching_cw_for_out_in_transition:
916- entrance_vertex= vertex_index;
917- clipped_entrance_vertex= false; /* remember if this passes through vertex */
918- break;
919-
920- case _searching_cw_for_in_out_transition:
921- exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
922- clipped_exit_vertex= false;
923- break;
924- case _searching_ccw_for_out_in_transition:
925- exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
926- clipped_exit_vertex= false; /* remember if this passes through vertex */
927- break;
928- }
929- }
930- }
931-
932- /* adjust vertex_index (clockwise or counterclockwise, depending on vertex_delta)
933- if weユve come back to the first vertex without finding an entrance point weユre
934- either all the way in or all the way out */
935- vertex_index= (vertex_delta<0) ? WRAP_LOW(vertex_index, vertex_count-1) :
936- WRAP_HIGH(vertex_index, vertex_count-1);
937- if (vertex_index==first_vertex) /* we came full-circle without hitting anything */
938- {
939- switch (state)
940- {
941- case _searching_cw_for_in_out_transition: /* never found a way out: clipped into nothing */
942- vertex_count= 0;
943- case _testing_first_vertex: /* is this the right thing to do? */
944- case _searching_ccw_for_out_in_transition: /* never found a way in: no clipping */
945- exit_vertex= NONE;
946- state= NONE;
947- break;
948- }
949- }
950- }
951- while (state!=NONE);
952-
953- if (exit_vertex!=NONE) /* weユve got clipping to do */
954- {
955- flagged_world_point2d new_entrance_point, new_exit_point;
956-
957-// dprintf("entrance_vertex==#%d (%s), exit_vertex==#%d (%s)", entrance_vertex, clipped_entrance_vertex ? "clipped" : "unclipped", exit_vertex, clipped_exit_vertex ? "clipped" : "unclipped");
958-
959- /* clip the entrance to the clipped area */
960- if (clipped_entrance_vertex)
961- {
962- z_clip_flagged_world_points(vertices + WRAP_LOW(entrance_vertex, vertex_count-1), vertices + entrance_vertex,
963- height, &new_entrance_point, line);
964- }
965- else
966- {
967- new_entrance_point= vertices[entrance_vertex];
968- }
969- new_entrance_point.flags|= flag;
970-
971- /* clip the exit from the clipped area */
972- if (clipped_exit_vertex)
973- {
974- z_clip_flagged_world_points(vertices + WRAP_LOW(exit_vertex, vertex_count-1), vertices + exit_vertex,
975- height, &new_exit_point, line);
976- }
977- else
978- {
979- new_exit_point= vertices[WRAP_LOW(exit_vertex, vertex_count-1)];
980- }
981- new_exit_point.flags|= flag;
982-
983- /* adjust for the change in number of vertices */
984- vertex_delta= entrance_vertex - exit_vertex;
985- if (vertex_delta<0)
986- {
987- if (vertex_delta!=-2) memmove(vertices+entrance_vertex+2, vertices+exit_vertex, (vertex_count-exit_vertex)*sizeof(flagged_world_point2d));
988- vertex_delta= vertex_count+vertex_delta;
989- }
990- else
991- {
992- /* move down by exit_vertex, add new vertices to end */
993- assert(vertex_delta);
994- if (exit_vertex)
995- {
996- memmove(vertices, vertices+exit_vertex, vertex_delta*sizeof(flagged_world_point2d));
997- entrance_vertex-= exit_vertex;
998- }
999- }
1000- vertex_count= vertex_delta+2;
1001-
1002- vwarn(vertex_count>=3 && vertex_count<=MAXIMUM_VERTICES_PER_WORLD_POLYGON,
1003- csprintf(temporary, "vertex overflow or underflow (#%d);g;", vertex_count));
1004-
1005- if (vertex_count<3 || vertex_count>MAXIMUM_VERTICES_PER_WORLD_POLYGON)
1006- {
1007- vertex_count= 0;
1008- }
1009- else
1010- {
1011- /* and, finally, add the new vertices */
1012- vertices[entrance_vertex]= new_entrance_point;
1013- vertices[entrance_vertex+1]= new_exit_point;
1014- }
1015- }
1016- }
1017-
1018-#ifdef QUICKDRAW_DEBUG
1019- debug_flagged_points(vertices, vertex_count);
1020- debug_x_line(line->j ? (line->i*height)/line->j : (height<0 ? INT32_MIN : INT32_MAX));
1021-#endif
1022-// dprintf("result == %p (#%d vertices)", vertices, vertex_count);
1023-
1024- return vertex_count;
1025-}
1026-
1027-/* sort points before clipping to assure consistency; this is almost identical to xz_clipノ()
1028- except that it clips 2d points in the xy-plane at the given height. */
1029-// LP change: make it better able to do long-distance views
1030-void RenderRasterizerClass::z_clip_flagged_world_points(
1031- flagged_world_point2d *p0,
1032- flagged_world_point2d *p1,
1033- world_distance height,
1034- flagged_world_point2d *clipped,
1035- long_vector2d *line)
1036-{
1037- bool swap= (p1->y>p0->y) ? false : ((p0->y==p1->y) ? (p1->x<p0->x) : true);
1038- flagged_world_point2d *local_p0= swap ? p1 : p0;
1039- flagged_world_point2d *local_p1= swap ? p0 : p1;
1040- world_distance dx= local_p1->x - local_p0->x;
1041- world_distance dy= local_p1->y - local_p0->y;
1042- int32 numerator= line->j*local_p0->x - line->i*height;
1043- int32 denominator= - line->j*dx;
1044- short shift_count= FIXED_FRACTIONAL_BITS;
1045- _fixed t;
1046-
1047- /* give numerator 16 significant bits over denominator and then calculate t==n/d; MPWユs PPCC
1048- didnユt seem to like (INT32_MIN>>1) and i had to substitute 0xc0000000 instead (hmmm) */
1049- while (numerator<=(int32)0x3fffffff && numerator>=(int32)0xc0000000 && shift_count--) numerator<<= 1;
1050- if (shift_count>0) denominator>>= shift_count;
1051- t= numerator;
1052- if (denominator)
1053- t /= denominator;
1054-
1055- /* calculate the clipped point */
1056- clipped->x= local_p0->x + FIXED_INTEGERAL_PART(t*dx);
1057- clipped->y= local_p0->y + FIXED_INTEGERAL_PART(t*dy);
1058- clipped->flags= local_p0->flags&local_p1->flags;
1059-}
1060-
1061-/* ---------- vertical polygon clipping */
1062-
1063-// LP change: make it better able to do long-distance views
1064-short RenderRasterizerClass::xy_clip_line(
1065- flagged_world_point2d *posts,
1066- short vertex_count,
1067- long_vector2d *line,
1068- uint16 flag)
1069-{
1070-#ifdef QUICKDRAW_DEBUG
1071-// debug_flagged_points(posts, vertex_count);
1072-// debug_vector(line);
1073-#endif
1074-// dprintf("clipping %p (#%d) to line (%d,%d)", posts, vertex_count, line->i, line->j);
1075-
1076- if (vertex_count)
1077- {
1078- CROSSPROD_TYPE cross_product0= CROSSPROD_TYPE(line->i)*posts[0].y - CROSSPROD_TYPE(line->j)*posts[0].x;
1079- CROSSPROD_TYPE cross_product1= CROSSPROD_TYPE(line->i)*posts[1].y - CROSSPROD_TYPE(line->j)*posts[1].x;
1080-
1081- if (cross_product0<0)
1082- {
1083- if (cross_product1<0) /* clipped out of existence */
1084- {
1085- vertex_count= 0;
1086- }
1087- else
1088- {
1089- xy_clip_flagged_world_points(&posts[0], &posts[1], &posts[0], line);
1090- posts[0].flags|= flag;
1091- }
1092- }
1093- else
1094- {
1095- if (cross_product1<0)
1096- {
1097- xy_clip_flagged_world_points(&posts[0], &posts[1], &posts[1], line);
1098- posts[1].flags|= flag;
1099- }
1100- }
1101- }
1102-
1103-#ifdef QUICKDRAW_DEBUG
1104-// debug_flagged_points(posts, vertex_count);
1105-// debug_vector(line);
1106-#endif
1107-// dprintf("result #%d vertices", vertex_count);
1108-
1109- return vertex_count;
1110-}
1111-
1112-// LP change: make it better able to do long-distance views
1113-short RenderRasterizerClass::xz_clip_vertical_polygon(
1114- flagged_world_point3d *vertices,
1115- short vertex_count,
1116- long_vector2d *line, /* i==x, j==z */
1117- uint16 flag)
1118-{
1119-#ifdef QUICKDRAW_DEBUG
1120-// debug_flagged_points3d(vertices, vertex_count);
1121-// debug_vector(line);
1122-#endif
1123-// dprintf("clipping %p (#%d vertices) to vector %x,%x", vertices, vertex_count, line->i, line->j);
1124-
1125- if (vertex_count)
1126- {
1127- short state= _testing_first_vertex;
1128- short vertex_index= 0, vertex_delta= 1, first_vertex= 0;
1129- short entrance_vertex= NONE, exit_vertex= NONE; /* exiting the clipped area and entering the clipped area */
1130- bool clipped_exit_vertex= true, clipped_entrance_vertex= true; /* will be false if these points lie directly on a vertex */
1131-
1132- do
1133- {
1134- CROSSPROD_TYPE cross_product= CROSSPROD_TYPE(line->i)*vertices[vertex_index].z - CROSSPROD_TYPE(line->j)*vertices[vertex_index].x;
1135-
1136- switch (SGN(cross_product))
1137- {
1138- case -1: /* inside (i.e., will be clipped) */
1139-// dprintf("vertex#%d is inside s==#%d", vertex_index, state);
1140- switch (state)
1141- {
1142- case _testing_first_vertex:
1143- first_vertex= vertex_index;
1144- state= _searching_cw_for_in_out_transition; /* the exit point from the clip area */
1145- break;
1146-
1147- case _searching_ccw_for_out_in_transition: /* found exit point from clip area */
1148- state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
1149- vertex_delta= 1;
1150- if (exit_vertex==NONE) exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
1151- vertex_index= first_vertex; /* skip vertices we already know are out */
1152- break;
1153-
1154- case _searching_cw_for_out_in_transition: /* found entrance point to clipped area */
1155- if (entrance_vertex==NONE) entrance_vertex= vertex_index;
1156- state= NONE;
1157- break;
1158- }
1159- break;
1160-
1161- case 0: /* clip line passed directly through a vertex */
1162-// dprintf("vertex#%d is on the clip line s==#%d", vertex_index, state);
1163- switch (state)
1164- {
1165- /* if weユre testing the first vertex, this tells us nothing */
1166-
1167- case _searching_cw_for_out_in_transition:
1168- entrance_vertex= vertex_index;
1169- clipped_entrance_vertex= false; /* remember if this passes through vertex */
1170- break;
1171-
1172- case _searching_cw_for_in_out_transition:
1173- exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
1174- clipped_exit_vertex= false;
1175- break;
1176- case _searching_ccw_for_out_in_transition:
1177- exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
1178- clipped_exit_vertex= false; /* remember if this passes through vertex */
1179- break;
1180- }
1181- break;
1182-
1183- case 1: /* outside (i.e., will not be clipped) */
1184-// dprintf("vertex#%d is outside s==#%d", vertex_index, state);
1185- switch (state)
1186- {
1187- case _testing_first_vertex:
1188- first_vertex= vertex_index;
1189- state= _searching_ccw_for_out_in_transition; /* the exit point from the clipped area */
1190- vertex_delta= -1;
1191- break;
1192-
1193- case _searching_cw_for_in_out_transition: /* found exit point from clipped area */
1194- state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
1195- if (exit_vertex==NONE) exit_vertex= vertex_index;
1196- break;
1197- }
1198- break;
1199- }
1200-
1201- /* adjust vertex_index (clockwise or counterclockwise, depending on vertex_delta)
1202- if weユve come back to the first vertex without finding an entrance point weユre
1203- either all the way in or all the way out */
1204- vertex_index= (vertex_delta<0) ? WRAP_LOW(vertex_index, vertex_count-1) :
1205- WRAP_HIGH(vertex_index, vertex_count-1);
1206- if (vertex_index==first_vertex) /* we came full-circle without hitting anything */
1207- {
1208- switch (state)
1209- {
1210- case _searching_cw_for_in_out_transition: /* never found a way out: clipped into nothing */
1211- vertex_count= 0;
1212- case _testing_first_vertex: /* is this the right thing to do? */
1213- case _searching_ccw_for_out_in_transition: /* never found a way in: no clipping */
1214- exit_vertex= NONE;
1215- state= NONE;
1216- break;
1217- }
1218- }
1219- }
1220- while (state!=NONE);
1221-
1222- if (exit_vertex!=NONE) /* weユve got clipping to do */
1223- {
1224- flagged_world_point3d new_entrance_point, new_exit_point;
1225-
1226-// dprintf("entrance_vertex==#%d (%s), exit_vertex==#%d (%s)", entrance_vertex, clipped_entrance_vertex ? "clipped" : "unclipped", exit_vertex, clipped_exit_vertex ? "clipped" : "unclipped");
1227-
1228- /* clip the entrance to the clipped area */
1229- if (clipped_entrance_vertex)
1230- {
1231- xz_clip_flagged_world_points(vertices + WRAP_LOW(entrance_vertex, vertex_count-1), vertices + entrance_vertex,
1232- &new_entrance_point, line);
1233- }
1234- else
1235- {
1236- new_entrance_point= vertices[entrance_vertex];
1237- }
1238- new_entrance_point.flags|= flag;
1239-
1240- /* clip the exit from the clipped area */
1241- if (clipped_exit_vertex)
1242- {
1243- xz_clip_flagged_world_points(vertices + WRAP_LOW(exit_vertex, vertex_count-1), vertices + exit_vertex,
1244- &new_exit_point, line);
1245- }
1246- else
1247- {
1248- new_exit_point= vertices[WRAP_LOW(exit_vertex, vertex_count-1)];
1249- }
1250- new_exit_point.flags|= flag;
1251-
1252- /* adjust for the change in number of vertices */
1253- vertex_delta= entrance_vertex - exit_vertex;
1254- if (vertex_delta<0)
1255- {
1256- if (vertex_delta!=-2) memmove(vertices+entrance_vertex+2, vertices+exit_vertex, (vertex_count-exit_vertex)*sizeof(flagged_world_point3d));
1257- vertex_delta= vertex_count+vertex_delta;
1258- }
1259- else
1260- {
1261- /* move down by exit_vertex, add new vertices to end */
1262- assert(vertex_delta);
1263- if (exit_vertex)
1264- {
1265- memmove(vertices, vertices+exit_vertex, vertex_delta*sizeof(flagged_world_point3d));
1266- entrance_vertex-= exit_vertex;
1267- }
1268- }
1269- vertex_count= vertex_delta+2;
1270-
1271- vwarn(vertex_count>=3 && vertex_count<=MAXIMUM_VERTICES_PER_WORLD_POLYGON,
1272- csprintf(temporary, "vertex overflow or underflow (#%d);g;", vertex_count));
1273-
1274- if (vertex_count<3 || vertex_count>MAXIMUM_VERTICES_PER_WORLD_POLYGON)
1275- {
1276- vertex_count= 0;
1277- }
1278- else
1279- {
1280- /* and, finally, add the new vertices */
1281- vertices[entrance_vertex]= new_entrance_point;
1282- vertices[entrance_vertex+1]= new_exit_point;
1283- }
1284- }
1285- }
1286-
1287-#ifdef QUICKDRAW_DEBUG
1288-// debug_flagged_points3d(vertices, vertex_count);
1289-// debug_vector(line);
1290-#endif
1291-// dprintf("result == %p (#%d vertices)", vertices, vertex_count);
1292-
1293- return vertex_count;
1294-}
1295-
1296-/* sort points before clipping to assure consistency */
1297-// LP change: make it better able to do long-distance views
1298-void RenderRasterizerClass::xz_clip_flagged_world_points(
1299- flagged_world_point3d *p0,
1300- flagged_world_point3d *p1,
1301- flagged_world_point3d *clipped,
1302- long_vector2d *line)
1303-{
1304- bool swap= (p1->y>p0->y) ? false : ((p0->y==p1->y) ? (p1->x<p0->x) : true);
1305- flagged_world_point3d *local_p0= swap ? p1 : p0;
1306- flagged_world_point3d *local_p1= swap ? p0 : p1;
1307- world_distance dx= local_p1->x - local_p0->x;
1308- world_distance dy= local_p1->y - local_p0->y;
1309- world_distance dz= local_p1->z - local_p0->z;
1310- int32 numerator= line->j*local_p0->x - line->i*local_p0->z;
1311- int32 denominator= line->i*dz - line->j*dx;
1312- short shift_count= FIXED_FRACTIONAL_BITS;
1313- _fixed t;
1314-
1315- /* give numerator 16 significant bits over denominator and then calculate t==n/d; MPWユs PPCC
1316- didnユt seem to like (INT32_MIN>>1) and i had to substitute 0xc0000000 instead (hmmm) */
1317- while (numerator<=(int32)0x3fffffff && numerator>=(int32)0xc0000000 && shift_count--) numerator<<= 1;
1318- if (shift_count>0) denominator>>= shift_count;
1319- t = numerator;
1320- if (denominator)
1321- t /= denominator;
1322-
1323- /* calculate the clipped point */
1324- clipped->x= local_p0->x + FIXED_INTEGERAL_PART(t*dx);
1325- clipped->y= local_p0->y + FIXED_INTEGERAL_PART(t*dy);
1326- clipped->z= local_p0->z + FIXED_INTEGERAL_PART(t*dz);
1327- clipped->flags= local_p0->flags&local_p1->flags;
1328-}
1+/*
2+
3+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4+ and the "Aleph One" developers.
5+
6+ This program is free software; you can redistribute it and/or modify
7+ it under the terms of the GNU General Public License as published by
8+ the Free Software Foundation; either version 3 of the License, or
9+ (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU General Public License for more details.
15+
16+ This license is contained in the file "COPYING",
17+ which is included with this source code; it is available online at
18+ http://www.gnu.org/licenses/gpl.html
19+
20+ Rendering Clipping/Rasterization Class
21+ by Loren Petrich,
22+ August 7, 2000
23+
24+ Contains the calculation of clipping and rasterization; from render.c
25+
26+ Made [view_data *view] a member and removed it as an argument
27+ Also removed [bitmap_definition *destination] as superfluous,
28+ now that there is a special rasterizer object that can contain it.
29+
30+Sep 2, 2000 (Loren Petrich):
31+ Added some idiot-proofing, since the shapes accessor now returns NULL for nonexistent bitmaps
32+
33+ If a polygon has a "full_side" texture, and there is another polgyon on the other side,
34+ then suppress the void for the boundary's texture.
35+*/
36+
37+#include "cseries.h"
38+
39+#include "map.h"
40+#include "lightsource.h"
41+#include "media.h"
42+#include "RenderRasterize.h"
43+#include "AnimatedTextures.h"
44+#include "OGL_Setup.h"
45+#include "preferences.h"
46+#include "screen.h"
47+
48+#include <string.h>
49+
50+
51+/* maximum number of vertices a polygon can be world-clipped into (one per clip line) */
52+#define MAXIMUM_VERTICES_PER_WORLD_POLYGON (MAXIMUM_VERTICES_PER_POLYGON+4)
53+
54+
55+RenderRasterizerClass::RenderRasterizerClass():
56+ view(NULL), // Idiot-proofing
57+ RSPtr(NULL),
58+ RasPtr(NULL)
59+{}
60+
61+
62+/* ---------- rendering the tree */
63+
64+void RenderRasterizerClass::render_tree()
65+{
66+ render_tree(kDiffuse);
67+}
68+
69+void RenderRasterizerClass::render_tree(RenderStep renderStep)
70+{
71+ assert(view); // Idiot-proofing
72+ assert(RSPtr);
73+ assert(RasPtr);
74+ vector<sorted_node_data>::iterator node;
75+ // LP: reference to simplify the code
76+ vector<sorted_node_data>& SortedNodes = RSPtr->SortedNodes;
77+
78+ // LP change: added support for semitransparent liquids
79+ bool SeeThruLiquids = get_screen_mode()->acceleration != _no_acceleration ? TEST_FLAG(Get_OGL_ConfigureData().Flags,OGL_Flag_LiqSeeThru) : graphics_preferences->software_alpha_blending != _sw_alpha_off;
80+
81+ /* walls, ceilings, interior objects, floors, exterior objects for all nodes, back to front */
82+ for (node= SortedNodes.begin(); node != SortedNodes.end(); ++node)
83+ render_node(&*node, SeeThruLiquids, renderStep);
84+}
85+
86+void RenderRasterizerClass::render_node(
87+ sorted_node_data *node,
88+ bool SeeThruLiquids,
89+ RenderStep renderStep)
90+{
91+ polygon_data *polygon= get_polygon_data(node->polygon_index);
92+ clipping_window_data *window;
93+ render_object_data *object;
94+
95+ // LP change: moved this stuff out here because it only has to be calculated
96+ // once per polygon.
97+ horizontal_surface_data floor_surface, ceiling_surface;
98+ short i;
99+
100+ ceiling_surface.origin= polygon->ceiling_origin;
101+ ceiling_surface.height= polygon->ceiling_height;
102+ ceiling_surface.texture= polygon->ceiling_texture;
103+ ceiling_surface.lightsource_index= polygon->ceiling_lightsource_index;
104+ ceiling_surface.transfer_mode= polygon->ceiling_transfer_mode;
105+ ceiling_surface.transfer_mode_data= 0;
106+
107+ floor_surface.origin= polygon->floor_origin;
108+ floor_surface.height= polygon->floor_height;
109+ floor_surface.texture= polygon->floor_texture;
110+ floor_surface.lightsource_index= polygon->floor_lightsource_index;
111+ floor_surface.transfer_mode= polygon->floor_transfer_mode;
112+ floor_surface.transfer_mode_data= 0;
113+
114+ // The "continue" conditions are OK to move out here, because a non-drawn polygon's
115+ // inhabitants will be clipped away.
116+
117+ // LP: get liquid data here for convenience;
118+ // pointer to it being NULL means no liquid in the polygon
119+ media_data *media = NULL;
120+ if (polygon->media_index!=NONE)
121+ media = get_media_data(polygon->media_index);
122+
123+ /* if necessary, replace the ceiling or floor surfaces with the media surface */
124+ // LP change: don't do this step if liquids are semitransparent
125+ if (media && !SeeThruLiquids)
126+ {
127+ // LP change: moved this get upwards
128+ // struct media_data *media= get_media_data(polygon->media_index);
129+ horizontal_surface_data *media_surface= NULL;
130+
131+ if (view->under_media_boundary)
132+ {
133+ // LP change: skip if high and dry
134+ if (media->height <= polygon->floor_height)
135+ return;
136+
137+ if (media->height<polygon->ceiling_height) media_surface= &ceiling_surface;
138+ }
139+ else
140+ {
141+ // LP change: skip if submerged
142+ if (media->height >= polygon->ceiling_height)
143+ return;
144+
145+ if (media->height>polygon->floor_height) media_surface= &floor_surface;
146+ }
147+
148+ if (media_surface)
149+ {
150+ media_surface->origin= media->origin;
151+ media_surface->height= media->height;
152+ media_surface->texture= media->texture;
153+ media_surface->lightsource_index= polygon->media_lightsource_index;
154+ media_surface->transfer_mode= media->transfer_mode;
155+ media_surface->transfer_mode_data= 0;
156+ }
157+ }
158+ // LP change: always render liquids that are semitransparent
159+ else if (!SeeThruLiquids)
160+ {
161+ // if weユre trying to draw a polygon without media from under a polygon with media, donユt
162+ if (view->under_media_boundary) return;
163+ }
164+
165+ // LP: this loop renders the walls
166+ for (window= node->clipping_windows; window; window= window->next_window)
167+ {
168+ if (ceiling_surface.height>floor_surface.height)
169+ {
170+ /* render ceiling if above viewer */
171+ if (ceiling_surface.height>view->origin.z)
172+ {
173+ // LP change: indicated that the void is on other side
174+ render_node_floor_or_ceiling(window, polygon, &ceiling_surface, true, true, renderStep);
175+ }
176+
177+ /* render visible sides */
178+ for (i= 0; i<polygon->vertex_count; ++i)
179+ {
180+ short side_index= polygon->side_indexes[i];
181+
182+ if (side_index!=NONE && TEST_RENDER_FLAG(side_index, _side_is_visible))
183+ {
184+ line_data *line= get_line_data(polygon->line_indexes[i]);
185+ side_data *side= get_side_data(side_index);
186+ vertical_surface_data surface;
187+
188+ surface.length= line->length;
189+ store_endpoint(get_endpoint_data(polygon->endpoint_indexes[i]), surface.p0);
190+ store_endpoint(get_endpoint_data(polygon->endpoint_indexes[WRAP_HIGH(i, polygon->vertex_count-1)]), surface.p1);
191+ surface.ambient_delta= side->ambient_delta;
192+
193+ // LP change: indicate in all cases whether the void is on the other side;
194+ // added a workaround for full-side textures with a polygon on the other side
195+ bool void_present;
196+
197+ switch (side->type)
198+ {
199+ case _full_side:
200+ void_present = true;
201+ // Suppress the void if there is a polygon on the other side.
202+ if (polygon->adjacent_polygon_indexes[i] != NONE) void_present = false;
203+
204+ surface.lightsource_index= side->primary_lightsource_index;
205+ surface.h0= floor_surface.height - view->origin.z;
206+ surface.hmax= ceiling_surface.height - view->origin.z;
207+ surface.h1= polygon->ceiling_height - view->origin.z;
208+ surface.texture_definition= &side->primary_texture;
209+ surface.transfer_mode= side->primary_transfer_mode;
210+ render_node_side(window, &surface, void_present, renderStep);
211+ break;
212+ case _split_side: /* render _low_side first */
213+ surface.lightsource_index= side->secondary_lightsource_index;
214+ surface.h0= floor_surface.height - view->origin.z;
215+ surface.h1= MAX(line->highest_adjacent_floor, floor_surface.height) - view->origin.z;
216+ surface.hmax= ceiling_surface.height - view->origin.z;
217+ surface.texture_definition= &side->secondary_texture;
218+ surface.transfer_mode= side->secondary_transfer_mode;
219+ render_node_side(window, &surface, true, renderStep);
220+ /* fall through and render high side */
221+ case _high_side:
222+ surface.lightsource_index= side->primary_lightsource_index;
223+ surface.h0= MIN(line->lowest_adjacent_ceiling, ceiling_surface.height) - view->origin.z;
224+ surface.hmax= ceiling_surface.height - view->origin.z;
225+ surface.h1= polygon->ceiling_height - view->origin.z;
226+ surface.texture_definition= &side->primary_texture;
227+ surface.transfer_mode= side->primary_transfer_mode;
228+ render_node_side(window, &surface, true, renderStep);
229+ // render_node_side(view, destination, window, &surface);
230+ break;
231+ case _low_side:
232+ surface.lightsource_index= side->primary_lightsource_index;
233+ surface.h0= floor_surface.height - view->origin.z;
234+ surface.h1= MAX(line->highest_adjacent_floor, floor_surface.height) - view->origin.z;
235+ surface.hmax= ceiling_surface.height - view->origin.z;
236+ surface.texture_definition= &side->primary_texture;
237+ surface.transfer_mode= side->primary_transfer_mode;
238+ render_node_side(window, &surface, true, renderStep);
239+ // render_node_side(view, destination, window, &surface);
240+ break;
241+
242+ default:
243+ assert(false);
244+ break;
245+ }
246+
247+ if (side->transparent_texture.texture!=UNONE)
248+ {
249+ surface.lightsource_index= side->transparent_lightsource_index;
250+ surface.h0= MAX(line->highest_adjacent_floor, floor_surface.height) - view->origin.z;
251+ surface.h1= line->lowest_adjacent_ceiling - view->origin.z;
252+ surface.hmax= ceiling_surface.height - view->origin.z;
253+ surface.texture_definition= &side->transparent_texture;
254+ surface.transfer_mode= side->transparent_transfer_mode;
255+ render_node_side(window, &surface, false, renderStep);
256+ }
257+ }
258+ }
259+
260+ /* render floor if below viewer */
261+ if (floor_surface.height<view->origin.z)
262+ {
263+ // LP change: indicated that the void is on other side
264+ render_node_floor_or_ceiling(window, polygon, &floor_surface, true, false, renderStep);
265+ }
266+ }
267+ }
268+
269+ // LP: this is for objects on the other side of the liquids;
270+ // render them out here if one can see through the liquids
271+ if (SeeThruLiquids)
272+ {
273+ /* render exterior objects (with their own clipping windows) */
274+ for (object= node->exterior_objects; object; object= object->next_object)
275+ {
276+ render_node_object(object, true, renderStep);
277+ }
278+ }
279+
280+ // LP: render the liquid surface after the walls and the stuff behind it
281+ // and before the stuff before it.
282+ if (media && SeeThruLiquids)
283+ {
284+
285+ // Render only if between the floor and the ceiling:
286+ if (media->height > polygon->floor_height && media->height < polygon->ceiling_height)
287+ {
288+
289+ // Render the liquids
290+ bool ceil = (media->height > view->origin.z);
291+ horizontal_surface_data LiquidSurface;
292+
293+ LiquidSurface.origin= media->origin;
294+ LiquidSurface.height= media->height;
295+ LiquidSurface.texture= media->texture;
296+ LiquidSurface.lightsource_index= polygon->media_lightsource_index;
297+ LiquidSurface.transfer_mode= media->transfer_mode;
298+ LiquidSurface.transfer_mode_data= 0;
299+
300+ for (window= node->clipping_windows; window; window= window->next_window)
301+ {
302+ render_node_floor_or_ceiling(window, polygon, &LiquidSurface, false, ceil, renderStep);
303+ }
304+ }
305+ }
306+
307+ // LP: this is for objects on the view side of the liquids
308+ /* render exterior objects (with their own clipping windows) */
309+ for (object= node->exterior_objects; object; object= object->next_object)
310+ {
311+ render_node_object(object, false, renderStep);
312+ }
313+}
314+
315+void RenderRasterizerClass::store_endpoint(
316+ endpoint_data *endpoint,
317+ long_vector2d& p)
318+{
319+ overflow_short_to_long_2d(endpoint->transformed, endpoint->flags, p);
320+}
321+
322+
323+/* ---------- rendering ceilings and floors */
324+
325+// LP change: added "void present on other side" flag
326+void RenderRasterizerClass::render_node_floor_or_ceiling(
327+ clipping_window_data *window,
328+ polygon_data *polygon,
329+ horizontal_surface_data *surface,
330+ bool void_present,
331+ bool ceil,
332+ RenderStep renderStep)
333+{
334+ // LP addition: animated-texture support
335+ // Extra variable defined so as not to edit the original texture
336+ shape_descriptor Texture = AnimTxtr_Translate(surface->texture);
337+ if (Texture!=UNONE)
338+ {
339+ struct polygon_definition textured_polygon;
340+ flagged_world_point2d vertices[MAXIMUM_VERTICES_PER_WORLD_POLYGON];
341+ world_distance adjusted_height= surface->height-view->origin.z;
342+ int32 transformed_height= adjusted_height*view->world_to_screen_y;
343+ short vertex_count;
344+ short i;
345+
346+ /* build transformed vertex list */
347+ vertex_count= polygon->vertex_count;
348+ for (i=0;i<vertex_count;++i)
349+ {
350+ // LP change: expanded the transformed-endpoint access
351+ long_vector2d temp_vertex;
352+ endpoint_data *endpoint = get_endpoint_data(polygon->endpoint_indexes[i]);
353+ overflow_short_to_long_2d(endpoint->transformed,endpoint->flags,temp_vertex);
354+ vertices[i].x = temp_vertex.i;
355+ vertices[i].y = temp_vertex.j;
356+ vertices[i].flags= 0;
357+ }
358+
359+ /* reversing the order in which these two were clipped caused weird problems */
360+
361+ /* clip to left and right sides of the window */
362+ vertex_count= xy_clip_horizontal_polygon(vertices, vertex_count, &window->left, _clip_left);
363+ vertex_count= xy_clip_horizontal_polygon(vertices, vertex_count, &window->right, _clip_right);
364+
365+ /* clip to top and bottom sides of the window */
366+ vertex_count= z_clip_horizontal_polygon(vertices, vertex_count, &window->top, adjusted_height, _clip_up);
367+ vertex_count= z_clip_horizontal_polygon(vertices, vertex_count, &window->bottom, adjusted_height, _clip_down);
368+
369+ if (vertex_count)
370+ {
371+ /* transform the points we have into screen-space (backwards for ceiling polygons) */
372+ for (i=0;i<vertex_count;++i)
373+ {
374+ flagged_world_point2d *world= vertices + (adjusted_height>0 ? vertex_count-i-1 : i);
375+ point2d *screen= textured_polygon.vertices + i;
376+
377+ switch (world->flags&(_clip_left|_clip_right))
378+ {
379+ case 0:
380+ // LP change: making it long-distance friendly
381+ {
382+ int32 world_x = world->x ? world->x : 1; // fix for division by zero error
383+ int32 screen_x= view->half_screen_width + (world->y*view->world_to_screen_x)/world_x;
384+ screen->x= PIN(screen_x, 0, view->screen_width);
385+ }
386+ break;
387+ case _clip_left: screen->x= window->x0; break;
388+ case _clip_right: screen->x= window->x1; break;
389+ default:
390+ screen->x= window->x0;
391+ break;
392+ }
393+
394+ switch (world->flags&(_clip_up|_clip_down))
395+ {
396+ case 0:
397+ // LP change: making it long-distance friendly
398+ {
399+ int32 world_x = world->x ? world->x : 1; // fix for division by zero error
400+ int32 screen_y= view->half_screen_height - transformed_height/world_x + view->dtanpitch;
401+ screen->y= PIN(screen_y, 0, view->screen_height);
402+ }
403+ break;
404+ case _clip_up: screen->y= window->y0; break;
405+ case _clip_down: screen->y= window->y1; break;
406+ default:
407+ screen->y= window->y0;
408+ break;
409+ }
410+ // vassert(screen->y>=0&&screen->y<=view->screen_height, csprintf(temporary, "horizontal: flags==%x, window @ %p", world->flags, window));
411+ }
412+
413+ /* setup the other parameters of the textured polygon */
414+ textured_polygon.flags= 0;
415+ textured_polygon.origin.x= view->origin.x + surface->origin.x;
416+ textured_polygon.origin.y= view->origin.y + surface->origin.y;
417+ textured_polygon.origin.z= adjusted_height;
418+ get_shape_bitmap_and_shading_table(Texture, &textured_polygon.texture, &textured_polygon.shading_tables, view->shading_mode);
419+ // Bug out if bitmap is nonexistent
420+ if (!textured_polygon.texture) return;
421+
422+ textured_polygon.ShapeDesc = Texture;
423+ textured_polygon.ambient_shade= get_light_intensity(surface->lightsource_index);
424+ textured_polygon.vertex_count= vertex_count;
425+ instantiate_polygon_transfer_mode(view, &textured_polygon, surface->transfer_mode, true);
426+ if (view->shading_mode==_shading_infravision) textured_polygon.flags|= _SHADELESS_BIT;
427+
428+ /* and, finally, map it */
429+ // LP: added OpenGL support; also presence of void on other side
430+ textured_polygon.VoidPresent = void_present;
431+ // LP: using rasterizer object
432+ RasPtr->texture_horizontal_polygon(textured_polygon);
433+ }
434+ }
435+}
436+
437+/* ---------- rendering sides (walls) */
438+
439+// LP change: added "void present on other side" flag
440+void RenderRasterizerClass::render_node_side(
441+ clipping_window_data *window,
442+ vertical_surface_data *surface,
443+ bool void_present,
444+ RenderStep renderStep)
445+{
446+ world_distance h= MIN(surface->h1, surface->hmax);
447+
448+ // LP addition: animated-texture support
449+ // Extra variable defined so as not to edit the original texture
450+ shape_descriptor Texture = AnimTxtr_Translate(surface->texture_definition->texture);
451+ if (h>surface->h0 && Texture!=UNONE)
452+ {
453+ struct polygon_definition textured_polygon;
454+ flagged_world_point2d posts[2];
455+ flagged_world_point3d vertices[MAXIMUM_VERTICES_PER_WORLD_POLYGON];
456+ short vertex_count;
457+ short i;
458+
459+ /* initialize the two posts of our trapezoid */
460+ vertex_count= 2;
461+ posts[0].x= surface->p0.i; posts[0].y= surface->p0.j; posts[0].flags= 0;
462+ posts[1].x= surface->p1.i; posts[1].y= surface->p1.j; posts[1].flags= 0;
463+
464+ /* clip to left and right sides of the cone (must happen in the same order as horizontal polygons) */
465+ vertex_count= xy_clip_line(posts, vertex_count, &window->left, _clip_left);
466+ vertex_count= xy_clip_line(posts, vertex_count, &window->right, _clip_right);
467+
468+ if (vertex_count)
469+ {
470+ /* build a polygon out of the two posts */
471+ vertex_count= 4;
472+ vertices[0].z= vertices[1].z= h;
473+ vertices[2].z= vertices[3].z= surface->h0;
474+ vertices[0].x= vertices[3].x= posts[0].x, vertices[0].y= vertices[3].y= posts[0].y;
475+ vertices[1].x= vertices[2].x= posts[1].x, vertices[1].y= vertices[2].y= posts[1].y;
476+ vertices[0].flags= vertices[3].flags= posts[0].flags;
477+ vertices[1].flags= vertices[2].flags= posts[1].flags;
478+
479+ /* clip to top and bottom sides of the window; because xz_clip_vertical_polygon accepts
480+ vertices in clockwise or counterclockwise order, we can set our vertex list up to be
481+ clockwise on the screen and never worry about it after that */
482+ vertex_count= xz_clip_vertical_polygon(vertices, vertex_count, &window->top, _clip_up);
483+ vertex_count= xz_clip_vertical_polygon(vertices, vertex_count, &window->bottom, _clip_down);
484+
485+ if (vertex_count)
486+ {
487+ world_distance dx= surface->p1.i - surface->p0.i;
488+ world_distance dy= surface->p1.j - surface->p0.j;
489+ world_distance x0= WORLD_FRACTIONAL_PART(surface->texture_definition->x0);
490+ world_distance y0= WORLD_FRACTIONAL_PART(surface->texture_definition->y0);
491+
492+ /* calculate texture origin and direction */
493+ world_distance divisor = surface->length;
494+ if (divisor == 0)
495+ divisor = 1;
496+ textured_polygon.vector.i= (WORLD_ONE*dx)/divisor;
497+ textured_polygon.vector.j= (WORLD_ONE*dy)/divisor;
498+ textured_polygon.vector.k= -WORLD_ONE;
499+ textured_polygon.origin.x= surface->p0.i - (x0*dx)/divisor;
500+ textured_polygon.origin.y= surface->p0.j - (x0*dy)/divisor;
501+ textured_polygon.origin.z= surface->h1 + y0;
502+
503+ /* transform the points we have into screen-space */
504+ for (i=0;i<vertex_count;++i)
505+ {
506+ flagged_world_point3d *world= vertices + i;
507+ point2d *screen= textured_polygon.vertices + i;
508+
509+ switch (world->flags&(_clip_left|_clip_right))
510+ {
511+ case 0:
512+ // LP change: making it long-distance friendly
513+ {
514+ int32 screen_x= view->half_screen_width + (world->x ? (world->y*view->world_to_screen_x)/world->x : 0);
515+ screen->x= PIN(screen_x, 0, view->screen_width);
516+ }
517+ break;
518+ case _clip_left: screen->x= window->x0; break;
519+ case _clip_right: screen->x= window->x1; break;
520+ default:
521+ screen->x= window->x0;
522+ break;
523+ }
524+
525+ switch (world->flags&(_clip_up|_clip_down))
526+ {
527+ case 0:
528+ // LP change: making it long-distance friendly
529+ {
530+ int32 screen_y= view->half_screen_height - (world->x ? (world->z*view->world_to_screen_y)/world->x : 0) + view->dtanpitch;
531+ screen->y= PIN(screen_y, 0, view->screen_height);
532+ }
533+ break;
534+ case _clip_up: screen->y= window->y0; break;
535+ case _clip_down: screen->y= window->y1; break;
536+ default:
537+ screen->y= window->y0;
538+ break;
539+ }
540+ // vassert(screen->y>=0&&screen->y<=view->screen_height, csprintf(temporary, "#%d!in[#0,#%d]: flags==%x, wind@%p #%d w@%p s@%p", screen->y, view->screen_height, world->flags, window, vertex_count, world, screen));
541+ }
542+
543+ /* setup the other parameters of the textured polygon */
544+ textured_polygon.flags= 0;
545+ get_shape_bitmap_and_shading_table(Texture, &textured_polygon.texture, &textured_polygon.shading_tables, view->shading_mode);
546+ // Bug out if bitmap is nonexistent
547+ if (!textured_polygon.texture) return;
548+
549+ textured_polygon.ShapeDesc = Texture;
550+ textured_polygon.ambient_shade= get_light_intensity(surface->lightsource_index) + surface->ambient_delta;
551+ textured_polygon.ambient_shade= PIN(textured_polygon.ambient_shade, 0, FIXED_ONE);
552+ textured_polygon.vertex_count= vertex_count;
553+ instantiate_polygon_transfer_mode(view, &textured_polygon, surface->transfer_mode, false);
554+ if (view->shading_mode==_shading_infravision) textured_polygon.flags|= _SHADELESS_BIT;
555+
556+ /* and, finally, map it */
557+ // LP: added OpenGL support; also presence of void on other side
558+ textured_polygon.VoidPresent = void_present;
559+ // LP: using rasterizer object
560+ RasPtr->texture_vertical_polygon(textured_polygon);
561+ }
562+ }
563+ }
564+}
565+
566+/* ---------- rendering objects */
567+
568+void RenderRasterizerClass::render_node_object(
569+ render_object_data *object,
570+ bool other_side_of_media,
571+ RenderStep renderStep)
572+{
573+ struct clipping_window_data *window;
574+
575+ for (window= object->clipping_windows; window; window= window->next_window)
576+ {
577+ object->rectangle.clip_left= window->x0;
578+ object->rectangle.clip_right= window->x1;
579+ object->rectangle.clip_top= window->y0;
580+ object->rectangle.clip_bottom= window->y1;
581+
582+ // Models will have their own liquid-surface clipping,
583+ // so don't edit their clip rects
584+ // This is bitwise XOR, but is presumably OK here
585+ if (view->under_media_boundary ^ other_side_of_media)
586+ {
587+ // Clipping: below a liquid surface
588+ if (object->rectangle.ModelPtr)
589+ object->rectangle.BelowLiquid = true;
590+ else
591+ object->rectangle.clip_top= MAX(object->rectangle.clip_top, object->ymedia);
592+ }
593+ else
594+ {
595+ // Clipping: above a liquid surface
596+ if (object->rectangle.ModelPtr)
597+ object->rectangle.BelowLiquid = false;
598+ else
599+ object->rectangle.clip_bottom= MIN(object->rectangle.clip_bottom, object->ymedia);
600+ }
601+
602+ // LP: added OpenGL support
603+ // LP: using rasterizer object
604+ RasPtr->texture_rectangle(object->rectangle);
605+ }
606+}
607+
608+
609+/* ---------- horizontal polygon clipping */
610+
611+enum /* xy_clip_horizontal_polygon() states */
612+{
613+ _testing_first_vertex, /* are we in or out? */
614+ _searching_cw_for_in_out_transition,
615+ _searching_ccw_for_out_in_transition,
616+ _searching_cw_for_out_in_transition
617+};
618+
619+// LP change: make it better able to do long-distance views
620+short RenderRasterizerClass::xy_clip_horizontal_polygon(
621+ flagged_world_point2d *vertices,
622+ short vertex_count,
623+ long_vector2d *line,
624+ uint16 flag)
625+{
626+#ifdef QUICKDRAW_DEBUG
627+ debug_flagged_points(vertices, vertex_count);
628+ debug_vector(line);
629+#endif
630+// dprintf("clipping %p (#%d vertices) to vector %x,%x (slope==%x)", vertices, vertex_count, line->i, line->j, slope);
631+
632+ if (vertex_count)
633+ {
634+ short state= _testing_first_vertex;
635+ short vertex_index= 0, vertex_delta= 1, first_vertex= 0;
636+ short entrance_vertex= NONE, exit_vertex= NONE; /* exiting the clipped area and entering the clipped area */
637+ bool clipped_exit_vertex= true, clipped_entrance_vertex= true; /* will be false if these points lie directly on a vertex */
638+
639+ do
640+ {
641+ // LP change:
642+ CROSSPROD_TYPE cross_product= CROSSPROD_TYPE(line->i)*vertices[vertex_index].y - CROSSPROD_TYPE(line->j)*vertices[vertex_index].x;
643+ // int32 cross_product= line->i*vertices[vertex_index].y - line->j*vertices[vertex_index].x;
644+
645+ switch (SGN(cross_product))
646+ {
647+ case -1: /* inside (i.e., will be clipped) */
648+// dprintf("vertex#%d is inside s==#%d", vertex_index, state);
649+ switch (state)
650+ {
651+ case _testing_first_vertex:
652+ first_vertex= vertex_index;
653+ state= _searching_cw_for_in_out_transition; /* the exit point from the clip area */
654+ break;
655+
656+ case _searching_ccw_for_out_in_transition: /* found exit point from clip area */
657+ state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
658+ vertex_delta= 1;
659+ if (exit_vertex==NONE) exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
660+ vertex_index= first_vertex; /* skip vertices we already know are out */
661+ break;
662+
663+ case _searching_cw_for_out_in_transition: /* found entrance point to clipped area */
664+ if (entrance_vertex==NONE) entrance_vertex= vertex_index;
665+ state= NONE;
666+ break;
667+ }
668+ break;
669+
670+ case 0: /* clip line passed directly through a vertex */
671+// dprintf("vertex#%d is on the clip line s==#%d", vertex_index, state);
672+ switch (state)
673+ {
674+ /* if weユre testing the first vertex, this tells us nothing */
675+
676+ case _searching_cw_for_out_in_transition:
677+ entrance_vertex= vertex_index;
678+ clipped_entrance_vertex= false; /* remember if this passes through vertex */
679+ break;
680+
681+ case _searching_cw_for_in_out_transition:
682+ exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
683+ clipped_exit_vertex= false;
684+ break;
685+ case _searching_ccw_for_out_in_transition:
686+ exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
687+ clipped_exit_vertex= false; /* remember if this passes through vertex */
688+ break;
689+ }
690+ break;
691+
692+ case 1: /* outside (i.e., will not be clipped) */
693+// dprintf("vertex#%d is outside s==#%d", vertex_index, state);
694+ switch (state)
695+ {
696+ case _testing_first_vertex:
697+ first_vertex= vertex_index;
698+ state= _searching_ccw_for_out_in_transition; /* the exit point from the clipped area */
699+ vertex_delta= -1;
700+ break;
701+
702+ case _searching_cw_for_in_out_transition: /* found exit point from clipped area */
703+ state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
704+ if (exit_vertex==NONE) exit_vertex= vertex_index;
705+ break;
706+ }
707+ break;
708+ }
709+
710+ /* adjust vertex_index (clockwise or counterclockwise, depending on vertex_delta)
711+ if weユve come back to the first vertex without finding an entrance point weユre
712+ either all the way in or all the way out */
713+ vertex_index= (vertex_delta<0) ? WRAP_LOW(vertex_index, vertex_count-1) :
714+ WRAP_HIGH(vertex_index, vertex_count-1);
715+ if (vertex_index==first_vertex) /* we came full-circle without hitting anything */
716+ {
717+ switch (state)
718+ {
719+ case _searching_cw_for_in_out_transition: /* never found a way out: clipped into nothing */
720+ vertex_count= 0;
721+ case _testing_first_vertex: /* is this the right thing to do? */
722+ case _searching_ccw_for_out_in_transition: /* never found a way in: no clipping */
723+ exit_vertex= NONE;
724+ state= NONE;
725+ break;
726+ }
727+ }
728+ }
729+ while (state!=NONE);
730+
731+ if (exit_vertex!=NONE) /* weユve got clipping to do */
732+ {
733+ flagged_world_point2d new_entrance_point, new_exit_point;
734+
735+// dprintf("entrance_vertex==#%d (%s), exit_vertex==#%d (%s)", entrance_vertex, clipped_entrance_vertex ? "clipped" : "unclipped", exit_vertex, clipped_exit_vertex ? "clipped" : "unclipped");
736+
737+ /* clip the entrance to the clipped area */
738+ if (clipped_entrance_vertex)
739+ {
740+ xy_clip_flagged_world_points(vertices + WRAP_LOW(entrance_vertex, vertex_count-1), vertices + entrance_vertex,
741+ &new_entrance_point, line);
742+ }
743+ else
744+ {
745+ new_entrance_point= vertices[entrance_vertex];
746+ }
747+ new_entrance_point.flags|= flag;
748+
749+ /* clip the exit from the clipped area */
750+ if (clipped_exit_vertex)
751+ {
752+ xy_clip_flagged_world_points(vertices + WRAP_LOW(exit_vertex, vertex_count-1), vertices + exit_vertex,
753+ &new_exit_point, line);
754+ }
755+ else
756+ {
757+ new_exit_point= vertices[WRAP_LOW(exit_vertex, vertex_count-1)];
758+ }
759+ new_exit_point.flags|= flag;
760+
761+ /* adjust for the change in number of vertices */
762+ vertex_delta= entrance_vertex - exit_vertex;
763+ if (vertex_delta<0)
764+ {
765+ if (vertex_delta!=-2) memmove(vertices+entrance_vertex+2, vertices+exit_vertex, (vertex_count-exit_vertex)*sizeof(flagged_world_point2d));
766+ vertex_delta= vertex_count+vertex_delta;
767+ }
768+ else
769+ {
770+ /* move down by exit_vertex, add new vertices to end */
771+ assert(vertex_delta);
772+ if (exit_vertex)
773+ {
774+ memmove(vertices, vertices+exit_vertex, vertex_delta*sizeof(flagged_world_point2d));
775+ entrance_vertex-= exit_vertex;
776+ }
777+ }
778+
779+ vertex_count= vertex_delta+2;
780+ vwarn(vertex_count>=3 && vertex_count<=MAXIMUM_VERTICES_PER_WORLD_POLYGON,
781+ csprintf(temporary, "vertex overflow or underflow (#%d);g;", vertex_count));
782+
783+ if (vertex_count<3 || vertex_count>MAXIMUM_VERTICES_PER_WORLD_POLYGON)
784+ {
785+ vertex_count= 0;
786+ }
787+ else
788+ {
789+ /* and, finally, add the new vertices */
790+ vertices[entrance_vertex]= new_entrance_point;
791+ vertices[entrance_vertex+1]= new_exit_point;
792+ }
793+ }
794+ }
795+
796+#ifdef QUICKDRAW_DEBUG
797+ debug_flagged_points(vertices, vertex_count);
798+ debug_vector(line);
799+#endif
800+// dprintf("result == %p (#%d vertices)", vertices, vertex_count);
801+
802+ return vertex_count;
803+}
804+
805+/* sort points before clipping to assure consistency; there is a way to make this more accurate
806+ but it requires the downshifting game, as played in SCOTTISH_TEXTURES.C. itユs tempting to
807+ think that having a smaller scale for our world coordinates would help here (i.e., less bits
808+ per distance) but then wouldnユt we be screwed when we tried to rotate? */
809+// LP change: make it better able to do long-distance views
810+void RenderRasterizerClass::xy_clip_flagged_world_points(
811+ flagged_world_point2d *p0,
812+ flagged_world_point2d *p1,
813+ flagged_world_point2d *clipped,
814+ long_vector2d *line)
815+{
816+ bool swap= (p1->y>p0->y) ? false : ((p0->y==p1->y) ? (p1->x<p0->x) : true);
817+ flagged_world_point2d *local_p0= swap ? p1 : p0;
818+ flagged_world_point2d *local_p1= swap ? p0 : p1;
819+ world_distance dx= local_p1->x - local_p0->x;
820+ world_distance dy= local_p1->y - local_p0->y;
821+ int32 numerator= line->j*local_p0->x - line->i*local_p0->y;
822+ int32 denominator= line->i*dy - line->j*dx;
823+ short shift_count= FIXED_FRACTIONAL_BITS;
824+ _fixed t;
825+
826+ /* give numerator 16 significant bits over denominator and then calculate t==n/d; MPWユs PPCC
827+ didnユt seem to like (INT32_MIN>>1) and i had to substitute 0xc0000000 instead (hmmm) */
828+ while (numerator<=(int32)0x3fffffff && numerator>=(int32)0xc0000000 && shift_count--) numerator<<= 1;
829+ if (shift_count>0) denominator>>= shift_count;
830+ t= numerator;
831+ if (denominator)
832+ t /= denominator;
833+
834+ /* calculate the clipped point */
835+ clipped->x= local_p0->x + FIXED_INTEGERAL_PART(t*dx);
836+ clipped->y= local_p0->y + FIXED_INTEGERAL_PART(t*dy);
837+ clipped->flags= local_p0->flags&local_p1->flags;
838+}
839+
840+/* almost wholly identical to xz_clip_vertical_polygon() except that this works off 2d points
841+ in the xy-plane and a height */
842+// LP change: make it better able to do long-distance views
843+short RenderRasterizerClass::z_clip_horizontal_polygon(
844+ flagged_world_point2d *vertices,
845+ short vertex_count,
846+ long_vector2d *line, /* i==x, j==z */
847+ world_distance height,
848+ uint16 flag)
849+{
850+ CROSSPROD_TYPE heighti= CROSSPROD_TYPE(line->i)*height;
851+
852+#ifdef QUICKDRAW_DEBUG
853+ debug_flagged_points(vertices, vertex_count);
854+ debug_x_line(line->j ? (line->i*height)/line->j : (height<0 ? INT32_MIN : INT32_MAX));
855+#endif
856+// dprintf("clipping %p (#%d vertices) to vector %x,%x", vertices, vertex_count, line->i, line->j);
857+
858+ if (vertex_count)
859+ {
860+ short state= _testing_first_vertex;
861+ short vertex_index= 0, vertex_delta= 1, first_vertex= 0;
862+ short entrance_vertex= NONE, exit_vertex= NONE; /* exiting the clipped area and entering the clipped area */
863+ bool clipped_exit_vertex= true, clipped_entrance_vertex= true; /* will be false if these points lie directly on a vertex */
864+
865+ do
866+ {
867+ CROSSPROD_TYPE cross_product= heighti - CROSSPROD_TYPE(line->j)*vertices[vertex_index].x;
868+
869+ if (cross_product<0) /* inside (i.e., will be clipped) */
870+ {
871+ switch (state)
872+ {
873+ case _testing_first_vertex:
874+ first_vertex= vertex_index;
875+ state= _searching_cw_for_in_out_transition; /* the exit point from the clip area */
876+ break;
877+
878+ case _searching_ccw_for_out_in_transition: /* found exit point from clip area */
879+ state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
880+ vertex_delta= 1;
881+ if (exit_vertex==NONE) exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
882+ vertex_index= first_vertex; /* skip vertices we already know are out */
883+ break;
884+
885+ case _searching_cw_for_out_in_transition: /* found entrance point to clipped area */
886+ if (entrance_vertex==NONE) entrance_vertex= vertex_index;
887+ state= NONE;
888+ break;
889+ }
890+ }
891+ else
892+ {
893+ if (cross_product>0) /* outside (i.e., will not be clipped) */
894+ {
895+ switch (state)
896+ {
897+ case _testing_first_vertex:
898+ first_vertex= vertex_index;
899+ state= _searching_ccw_for_out_in_transition; /* the exit point from the clipped area */
900+ vertex_delta= -1;
901+ break;
902+
903+ case _searching_cw_for_in_out_transition: /* found exit point from clipped area */
904+ state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
905+ if (exit_vertex==NONE) exit_vertex= vertex_index;
906+ break;
907+ }
908+ }
909+ else /* clip line passed directly through a vertex */
910+ {
911+ switch (state)
912+ {
913+ /* if weユre testing the first vertex (_testing_first_vertex), this tells us nothing */
914+
915+ case _searching_cw_for_out_in_transition:
916+ entrance_vertex= vertex_index;
917+ clipped_entrance_vertex= false; /* remember if this passes through vertex */
918+ break;
919+
920+ case _searching_cw_for_in_out_transition:
921+ exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
922+ clipped_exit_vertex= false;
923+ break;
924+ case _searching_ccw_for_out_in_transition:
925+ exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
926+ clipped_exit_vertex= false; /* remember if this passes through vertex */
927+ break;
928+ }
929+ }
930+ }
931+
932+ /* adjust vertex_index (clockwise or counterclockwise, depending on vertex_delta)
933+ if weユve come back to the first vertex without finding an entrance point weユre
934+ either all the way in or all the way out */
935+ vertex_index= (vertex_delta<0) ? WRAP_LOW(vertex_index, vertex_count-1) :
936+ WRAP_HIGH(vertex_index, vertex_count-1);
937+ if (vertex_index==first_vertex) /* we came full-circle without hitting anything */
938+ {
939+ switch (state)
940+ {
941+ case _searching_cw_for_in_out_transition: /* never found a way out: clipped into nothing */
942+ vertex_count= 0;
943+ case _testing_first_vertex: /* is this the right thing to do? */
944+ case _searching_ccw_for_out_in_transition: /* never found a way in: no clipping */
945+ exit_vertex= NONE;
946+ state= NONE;
947+ break;
948+ }
949+ }
950+ }
951+ while (state!=NONE);
952+
953+ if (exit_vertex!=NONE) /* weユve got clipping to do */
954+ {
955+ flagged_world_point2d new_entrance_point, new_exit_point;
956+
957+// dprintf("entrance_vertex==#%d (%s), exit_vertex==#%d (%s)", entrance_vertex, clipped_entrance_vertex ? "clipped" : "unclipped", exit_vertex, clipped_exit_vertex ? "clipped" : "unclipped");
958+
959+ /* clip the entrance to the clipped area */
960+ if (clipped_entrance_vertex)
961+ {
962+ z_clip_flagged_world_points(vertices + WRAP_LOW(entrance_vertex, vertex_count-1), vertices + entrance_vertex,
963+ height, &new_entrance_point, line);
964+ }
965+ else
966+ {
967+ new_entrance_point= vertices[entrance_vertex];
968+ }
969+ new_entrance_point.flags|= flag;
970+
971+ /* clip the exit from the clipped area */
972+ if (clipped_exit_vertex)
973+ {
974+ z_clip_flagged_world_points(vertices + WRAP_LOW(exit_vertex, vertex_count-1), vertices + exit_vertex,
975+ height, &new_exit_point, line);
976+ }
977+ else
978+ {
979+ new_exit_point= vertices[WRAP_LOW(exit_vertex, vertex_count-1)];
980+ }
981+ new_exit_point.flags|= flag;
982+
983+ /* adjust for the change in number of vertices */
984+ vertex_delta= entrance_vertex - exit_vertex;
985+ if (vertex_delta<0)
986+ {
987+ if (vertex_delta!=-2) memmove(vertices+entrance_vertex+2, vertices+exit_vertex, (vertex_count-exit_vertex)*sizeof(flagged_world_point2d));
988+ vertex_delta= vertex_count+vertex_delta;
989+ }
990+ else
991+ {
992+ /* move down by exit_vertex, add new vertices to end */
993+ assert(vertex_delta);
994+ if (exit_vertex)
995+ {
996+ memmove(vertices, vertices+exit_vertex, vertex_delta*sizeof(flagged_world_point2d));
997+ entrance_vertex-= exit_vertex;
998+ }
999+ }
1000+ vertex_count= vertex_delta+2;
1001+
1002+ vwarn(vertex_count>=3 && vertex_count<=MAXIMUM_VERTICES_PER_WORLD_POLYGON,
1003+ csprintf(temporary, "vertex overflow or underflow (#%d);g;", vertex_count));
1004+
1005+ if (vertex_count<3 || vertex_count>MAXIMUM_VERTICES_PER_WORLD_POLYGON)
1006+ {
1007+ vertex_count= 0;
1008+ }
1009+ else
1010+ {
1011+ /* and, finally, add the new vertices */
1012+ vertices[entrance_vertex]= new_entrance_point;
1013+ vertices[entrance_vertex+1]= new_exit_point;
1014+ }
1015+ }
1016+ }
1017+
1018+#ifdef QUICKDRAW_DEBUG
1019+ debug_flagged_points(vertices, vertex_count);
1020+ debug_x_line(line->j ? (line->i*height)/line->j : (height<0 ? INT32_MIN : INT32_MAX));
1021+#endif
1022+// dprintf("result == %p (#%d vertices)", vertices, vertex_count);
1023+
1024+ return vertex_count;
1025+}
1026+
1027+/* sort points before clipping to assure consistency; this is almost identical to xz_clipノ()
1028+ except that it clips 2d points in the xy-plane at the given height. */
1029+// LP change: make it better able to do long-distance views
1030+void RenderRasterizerClass::z_clip_flagged_world_points(
1031+ flagged_world_point2d *p0,
1032+ flagged_world_point2d *p1,
1033+ world_distance height,
1034+ flagged_world_point2d *clipped,
1035+ long_vector2d *line)
1036+{
1037+ bool swap= (p1->y>p0->y) ? false : ((p0->y==p1->y) ? (p1->x<p0->x) : true);
1038+ flagged_world_point2d *local_p0= swap ? p1 : p0;
1039+ flagged_world_point2d *local_p1= swap ? p0 : p1;
1040+ world_distance dx= local_p1->x - local_p0->x;
1041+ world_distance dy= local_p1->y - local_p0->y;
1042+ int32 numerator= line->j*local_p0->x - line->i*height;
1043+ int32 denominator= - line->j*dx;
1044+ short shift_count= FIXED_FRACTIONAL_BITS;
1045+ _fixed t;
1046+
1047+ /* give numerator 16 significant bits over denominator and then calculate t==n/d; MPWユs PPCC
1048+ didnユt seem to like (INT32_MIN>>1) and i had to substitute 0xc0000000 instead (hmmm) */
1049+ while (numerator<=(int32)0x3fffffff && numerator>=(int32)0xc0000000 && shift_count--) numerator<<= 1;
1050+ if (shift_count>0) denominator>>= shift_count;
1051+ t= numerator;
1052+ if (denominator)
1053+ t /= denominator;
1054+
1055+ /* calculate the clipped point */
1056+ clipped->x= local_p0->x + FIXED_INTEGERAL_PART(t*dx);
1057+ clipped->y= local_p0->y + FIXED_INTEGERAL_PART(t*dy);
1058+ clipped->flags= local_p0->flags&local_p1->flags;
1059+}
1060+
1061+/* ---------- vertical polygon clipping */
1062+
1063+// LP change: make it better able to do long-distance views
1064+short RenderRasterizerClass::xy_clip_line(
1065+ flagged_world_point2d *posts,
1066+ short vertex_count,
1067+ long_vector2d *line,
1068+ uint16 flag)
1069+{
1070+#ifdef QUICKDRAW_DEBUG
1071+// debug_flagged_points(posts, vertex_count);
1072+// debug_vector(line);
1073+#endif
1074+// dprintf("clipping %p (#%d) to line (%d,%d)", posts, vertex_count, line->i, line->j);
1075+
1076+ if (vertex_count)
1077+ {
1078+ CROSSPROD_TYPE cross_product0= CROSSPROD_TYPE(line->i)*posts[0].y - CROSSPROD_TYPE(line->j)*posts[0].x;
1079+ CROSSPROD_TYPE cross_product1= CROSSPROD_TYPE(line->i)*posts[1].y - CROSSPROD_TYPE(line->j)*posts[1].x;
1080+
1081+ if (cross_product0<0)
1082+ {
1083+ if (cross_product1<0) /* clipped out of existence */
1084+ {
1085+ vertex_count= 0;
1086+ }
1087+ else
1088+ {
1089+ xy_clip_flagged_world_points(&posts[0], &posts[1], &posts[0], line);
1090+ posts[0].flags|= flag;
1091+ }
1092+ }
1093+ else
1094+ {
1095+ if (cross_product1<0)
1096+ {
1097+ xy_clip_flagged_world_points(&posts[0], &posts[1], &posts[1], line);
1098+ posts[1].flags|= flag;
1099+ }
1100+ }
1101+ }
1102+
1103+#ifdef QUICKDRAW_DEBUG
1104+// debug_flagged_points(posts, vertex_count);
1105+// debug_vector(line);
1106+#endif
1107+// dprintf("result #%d vertices", vertex_count);
1108+
1109+ return vertex_count;
1110+}
1111+
1112+// LP change: make it better able to do long-distance views
1113+short RenderRasterizerClass::xz_clip_vertical_polygon(
1114+ flagged_world_point3d *vertices,
1115+ short vertex_count,
1116+ long_vector2d *line, /* i==x, j==z */
1117+ uint16 flag)
1118+{
1119+#ifdef QUICKDRAW_DEBUG
1120+// debug_flagged_points3d(vertices, vertex_count);
1121+// debug_vector(line);
1122+#endif
1123+// dprintf("clipping %p (#%d vertices) to vector %x,%x", vertices, vertex_count, line->i, line->j);
1124+
1125+ if (vertex_count)
1126+ {
1127+ short state= _testing_first_vertex;
1128+ short vertex_index= 0, vertex_delta= 1, first_vertex= 0;
1129+ short entrance_vertex= NONE, exit_vertex= NONE; /* exiting the clipped area and entering the clipped area */
1130+ bool clipped_exit_vertex= true, clipped_entrance_vertex= true; /* will be false if these points lie directly on a vertex */
1131+
1132+ do
1133+ {
1134+ CROSSPROD_TYPE cross_product= CROSSPROD_TYPE(line->i)*vertices[vertex_index].z - CROSSPROD_TYPE(line->j)*vertices[vertex_index].x;
1135+
1136+ switch (SGN(cross_product))
1137+ {
1138+ case -1: /* inside (i.e., will be clipped) */
1139+// dprintf("vertex#%d is inside s==#%d", vertex_index, state);
1140+ switch (state)
1141+ {
1142+ case _testing_first_vertex:
1143+ first_vertex= vertex_index;
1144+ state= _searching_cw_for_in_out_transition; /* the exit point from the clip area */
1145+ break;
1146+
1147+ case _searching_ccw_for_out_in_transition: /* found exit point from clip area */
1148+ state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
1149+ vertex_delta= 1;
1150+ if (exit_vertex==NONE) exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
1151+ vertex_index= first_vertex; /* skip vertices we already know are out */
1152+ break;
1153+
1154+ case _searching_cw_for_out_in_transition: /* found entrance point to clipped area */
1155+ if (entrance_vertex==NONE) entrance_vertex= vertex_index;
1156+ state= NONE;
1157+ break;
1158+ }
1159+ break;
1160+
1161+ case 0: /* clip line passed directly through a vertex */
1162+// dprintf("vertex#%d is on the clip line s==#%d", vertex_index, state);
1163+ switch (state)
1164+ {
1165+ /* if weユre testing the first vertex, this tells us nothing */
1166+
1167+ case _searching_cw_for_out_in_transition:
1168+ entrance_vertex= vertex_index;
1169+ clipped_entrance_vertex= false; /* remember if this passes through vertex */
1170+ break;
1171+
1172+ case _searching_cw_for_in_out_transition:
1173+ exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
1174+ clipped_exit_vertex= false;
1175+ break;
1176+ case _searching_ccw_for_out_in_transition:
1177+ exit_vertex= WRAP_HIGH(vertex_index, vertex_count-1);
1178+ clipped_exit_vertex= false; /* remember if this passes through vertex */
1179+ break;
1180+ }
1181+ break;
1182+
1183+ case 1: /* outside (i.e., will not be clipped) */
1184+// dprintf("vertex#%d is outside s==#%d", vertex_index, state);
1185+ switch (state)
1186+ {
1187+ case _testing_first_vertex:
1188+ first_vertex= vertex_index;
1189+ state= _searching_ccw_for_out_in_transition; /* the exit point from the clipped area */
1190+ vertex_delta= -1;
1191+ break;
1192+
1193+ case _searching_cw_for_in_out_transition: /* found exit point from clipped area */
1194+ state= _searching_cw_for_out_in_transition; /* the entrance point to the clipped area */
1195+ if (exit_vertex==NONE) exit_vertex= vertex_index;
1196+ break;
1197+ }
1198+ break;
1199+ }
1200+
1201+ /* adjust vertex_index (clockwise or counterclockwise, depending on vertex_delta)
1202+ if weユve come back to the first vertex without finding an entrance point weユre
1203+ either all the way in or all the way out */
1204+ vertex_index= (vertex_delta<0) ? WRAP_LOW(vertex_index, vertex_count-1) :
1205+ WRAP_HIGH(vertex_index, vertex_count-1);
1206+ if (vertex_index==first_vertex) /* we came full-circle without hitting anything */
1207+ {
1208+ switch (state)
1209+ {
1210+ case _searching_cw_for_in_out_transition: /* never found a way out: clipped into nothing */
1211+ vertex_count= 0;
1212+ case _testing_first_vertex: /* is this the right thing to do? */
1213+ case _searching_ccw_for_out_in_transition: /* never found a way in: no clipping */
1214+ exit_vertex= NONE;
1215+ state= NONE;
1216+ break;
1217+ }
1218+ }
1219+ }
1220+ while (state!=NONE);
1221+
1222+ if (exit_vertex!=NONE) /* weユve got clipping to do */
1223+ {
1224+ flagged_world_point3d new_entrance_point, new_exit_point;
1225+
1226+// dprintf("entrance_vertex==#%d (%s), exit_vertex==#%d (%s)", entrance_vertex, clipped_entrance_vertex ? "clipped" : "unclipped", exit_vertex, clipped_exit_vertex ? "clipped" : "unclipped");
1227+
1228+ /* clip the entrance to the clipped area */
1229+ if (clipped_entrance_vertex)
1230+ {
1231+ xz_clip_flagged_world_points(vertices + WRAP_LOW(entrance_vertex, vertex_count-1), vertices + entrance_vertex,
1232+ &new_entrance_point, line);
1233+ }
1234+ else
1235+ {
1236+ new_entrance_point= vertices[entrance_vertex];
1237+ }
1238+ new_entrance_point.flags|= flag;
1239+
1240+ /* clip the exit from the clipped area */
1241+ if (clipped_exit_vertex)
1242+ {
1243+ xz_clip_flagged_world_points(vertices + WRAP_LOW(exit_vertex, vertex_count-1), vertices + exit_vertex,
1244+ &new_exit_point, line);
1245+ }
1246+ else
1247+ {
1248+ new_exit_point= vertices[WRAP_LOW(exit_vertex, vertex_count-1)];
1249+ }
1250+ new_exit_point.flags|= flag;
1251+
1252+ /* adjust for the change in number of vertices */
1253+ vertex_delta= entrance_vertex - exit_vertex;
1254+ if (vertex_delta<0)
1255+ {
1256+ if (vertex_delta!=-2) memmove(vertices+entrance_vertex+2, vertices+exit_vertex, (vertex_count-exit_vertex)*sizeof(flagged_world_point3d));
1257+ vertex_delta= vertex_count+vertex_delta;
1258+ }
1259+ else
1260+ {
1261+ /* move down by exit_vertex, add new vertices to end */
1262+ assert(vertex_delta);
1263+ if (exit_vertex)
1264+ {
1265+ memmove(vertices, vertices+exit_vertex, vertex_delta*sizeof(flagged_world_point3d));
1266+ entrance_vertex-= exit_vertex;
1267+ }
1268+ }
1269+ vertex_count= vertex_delta+2;
1270+
1271+ vwarn(vertex_count>=3 && vertex_count<=MAXIMUM_VERTICES_PER_WORLD_POLYGON,
1272+ csprintf(temporary, "vertex overflow or underflow (#%d);g;", vertex_count));
1273+
1274+ if (vertex_count<3 || vertex_count>MAXIMUM_VERTICES_PER_WORLD_POLYGON)
1275+ {
1276+ vertex_count= 0;
1277+ }
1278+ else
1279+ {
1280+ /* and, finally, add the new vertices */
1281+ vertices[entrance_vertex]= new_entrance_point;
1282+ vertices[entrance_vertex+1]= new_exit_point;
1283+ }
1284+ }
1285+ }
1286+
1287+#ifdef QUICKDRAW_DEBUG
1288+// debug_flagged_points3d(vertices, vertex_count);
1289+// debug_vector(line);
1290+#endif
1291+// dprintf("result == %p (#%d vertices)", vertices, vertex_count);
1292+
1293+ return vertex_count;
1294+}
1295+
1296+/* sort points before clipping to assure consistency */
1297+// LP change: make it better able to do long-distance views
1298+void RenderRasterizerClass::xz_clip_flagged_world_points(
1299+ flagged_world_point3d *p0,
1300+ flagged_world_point3d *p1,
1301+ flagged_world_point3d *clipped,
1302+ long_vector2d *line)
1303+{
1304+ bool swap= (p1->y>p0->y) ? false : ((p0->y==p1->y) ? (p1->x<p0->x) : true);
1305+ flagged_world_point3d *local_p0= swap ? p1 : p0;
1306+ flagged_world_point3d *local_p1= swap ? p0 : p1;
1307+ world_distance dx= local_p1->x - local_p0->x;
1308+ world_distance dy= local_p1->y - local_p0->y;
1309+ world_distance dz= local_p1->z - local_p0->z;
1310+ int32 numerator= line->j*local_p0->x - line->i*local_p0->z;
1311+ int32 denominator= line->i*dz - line->j*dx;
1312+ short shift_count= FIXED_FRACTIONAL_BITS;
1313+ _fixed t;
1314+
1315+ /* give numerator 16 significant bits over denominator and then calculate t==n/d; MPWユs PPCC
1316+ didnユt seem to like (INT32_MIN>>1) and i had to substitute 0xc0000000 instead (hmmm) */
1317+ while (numerator<=(int32)0x3fffffff && numerator>=(int32)0xc0000000 && shift_count--) numerator<<= 1;
1318+ if (shift_count>0) denominator>>= shift_count;
1319+ t = numerator;
1320+ if (denominator)
1321+ t /= denominator;
1322+
1323+ /* calculate the clipped point */
1324+ clipped->x= local_p0->x + FIXED_INTEGERAL_PART(t*dx);
1325+ clipped->y= local_p0->y + FIXED_INTEGERAL_PART(t*dy);
1326+ clipped->z= local_p0->z + FIXED_INTEGERAL_PART(t*dz);
1327+ clipped->flags= local_p0->flags&local_p1->flags;
1328+}
--- marathon/trunk/Source_Files/RenderMain/collection_definition.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/collection_definition.h (revision 530)
@@ -1,170 +1,170 @@
1-#ifndef __COLLECTION_DEFINITION_H
2-#define __COLLECTION_DEFINITION_H
3-
4-/*
5-COLLECTION_DEFINITION.H
6-
7- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
8- and the "Aleph One" developers.
9-
10- This program is free software; you can redistribute it and/or modify
11- it under the terms of the GNU General Public License as published by
12- the Free Software Foundation; either version 3 of the License, or
13- (at your option) any later version.
14-
15- This program is distributed in the hope that it will be useful,
16- but WITHOUT ANY WARRANTY; without even the implied warranty of
17- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18- GNU General Public License for more details.
19-
20- This license is contained in the file "COPYING",
21- which is included with this source code; it is available online at
22- http://www.gnu.org/licenses/gpl.html
23-
24-Friday, June 17, 1994 11:48:27 AM
25-
26-Friday, June 17, 1994 11:27:13 PM
27- added .minimum_light_intensity field to low-level shape.
28-Tuesday, June 21, 1994 2:59:16 PM
29- added collection version number, added unused bytes to all structures.
30-Wednesday, June 22, 1994 3:53:22 PM
31- scaling modifications.
32-Wednesday, June 22, 1994 10:07:38 PM
33- added _scenery_collection type, .size field to collection_definition structure, changed
34- ヤshape_indexesユ to ヤlow_level_shape_indexesユ in high_level_shape_definition structure
35-Saturday, July 9, 1994 3:36:05 PM
36- added NUMBER_OF_PRIVATE_COLORS constant.
37-*/
38-
39-/* ---------- collection definition structure */
40-
41-/* 2 added pixels_to_world to collection_definition structure */
42-/* 3 added size to collection_definition structure */
43-#define COLLECTION_VERSION 3
44-
45-/* at the beginning of the clut, used by the extractor for various opaque reasons */
46-#define NUMBER_OF_PRIVATE_COLORS 3
47-
48-enum /* collection types */
49-{
50- _unused_collection= 0, /* raw */
51- _wall_collection, /* raw */
52- _object_collection, /* rle */
53- _interface_collection, /* raw */
54- _scenery_collection /* rle */
55-};
56-
57-struct high_level_shape_definition;
58-struct low_level_shape_definition;
59-struct bitmap_definition;
60-struct rgb_color_value;
61-
62-struct collection_definition
63-{
64- int16 version;
65-
66- int16 type; /* used for get_shape_descriptors() */
67- uint16 flags; /* [unused.16] */
68-
69- int16 color_count, clut_count;
70- int32 color_table_offset; /* an array of clut_count arrays of color_count ColorSpec structures */
71-
72- int16 high_level_shape_count;
73- int32 high_level_shape_offset_table_offset;
74-
75- int16 low_level_shape_count;
76- int32 low_level_shape_offset_table_offset;
77-
78- int16 bitmap_count;
79- int32 bitmap_offset_table_offset;
80-
81- int16 pixels_to_world; /* used to shift pixel values into world coordinates */
82-
83- int32 size; /* used to assert offsets */
84-
85- int16 unused[253];
86-
87- std::vector<rgb_color_value> color_tables;
88- std::vector<std::vector<uint8> > high_level_shapes;
89- std::vector<low_level_shape_definition> low_level_shapes;
90- std::vector<std::vector<uint8> > bitmaps;
91-};
92-const int SIZEOF_collection_definition = 544;
93-
94-/* ---------- high level shape definition */
95-
96-#define HIGH_LEVEL_SHAPE_NAME_LENGTH 32
97-
98-struct high_level_shape_definition // Starting with number_of_views, this is a shape_animation_data structure
99-{
100- int16 type; /* ==0 */
101- uint16 flags; /* [unused.16] */
102-
103- char name[HIGH_LEVEL_SHAPE_NAME_LENGTH+2];
104-
105- int16 number_of_views;
106-
107- int16 frames_per_view, ticks_per_frame;
108- int16 key_frame;
109-
110- int16 transfer_mode;
111- int16 transfer_mode_period; /* in ticks */
112-
113- int16 first_frame_sound, key_frame_sound, last_frame_sound;
114-
115- int16 pixels_to_world;
116-
117- int16 loop_frame;
118-
119- int16 unused[14];
120-
121- /* see the interface.h/shape_animation_data for a decription of how many
122- low-level indices follow (it's not simply number_of_view * frames_per_view) */
123- int16 low_level_shape_indexes[1];
124-};
125-const int SIZEOF_high_level_shape_definition = 90;
126-
127-/* --------- low-level shape definition */
128-
129-#define _X_MIRRORED_BIT 0x8000
130-#define _Y_MIRRORED_BIT 0x4000
131-#define _KEYPOINT_OBSCURED_BIT 0x2000
132-
133-struct low_level_shape_definition
134-{
135- uint16 flags; /* [x-mirror.1] [y-mirror.1] [keypoint_obscured.1] [unused.13] */
136-
137- _fixed minimum_light_intensity; /* in [0,FIXED_ONE] */
138-
139- int16 bitmap_index;
140-
141- /* (x,y) in pixel coordinates of origin */
142- int16 origin_x, origin_y;
143-
144- /* (x,y) in pixel coordinates of key point */
145- int16 key_x, key_y;
146-
147- int16 world_left, world_right, world_top, world_bottom;
148- int16 world_x0, world_y0;
149-
150- int16 unused[4];
151-};
152-const int SIZEOF_low_level_shape_definition = 36;
153-
154-/* ---------- colors */
155-
156-enum
157-{
158- SELF_LUMINESCENT_COLOR_FLAG= 0x80
159-};
160-
161-struct rgb_color_value
162-{
163- uint8 flags;
164- uint8 value;
165-
166- uint16 red, green, blue;
167-};
168-const int SIZEOF_rgb_color_value = 8;
169-
170-#endif
1+#ifndef __COLLECTION_DEFINITION_H
2+#define __COLLECTION_DEFINITION_H
3+
4+/*
5+COLLECTION_DEFINITION.H
6+
7+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
8+ and the "Aleph One" developers.
9+
10+ This program is free software; you can redistribute it and/or modify
11+ it under the terms of the GNU General Public License as published by
12+ the Free Software Foundation; either version 3 of the License, or
13+ (at your option) any later version.
14+
15+ This program is distributed in the hope that it will be useful,
16+ but WITHOUT ANY WARRANTY; without even the implied warranty of
17+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+ GNU General Public License for more details.
19+
20+ This license is contained in the file "COPYING",
21+ which is included with this source code; it is available online at
22+ http://www.gnu.org/licenses/gpl.html
23+
24+Friday, June 17, 1994 11:48:27 AM
25+
26+Friday, June 17, 1994 11:27:13 PM
27+ added .minimum_light_intensity field to low-level shape.
28+Tuesday, June 21, 1994 2:59:16 PM
29+ added collection version number, added unused bytes to all structures.
30+Wednesday, June 22, 1994 3:53:22 PM
31+ scaling modifications.
32+Wednesday, June 22, 1994 10:07:38 PM
33+ added _scenery_collection type, .size field to collection_definition structure, changed
34+ ヤshape_indexesユ to ヤlow_level_shape_indexesユ in high_level_shape_definition structure
35+Saturday, July 9, 1994 3:36:05 PM
36+ added NUMBER_OF_PRIVATE_COLORS constant.
37+*/
38+
39+/* ---------- collection definition structure */
40+
41+/* 2 added pixels_to_world to collection_definition structure */
42+/* 3 added size to collection_definition structure */
43+#define COLLECTION_VERSION 3
44+
45+/* at the beginning of the clut, used by the extractor for various opaque reasons */
46+#define NUMBER_OF_PRIVATE_COLORS 3
47+
48+enum /* collection types */
49+{
50+ _unused_collection= 0, /* raw */
51+ _wall_collection, /* raw */
52+ _object_collection, /* rle */
53+ _interface_collection, /* raw */
54+ _scenery_collection /* rle */
55+};
56+
57+struct high_level_shape_definition;
58+struct low_level_shape_definition;
59+struct bitmap_definition;
60+struct rgb_color_value;
61+
62+struct collection_definition
63+{
64+ int16 version;
65+
66+ int16 type; /* used for get_shape_descriptors() */
67+ uint16 flags; /* [unused.16] */
68+
69+ int16 color_count, clut_count;
70+ int32 color_table_offset; /* an array of clut_count arrays of color_count ColorSpec structures */
71+
72+ int16 high_level_shape_count;
73+ int32 high_level_shape_offset_table_offset;
74+
75+ int16 low_level_shape_count;
76+ int32 low_level_shape_offset_table_offset;
77+
78+ int16 bitmap_count;
79+ int32 bitmap_offset_table_offset;
80+
81+ int16 pixels_to_world; /* used to shift pixel values into world coordinates */
82+
83+ int32 size; /* used to assert offsets */
84+
85+ int16 unused[253];
86+
87+ std::vector<rgb_color_value> color_tables;
88+ std::vector<std::vector<uint8> > high_level_shapes;
89+ std::vector<low_level_shape_definition> low_level_shapes;
90+ std::vector<std::vector<uint8> > bitmaps;
91+};
92+const int SIZEOF_collection_definition = 544;
93+
94+/* ---------- high level shape definition */
95+
96+#define HIGH_LEVEL_SHAPE_NAME_LENGTH 32
97+
98+struct high_level_shape_definition // Starting with number_of_views, this is a shape_animation_data structure
99+{
100+ int16 type; /* ==0 */
101+ uint16 flags; /* [unused.16] */
102+
103+ char name[HIGH_LEVEL_SHAPE_NAME_LENGTH+2];
104+
105+ int16 number_of_views;
106+
107+ int16 frames_per_view, ticks_per_frame;
108+ int16 key_frame;
109+
110+ int16 transfer_mode;
111+ int16 transfer_mode_period; /* in ticks */
112+
113+ int16 first_frame_sound, key_frame_sound, last_frame_sound;
114+
115+ int16 pixels_to_world;
116+
117+ int16 loop_frame;
118+
119+ int16 unused[14];
120+
121+ /* see the interface.h/shape_animation_data for a decription of how many
122+ low-level indices follow (it's not simply number_of_view * frames_per_view) */
123+ int16 low_level_shape_indexes[1];
124+};
125+const int SIZEOF_high_level_shape_definition = 90;
126+
127+/* --------- low-level shape definition */
128+
129+#define _X_MIRRORED_BIT 0x8000
130+#define _Y_MIRRORED_BIT 0x4000
131+#define _KEYPOINT_OBSCURED_BIT 0x2000
132+
133+struct low_level_shape_definition
134+{
135+ uint16 flags; /* [x-mirror.1] [y-mirror.1] [keypoint_obscured.1] [unused.13] */
136+
137+ _fixed minimum_light_intensity; /* in [0,FIXED_ONE] */
138+
139+ int16 bitmap_index;
140+
141+ /* (x,y) in pixel coordinates of origin */
142+ int16 origin_x, origin_y;
143+
144+ /* (x,y) in pixel coordinates of key point */
145+ int16 key_x, key_y;
146+
147+ int16 world_left, world_right, world_top, world_bottom;
148+ int16 world_x0, world_y0;
149+
150+ int16 unused[4];
151+};
152+const int SIZEOF_low_level_shape_definition = 36;
153+
154+/* ---------- colors */
155+
156+enum
157+{
158+ SELF_LUMINESCENT_COLOR_FLAG= 0x80
159+};
160+
161+struct rgb_color_value
162+{
163+ uint8 flags;
164+ uint8 value;
165+
166+ uint16 red, green, blue;
167+};
168+const int SIZEOF_rgb_color_value = 8;
169+
170+#endif
--- marathon/trunk/Source_Files/RenderMain/OGL_Faders.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/OGL_Faders.h (revision 530)
@@ -1,57 +1,57 @@
1-#ifndef _OGL_FADERS_
2-#define _OGL_FADERS_
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- OpenGL Renderer,
22- by Loren Petrich,
23- May 30, 2000
24-
25- This contains code for doing fader stuff.
26-*/
27-
28-
29-// Indicates whether OpenGL-rendering faders will be used
30-bool OGL_FaderActive();
31-
32-// Which kinds of faders in the fader queue?
33-enum
34-{
35- FaderQueue_Liquid,
36- FaderQueue_Other,
37- NUMBER_OF_FADER_QUEUE_ENTRIES
38-};
39-
40-// Fader data
41-struct OGL_Fader
42-{
43- // Which type of fade to do
44- short Type;
45- // The three color channels and a transparency channel
46- float Color[4];
47-
48- OGL_Fader(): Type(NONE) {}
49-};
50-
51-// Fader=queue accessor
52-OGL_Fader *GetOGL_FaderQueueEntry(int Index);
53-
54-// Fader renderer; returns whether or not OpenGL faders were active.
55-bool OGL_DoFades(float Left, float Top, float Right, float Bottom);
56-
57-#endif
1+#ifndef _OGL_FADERS_
2+#define _OGL_FADERS_
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+ OpenGL Renderer,
22+ by Loren Petrich,
23+ May 30, 2000
24+
25+ This contains code for doing fader stuff.
26+*/
27+
28+
29+// Indicates whether OpenGL-rendering faders will be used
30+bool OGL_FaderActive();
31+
32+// Which kinds of faders in the fader queue?
33+enum
34+{
35+ FaderQueue_Liquid,
36+ FaderQueue_Other,
37+ NUMBER_OF_FADER_QUEUE_ENTRIES
38+};
39+
40+// Fader data
41+struct OGL_Fader
42+{
43+ // Which type of fade to do
44+ short Type;
45+ // The three color channels and a transparency channel
46+ float Color[4];
47+
48+ OGL_Fader(): Type(NONE) {}
49+};
50+
51+// Fader=queue accessor
52+OGL_Fader *GetOGL_FaderQueueEntry(int Index);
53+
54+// Fader renderer; returns whether or not OpenGL faders were active.
55+bool OGL_DoFades(float Left, float Top, float Right, float Bottom);
56+
57+#endif
--- marathon/trunk/Source_Files/RenderMain/ImageLoader_SDL.cpp (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/ImageLoader_SDL.cpp (revision 530)
@@ -1,142 +1,142 @@
1-/*
2-
3- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4- and the "Aleph One" developers.
5-
6- This program is free software; you can redistribute it and/or modify
7- it under the terms of the GNU General Public License as published by
8- the Free Software Foundation; either version 3 of the License, or
9- (at your option) any later version.
10-
11- This program is distributed in the hope that it will be useful,
12- but WITHOUT ANY WARRANTY; without even the implied warranty of
13- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14- GNU General Public License for more details.
15-
16- This license is contained in the file "COPYING",
17- which is included with this source code; it is available online at
18- http://www.gnu.org/licenses/gpl.html
19-
20-*/
21-
22-/*
23- * ImageLoader_SDL.cpp - Image file loading, SDL implementation
24- *
25- * Written in 2001 by Christian Bauer
26- */
27-
28-#include "ImageLoader.h"
29-#include "FileHandler.h"
30-
31-#ifdef HAVE_SDL_IMAGE_H
32-#include <SDL_image.h>
33-#endif
34-
35-#include <cmath>
36-
37-/*
38- * Load specified image file
39- */
40-
41-bool ImageDescriptor::LoadFromFile(FileSpecifier& File, int ImgMode, int flags, int actual_width, int actual_height, int maxSize)
42-{
43- if (flags & ImageLoader_ImageIsAlreadyPremultiplied)
44- PremultipliedAlpha = true;
45-
46- // Don't load opacity if there is no color component:
47- switch(ImgMode) {
48- case ImageLoader_Colors:
49- if (LoadDDSFromFile(File, flags, actual_width, actual_height, maxSize)) return true;
50- break;
51-
52- case ImageLoader_Opacity:
53- if (!IsPresent())
54- return false;
55- break;
56-
57- default:
58- vassert(false, csprintf(temporary,"Bad image mode for loader: %d",ImgMode));
59- }
60-
61- // Load image to surface
62- OpenedFile of;
63- if (!File.Open(of))
64- {
65- return false;
66- }
67-#ifdef HAVE_SDL_IMAGE
68- SDL_Surface *s = IMG_Load_RW(of.GetRWops(), 0);
69-#else
70- SDL_Surface *s = SDL_LoadBMP_RW(of.GetRWops(), 0);
71-#endif
72- if (s == NULL)
73- return false;
74-
75- // Get image dimensions and set its size
76- int Width = s->w, Height = s->h;
77- int OriginalWidth = (actual_width) ? actual_width : Width;
78- int OriginalHeight = (actual_height) ? actual_height : Height;
79- if (flags & ImageLoader_ResizeToPowersOfTwo) {
80- Width = NextPowerOfTwo(Width);
81- Height = NextPowerOfTwo(Height);
82- }
83- switch (ImgMode) {
84- case ImageLoader_Colors:
85- Resize(Width, Height);
86- VScale = ((double) OriginalWidth / (double) Width);
87- UScale = ((double) OriginalHeight / (double) Height);
88- MipMapCount = 0;
89- break;
90-
91- case ImageLoader_Opacity:
92- // If the wrong size, then bug out
93- if (Width != this->Width || Height != this->Height || ((double) OriginalWidth / Width != VScale || ((double) OriginalHeight / Height != UScale))) {
94- SDL_FreeSurface(s);
95- return false;
96- }
97- break;
98- }
99-
100- // Convert to 32-bit OpenGL-friendly RGBA surface
101-#ifdef ALEPHONE_LITTLE_ENDIAN
102- SDL_Surface *rgba = SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
103-#else
104- SDL_Surface *rgba = SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Height, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
105-#endif
106- if (rgba == NULL) {
107- SDL_FreeSurface(s);
108- return false;
109- }
110-
111- SDL_SetAlpha(s, 0, 0xff); // disable SDL_SRCALPHA
112- SDL_BlitSurface(s, NULL, rgba, NULL);
113- SDL_FreeSurface(s);
114-
115- // Convert surface to RGBA texture
116- switch (ImgMode) {
117- case ImageLoader_Colors:
118- memcpy(GetPixelBasePtr(), rgba->pixels, Width * Height * 4);
119- break;
120-
121- case ImageLoader_Opacity: {
122- uint8 *p = (uint8 *)rgba->pixels;
123- uint8 *q = (uint8 *)GetPixelBasePtr();
124- for (int h=0; h<Height; h++) {
125- for (int w=0; w<Width; w++) {
126- // RGB to greyscale value, and then to the opacity
127- float Red = float(*p++);
128- float Green = float(*p++);
129- float Blue = float(*p++);
130- p++;
131- float Opacity = (Red + Green + Blue) / 3.0F;
132- q[3] = PIN(int(Opacity + 0.5), 0, 255);
133- q += 4;
134- }
135- }
136- break;
137- }
138- }
139-
140- SDL_FreeSurface(rgba);
141- return true;
142-}
1+/*
2+
3+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4+ and the "Aleph One" developers.
5+
6+ This program is free software; you can redistribute it and/or modify
7+ it under the terms of the GNU General Public License as published by
8+ the Free Software Foundation; either version 3 of the License, or
9+ (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU General Public License for more details.
15+
16+ This license is contained in the file "COPYING",
17+ which is included with this source code; it is available online at
18+ http://www.gnu.org/licenses/gpl.html
19+
20+*/
21+
22+/*
23+ * ImageLoader_SDL.cpp - Image file loading, SDL implementation
24+ *
25+ * Written in 2001 by Christian Bauer
26+ */
27+
28+#include "ImageLoader.h"
29+#include "FileHandler.h"
30+
31+#ifdef HAVE_SDL_IMAGE_H
32+#include <SDL_image.h>
33+#endif
34+
35+#include <cmath>
36+
37+/*
38+ * Load specified image file
39+ */
40+
41+bool ImageDescriptor::LoadFromFile(FileSpecifier& File, int ImgMode, int flags, int actual_width, int actual_height, int maxSize)
42+{
43+ if (flags & ImageLoader_ImageIsAlreadyPremultiplied)
44+ PremultipliedAlpha = true;
45+
46+ // Don't load opacity if there is no color component:
47+ switch(ImgMode) {
48+ case ImageLoader_Colors:
49+ if (LoadDDSFromFile(File, flags, actual_width, actual_height, maxSize)) return true;
50+ break;
51+
52+ case ImageLoader_Opacity:
53+ if (!IsPresent())
54+ return false;
55+ break;
56+
57+ default:
58+ vassert(false, csprintf(temporary,"Bad image mode for loader: %d",ImgMode));
59+ }
60+
61+ // Load image to surface
62+ OpenedFile of;
63+ if (!File.Open(of))
64+ {
65+ return false;
66+ }
67+#ifdef HAVE_SDL_IMAGE
68+ SDL_Surface *s = IMG_Load_RW(of.GetRWops(), 0);
69+#else
70+ SDL_Surface *s = SDL_LoadBMP_RW(of.GetRWops(), 0);
71+#endif
72+ if (s == NULL)
73+ return false;
74+
75+ // Get image dimensions and set its size
76+ int Width = s->w, Height = s->h;
77+ int OriginalWidth = (actual_width) ? actual_width : Width;
78+ int OriginalHeight = (actual_height) ? actual_height : Height;
79+ if (flags & ImageLoader_ResizeToPowersOfTwo) {
80+ Width = NextPowerOfTwo(Width);
81+ Height = NextPowerOfTwo(Height);
82+ }
83+ switch (ImgMode) {
84+ case ImageLoader_Colors:
85+ Resize(Width, Height);
86+ VScale = ((double) OriginalWidth / (double) Width);
87+ UScale = ((double) OriginalHeight / (double) Height);
88+ MipMapCount = 0;
89+ break;
90+
91+ case ImageLoader_Opacity:
92+ // If the wrong size, then bug out
93+ if (Width != this->Width || Height != this->Height || ((double) OriginalWidth / Width != VScale || ((double) OriginalHeight / Height != UScale))) {
94+ SDL_FreeSurface(s);
95+ return false;
96+ }
97+ break;
98+ }
99+
100+ // Convert to 32-bit OpenGL-friendly RGBA surface
101+#ifdef ALEPHONE_LITTLE_ENDIAN
102+ SDL_Surface *rgba = SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
103+#else
104+ SDL_Surface *rgba = SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Height, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
105+#endif
106+ if (rgba == NULL) {
107+ SDL_FreeSurface(s);
108+ return false;
109+ }
110+
111+ SDL_SetAlpha(s, 0, 0xff); // disable SDL_SRCALPHA
112+ SDL_BlitSurface(s, NULL, rgba, NULL);
113+ SDL_FreeSurface(s);
114+
115+ // Convert surface to RGBA texture
116+ switch (ImgMode) {
117+ case ImageLoader_Colors:
118+ memcpy(GetPixelBasePtr(), rgba->pixels, Width * Height * 4);
119+ break;
120+
121+ case ImageLoader_Opacity: {
122+ uint8 *p = (uint8 *)rgba->pixels;
123+ uint8 *q = (uint8 *)GetPixelBasePtr();
124+ for (int h=0; h<Height; h++) {
125+ for (int w=0; w<Width; w++) {
126+ // RGB to greyscale value, and then to the opacity
127+ float Red = float(*p++);
128+ float Green = float(*p++);
129+ float Blue = float(*p++);
130+ p++;
131+ float Opacity = (Red + Green + Blue) / 3.0F;
132+ q[3] = PIN(int(Opacity + 0.5), 0, 255);
133+ q += 4;
134+ }
135+ }
136+ break;
137+ }
138+ }
139+
140+ SDL_FreeSurface(rgba);
141+ return true;
142+}
--- marathon/trunk/Source_Files/RenderMain/ImageLoader.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/ImageLoader.h (revision 530)
@@ -1,216 +1,216 @@
1-#ifndef _IMAGE_LOADER_
2-#define _IMAGE_LOADER_
3-/*
4-
5- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6- and the "Aleph One" developers.
7-
8- This program is free software; you can redistribute it and/or modify
9- it under the terms of the GNU General Public License as published by
10- the Free Software Foundation; either version 3 of the License, or
11- (at your option) any later version.
12-
13- This program is distributed in the hope that it will be useful,
14- but WITHOUT ANY WARRANTY; without even the implied warranty of
15- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16- GNU General Public License for more details.
17-
18- This license is contained in the file "COPYING",
19- which is included with this source code; it is available online at
20- http://www.gnu.org/licenses/gpl.html
21-
22- Image-Loader Interface File,
23- by Loren Petrich,
24- October 21, 2000
25-
26- This file contains an image-descriptor object and a function for loading the image
27- from a file.
28-
29-*/
30-
31-#include "DDS.h"
32-#include <vector>
33-#include "cseries.h"
34-#include "FileHandler.h"
35-
36-using namespace std;
37-
38-// Need an object to hold the read-in image.
39-class ImageDescriptor
40-{
41- int Width; // along scanlines
42- int Height; // scanline to scanline
43-
44- double VScale;
45- double UScale;
46-
47- uint32 *Pixels;
48- int Size;
49-
50- int MipMapCount;
51-
52-public:
53-
54- bool IsPresent() const {return (Pixels != NULL); }
55- bool IsPremultiplied() const { return (IsPresent() ? PremultipliedAlpha : false); }
56-
57- bool LoadFromFile(FileSpecifier& File, int ImgMode, int flags, int actual_width = 0, int actual_height = 0, int maxSize = 0);
58-
59- // Size of level 0 image
60- int GetWidth() const {return Width;}
61- int GetHeight() const {return Height;}
62- int GetNumPixels() const {return Width*Height;}
63-
64- int GetMipMapCount() const { return MipMapCount; }
65- int GetTotalBytes() const { return Size; }
66- int GetBufferSize() const { return Size; }
67- int GetFormat() const { return Format; }
68-
69- double GetVScale() const { return VScale; }
70- double GetUScale() const { return UScale; }
71-
72- // Pixel accessors
73- uint32& GetPixel(int Horiz, int Vert) {return Pixels[Width*(Vert%Height) + (Horiz%Width)];}
74- uint32 *GetPixelBasePtr() {return Pixels;}
75- const uint32 *GetBuffer() const { return Pixels; }
76- uint32 *GetBuffer() { return Pixels; }
77-
78- uint32 *GetMipMapPtr(int Level);
79- const uint32 *GetMipMapPtr(int Level) const;
80- int GetMipMapSize(int level) const;
81-
82- // Reallocation
83- void Resize(int _Width, int _Height);
84-
85- // mipmappy operations
86- void Resize(int _Width, int _Height, int _TotalBytes);
87-
88- bool Minify();
89-
90- bool MakeRGBA();
91- bool MakeDXTC3();
92-
93- void PremultiplyAlpha();
94- bool PremultipliedAlpha; // public so find silhouette version can unset
95-
96- // Clearing
97- void Clear()
98- {Width = Height = Size = 0; delete []Pixels; Pixels = NULL;}
99-
100- ImageDescriptor(const ImageDescriptor &CopyFrom);
101-
102-ImageDescriptor(): Width(0), Height(0), VScale(1.0), UScale(1.0), Pixels(NULL), Size(0), PremultipliedAlpha(false) {}
103-
104- // asumes RGBA8
105- ImageDescriptor(int width, int height, uint32 *pixels);
106-
107- enum ImageFormat {
108- RGBA8,
109- DXTC1,
110- DXTC3,
111- DXTC5,
112- Unknown
113- };
114-
115- ~ImageDescriptor()
116- {
117- delete []Pixels;
118- Pixels = NULL;
119- }
120-
121-private:
122- bool LoadDDSFromFile(FileSpecifier& File, int flags, int actual_width = 0, int actual_height = 0, int maxSize = 0);
123- bool LoadMipMapFromFile(OpenedFile &File, int flags, int level, DDSURFACEDESC2 &ddsd, int skip);
124- bool SkipMipMapFromFile(OpenedFile &File, int flags, int level, DDSURFACEDESC2 &ddsd);
125-
126- ImageFormat Format;
127-};
128-
129-template <typename T>
130-class copy_on_edit
131-{
132-public:
133- copy_on_edit() : _original(NULL), _copy(NULL) { };
134-
135- void set(const T* original) {
136- if (_copy) {
137- delete _copy;
138- _copy = NULL;
139- }
140- _original = original;
141- }
142-
143- void set(T* original) {
144- if (_copy) {
145- delete _copy;
146- _copy= NULL;
147- }
148- _original = original;
149- }
150-
151-
152- const T* get() {
153- if (_copy)
154- return (const T*) _copy;
155- else
156- return (const T*) _original;
157- }
158-
159- T* edit() {
160- if (!_original) {
161- return _copy;
162- } else {
163- if (!_copy) {
164- _copy = new T(*_original);
165- }
166- return _copy;
167- }
168- }
169-
170- // takes possession of copy
171- T* edit(T* copy) {
172- if (_copy) {
173- delete _copy;
174- }
175- _original = NULL;
176- _copy = copy;
177- return _copy;
178- }
179-
180- ~copy_on_edit() {
181- if (_copy) {
182- delete _copy;
183- _copy = NULL;
184- }
185- }
186-
187-private:
188- T* _original;
189- T* _copy;
190-};
191-
192-typedef copy_on_edit<ImageDescriptor> ImageDescriptorManager;
193-
194-
195-// What to load: image colors (must be loaded first)
196-// or image opacity (replaces the default, which is 100% opaque everywhere).
197-// The image-opacity image must have the same size as the color image;
198-// it is interpreted as a grayscale image.
199-enum {
200- ImageLoader_Colors,
201- ImageLoader_Opacity
202-};
203-
204-enum {
205- ImageLoader_ResizeToPowersOfTwo = 0x1,
206- ImageLoader_CanUseDXTC = 0x2,
207- ImageLoader_LoadMipMaps = 0x4,
208- ImageLoader_LoadDXTC1AsDXTC3 = 0x8,
209- ImageLoader_ImageIsAlreadyPremultiplied = 0x10
210-};
211-// Returns whether or not the loading was successful
212-//bool LoadImageFromFile(ImageDescriptor& Img, FileSpecifier& File, int ImgMode, int flags, int maxSize = 0);
213-
214-uint32 *GetMipMapPtr(uint32 *pixels, int size, int level, int width, int height, int format);
215-
216-#endif
1+#ifndef _IMAGE_LOADER_
2+#define _IMAGE_LOADER_
3+/*
4+
5+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
6+ and the "Aleph One" developers.
7+
8+ This program is free software; you can redistribute it and/or modify
9+ it under the terms of the GNU General Public License as published by
10+ the Free Software Foundation; either version 3 of the License, or
11+ (at your option) any later version.
12+
13+ This program is distributed in the hope that it will be useful,
14+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU General Public License for more details.
17+
18+ This license is contained in the file "COPYING",
19+ which is included with this source code; it is available online at
20+ http://www.gnu.org/licenses/gpl.html
21+
22+ Image-Loader Interface File,
23+ by Loren Petrich,
24+ October 21, 2000
25+
26+ This file contains an image-descriptor object and a function for loading the image
27+ from a file.
28+
29+*/
30+
31+#include "DDS.h"
32+#include <vector>
33+#include "cseries.h"
34+#include "FileHandler.h"
35+
36+using namespace std;
37+
38+// Need an object to hold the read-in image.
39+class ImageDescriptor
40+{
41+ int Width; // along scanlines
42+ int Height; // scanline to scanline
43+
44+ double VScale;
45+ double UScale;
46+
47+ uint32 *Pixels;
48+ int Size;
49+
50+ int MipMapCount;
51+
52+public:
53+
54+ bool IsPresent() const {return (Pixels != NULL); }
55+ bool IsPremultiplied() const { return (IsPresent() ? PremultipliedAlpha : false); }
56+
57+ bool LoadFromFile(FileSpecifier& File, int ImgMode, int flags, int actual_width = 0, int actual_height = 0, int maxSize = 0);
58+
59+ // Size of level 0 image
60+ int GetWidth() const {return Width;}
61+ int GetHeight() const {return Height;}
62+ int GetNumPixels() const {return Width*Height;}
63+
64+ int GetMipMapCount() const { return MipMapCount; }
65+ int GetTotalBytes() const { return Size; }
66+ int GetBufferSize() const { return Size; }
67+ int GetFormat() const { return Format; }
68+
69+ double GetVScale() const { return VScale; }
70+ double GetUScale() const { return UScale; }
71+
72+ // Pixel accessors
73+ uint32& GetPixel(int Horiz, int Vert) {return Pixels[Width*(Vert%Height) + (Horiz%Width)];}
74+ uint32 *GetPixelBasePtr() {return Pixels;}
75+ const uint32 *GetBuffer() const { return Pixels; }
76+ uint32 *GetBuffer() { return Pixels; }
77+
78+ uint32 *GetMipMapPtr(int Level);
79+ const uint32 *GetMipMapPtr(int Level) const;
80+ int GetMipMapSize(int level) const;
81+
82+ // Reallocation
83+ void Resize(int _Width, int _Height);
84+
85+ // mipmappy operations
86+ void Resize(int _Width, int _Height, int _TotalBytes);
87+
88+ bool Minify();
89+
90+ bool MakeRGBA();
91+ bool MakeDXTC3();
92+
93+ void PremultiplyAlpha();
94+ bool PremultipliedAlpha; // public so find silhouette version can unset
95+
96+ // Clearing
97+ void Clear()
98+ {Width = Height = Size = 0; delete []Pixels; Pixels = NULL;}
99+
100+ ImageDescriptor(const ImageDescriptor &CopyFrom);
101+
102+ImageDescriptor(): Width(0), Height(0), VScale(1.0), UScale(1.0), Pixels(NULL), Size(0), PremultipliedAlpha(false) {}
103+
104+ // asumes RGBA8
105+ ImageDescriptor(int width, int height, uint32 *pixels);
106+
107+ enum ImageFormat {
108+ RGBA8,
109+ DXTC1,
110+ DXTC3,
111+ DXTC5,
112+ Unknown
113+ };
114+
115+ ~ImageDescriptor()
116+ {
117+ delete []Pixels;
118+ Pixels = NULL;
119+ }
120+
121+private:
122+ bool LoadDDSFromFile(FileSpecifier& File, int flags, int actual_width = 0, int actual_height = 0, int maxSize = 0);
123+ bool LoadMipMapFromFile(OpenedFile &File, int flags, int level, DDSURFACEDESC2 &ddsd, int skip);
124+ bool SkipMipMapFromFile(OpenedFile &File, int flags, int level, DDSURFACEDESC2 &ddsd);
125+
126+ ImageFormat Format;
127+};
128+
129+template <typename T>
130+class copy_on_edit
131+{
132+public:
133+ copy_on_edit() : _original(NULL), _copy(NULL) { };
134+
135+ void set(const T* original) {
136+ if (_copy) {
137+ delete _copy;
138+ _copy = NULL;
139+ }
140+ _original = original;
141+ }
142+
143+ void set(T* original) {
144+ if (_copy) {
145+ delete _copy;
146+ _copy= NULL;
147+ }
148+ _original = original;
149+ }
150+
151+
152+ const T* get() {
153+ if (_copy)
154+ return (const T*) _copy;
155+ else
156+ return (const T*) _original;
157+ }
158+
159+ T* edit() {
160+ if (!_original) {
161+ return _copy;
162+ } else {
163+ if (!_copy) {
164+ _copy = new T(*_original);
165+ }
166+ return _copy;
167+ }
168+ }
169+
170+ // takes possession of copy
171+ T* edit(T* copy) {
172+ if (_copy) {
173+ delete _copy;
174+ }
175+ _original = NULL;
176+ _copy = copy;
177+ return _copy;
178+ }
179+
180+ ~copy_on_edit() {
181+ if (_copy) {
182+ delete _copy;
183+ _copy = NULL;
184+ }
185+ }
186+
187+private:
188+ T* _original;
189+ T* _copy;
190+};
191+
192+typedef copy_on_edit<ImageDescriptor> ImageDescriptorManager;
193+
194+
195+// What to load: image colors (must be loaded first)
196+// or image opacity (replaces the default, which is 100% opaque everywhere).
197+// The image-opacity image must have the same size as the color image;
198+// it is interpreted as a grayscale image.
199+enum {
200+ ImageLoader_Colors,
201+ ImageLoader_Opacity
202+};
203+
204+enum {
205+ ImageLoader_ResizeToPowersOfTwo = 0x1,
206+ ImageLoader_CanUseDXTC = 0x2,
207+ ImageLoader_LoadMipMaps = 0x4,
208+ ImageLoader_LoadDXTC1AsDXTC3 = 0x8,
209+ ImageLoader_ImageIsAlreadyPremultiplied = 0x10
210+};
211+// Returns whether or not the loading was successful
212+//bool LoadImageFromFile(ImageDescriptor& Img, FileSpecifier& File, int ImgMode, int flags, int maxSize = 0);
213+
214+uint32 *GetMipMapPtr(uint32 *pixels, int size, int level, int width, int height, int format);
215+
216+#endif
--- marathon/trunk/Source_Files/RenderMain/render.cpp (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/render.cpp (revision 530)
@@ -1,1119 +1,1119 @@
1-/*
2-RENDER.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, September 8, 1994 1:58:20 PM (Jason')
22-
23-Friday, September 9, 1994 1:36:15 PM (Jason')
24- on the quads, in the sun.
25-Sunday, September 11, 1994 7:32:49 PM (Jason')
26- the clock on the 540 was wrong, yesterday was Saturday (not Friday). on quads again, but
27- back home now. something will draw before i go to bed tonight. dinner at the nile?
28-Tuesday, September 13, 1994 2:54:56 AM (Jason')
29- no fair!ムム itユs still monday, really. with the aid of some graphical debugging the clipping
30- all works now and iユm trying to have the entire floor/ceiling thing going tonight (the nile
31- was closed by the time i got around to taking a shower and heading out).
32-Friday, September 16, 1994 4:06:17 AM (Jason')
33- walls, floors and ceilings texture, wobble, etc. contemplating objects ... maybe this will
34- work after all.
35-Monday, September 19, 1994 11:03:49 AM (Jason')
36- unified xz_clip_vertical_polygon() and z_clip_horizontal_polygon() to get rid of the last
37- known whitespace problem. canユt wait to see what others i have. objects now respect the
38- clipping windows of all nodes they cross.
39-Monday, October 24, 1994 4:35:38 PM (Jason)
40- fixed render sorting problem with objects of equal depth (i.e., parasitic objects).
41-Tuesday, October 25, 1994 5:14:27 PM (Jason')
42- fixed object sort order with respect to nodes and height.
43-Wednesday, October 26, 1994 3:18:59 PM (Jason)
44- fixed half of the object sort order back so that it worked: in order to correctly handle
45- objects below the viewer projecting into higher polygons we need to sort objects inside
46- nodes (to be draw after their walls and ceilings but before their floors).
47-Wednesday, November 2, 1994 3:49:57 PM (Jason)
48- the bottom panel of short split sides sometimes takes on the ceiling lightsource.
49-Tuesday, November 8, 1994 5:29:12 PM (Jason')
50- implemented new transfer modes: _slide, _wander. _render_effect_earthquake doesnユt work
51- yet because the player can shake behind his own shape.
52-Thursday, December 15, 1994 12:15:55 AM (Jason)
53- the object depth sort order problem ocurrs with multiple objects in the same polygon,
54- is some function of relative depths and overlap, and does not seem to involve objects at
55- the same depth. also, it seems to sort many further objects in front of a single closer
56- one.
57-Monday, January 23, 1995 6:53:26 AM (Jason')
58- the way to fix the render object sorting problem is to ignore overlap and sort everything
59- by depth, regardless. imagine: two, far, non-overlapping objects; by the old algorithm their
60- drawing order is irrelevant. when a closer object which overlaps both of them is sorted, it
61- only attempts to lie in front of the closest of the two (leaving the farthest one in an
62- uncertain position). unfortunately this will cause us to do unnecessary promotion and might
63- look stupid.
64-Sunday, March 26, 1995 12:57:39 AM (Jason')
65- media modifications for marathon2; the object sort order problem still exists (the above
66- solution indeed looked stupid).
67-Thursday, March 30, 1995 11:23:35 PM (Jason')
68- tried to fix object sort problem by attempting to assure that objects are always drawn in
69- depth-order within a node.
70-Monday, June 5, 1995 8:37:42 AM (Jason)
71- blood and fire (baby).
72-
73-Jan 30, 2000 (Loren Petrich):
74- Added some typecasts
75- Increased MAXIMUM_NODE_ALIASES to 32
76- Added an "assert" for when DEBUG is off in aliases-building section in sort_render_tree().
77-
78-Feb 1, 2000 (Loren Petrich):
79- Added growable list of node aliases; replaced static-list node-alias code
80-
81-Feb 4, 2000 (Loren Petrich):
82- Changed halt() to assert(false) for better debugging
83-
84-Feb 5, 2000 (Loren Petrich):
85- Added growable lists of nodes and also clips for endpoints and lines.
86-
87-Feb 6, 2000 (Loren Petrich):
88- Doing initial allocations of the growable lists of various quantities as a defensive measure
89- against memory leaks that seem to occur.
90-
91-Feb 9, 2000 (Loren Petrich):
92- Suppressed ambiguous-clip-flag debugging statement;
93- it gets activated only for excessively distant objects
94-
95-Feb 10, 2000 (Loren Petrich):
96- Added dynamic-limits setting of MAXIMUM_RENDER_OBJECTS
97-
98-Feb 14, 2000 (Loren Petrich):
99- Added test for other-side polygon to LINE_IS_TRANSPARENT() check in next_polygon_along_line()
100-
101-Feb 16, 2000 (Loren Petrich):
102- Put in handling of overflow digits for the purpose of doing long distance correctly;
103- also turning several horizontal-coordinate short integers into long ones.
104-
105-Feb 17, 2000 (Loren Petrich):
106- Made the sprites long-distance-friendly; there is a bug where they flip around when they
107- go past half the world size, but that's a short-integer wraparound, and the relevant routine
108- is in map.c.
109-
110-Feb 18, 2000 (Loren Petrich):
111- Added support for conditional display of weapons-in-hand; so as to support third-person
112- as well as first-person view.
113-
114-Feb 21, 2000 (Loren Petrich):
115- Idiot-proofed next_polygon_along_line(), making it quit a loop if it searches a whole circle.
116-
117-Feb 24, 2000 (Loren Petrich):
118- Added animated-texture support
119-
120-Mar 3, 2000 (Loren Petrich):
121- Set view to normal in initialize_view_data();
122- squashed persistent-extravision bug.
123-
124-Mar 5, 2000 (Loren Petrich):
125- Moved extravision-persistence bug fix out of this file.
126-
127-Mar 9, 2000 (Loren Petrich):
128- Sorted the nodes by polygon index in sort_render_tree() and used them to speed up searches
129- for nodes with the same polygon index; maps with slowed-down visibility calculations,
130- such as Desla, can become twice as fast.
131-
132-Mar 12, 2000 (Loren Petrich):
133- Added OpenGL support
134-
135-Mar 14, 2000 (Loren Petrich):
136- Modified data transmitted to OpenGL renderer; it's now collection/color/frame for
137- both walls and sprites. Also added transmission of view data.
138-
139-Mar 24, 2000 (Loren Petrich):
140- Added landscape_yaw calculation; this is the yaw of the landscapes' left edges
141-
142-Mar 30, 2000 (Loren Petrich):
143- Inspired by Rhys Hill's work, I've created a second tree to contain the visibility nodes;
144- in addition to their visibility tree, they have a polygon-sort tree.
145- This tree is implemented by setting up some additional members of node_data
146- for indicating its structure; there are members for polygon >, polygon <,
147- and the next member of a chain that shares polygon-index values.
148- As a result, the node-aliases list can now be abolished once and for all.
149-
150-Jun 11, 2000 (Loren Petrich):
151- Added support for see-through liquids; this requires several changes.
152- The rendering of each map polygon had to be changed so that there would be a
153- separate liquid surface; it would no longer replace the floor or the ceiling.
154- Next, the inhabitant objects had to be done in two passes, one other side, and one view side.
155- Also, whether there is void on the other side had to be indicated, so that
156- waterfalls and the like may look right.
157-
158-Jun 28, 2000 (Loren Petrich):
159- Fixed Aaron Davies bug; if a polygon is completely below a liquid, it will not be rendered
160- if the viewpoint is above the liquid; the bug was that it was not rendered if the viewpoint
161- was below the liquid. This only happened if semitransparent liquid surfaces was turned off.
162-
163-Jul 10, 2000 (Loren Petrich):
164- Fixed liquid visibility bug in render_tree() that happens when liquid surfaces are not semitransparent;
165- rendering is skipped if the viewpoint is under a liquid and the polygon is high and dry,
166- or else if the viewpoint is above a liquid and the polygon is submerged.
167-
168-Jul 17, 2000 (Loren Petrich):
169- Suppressed view-effect resetting in initialize_view_data(),
170- in order to make teleport view-stretching work correctly.
171-
172-Aug 9, 2000 (Loren Petrich):
173- Moved most of the rendering code here into separate files with these classes:
174-
175- RenderVisTreeClass --
176- creates the visibility tree (which polygons can be seen from which other ones)
177- RenderSortPolyClass --
178- uses that tree to sort the polygons into appropriate depth order
179- RenderPlaceObjsClass --
180- finds which objects are visible and places them into appropriately sorted order
181- RenderRasterize --
182- handles the clipping of each object and requests those objects' rasterization
183-
184- Added a rasterizer class; currently, it does everything from the base class,
185- though what it does will be moved into subclasses.
186-
187-Sep 2, 2000 (Loren Petrich):
188- Added some idiot-proofing, since the shapes accessor now returns NULL for nonexistent bitmaps
189-
190-Nov 12, 2000 (Loren Petrich):
191- Added automap reset before rendering
192-
193-Nov 29, 2000 (Loren Petrich):
194- Made teleport static/fold effect optional
195-
196-Jan 17, 2001 (Loren Petrich):
197- Added vertical flipping
198-*/
199-
200-
201-#ifdef QUICKDRAW_DEBUG
202-#include "macintosh_cseries.h"
203-#else
204-#include "cseries.h"
205-#endif
206-
207-#include "map.h"
208-#include "render.h"
209-#include "interface.h"
210-#include "lightsource.h"
211-#include "media.h"
212-#include "weapons.h"
213-
214-// LP additions
215-#include "dynamic_limits.h"
216-#include "AnimatedTextures.h"
217-#ifdef HAVE_OPENGL
218-#include "OGL_Render.h"
219-#endif
220-
221-#ifdef QUICKDRAW_DEBUG
222-#include "shell.h"
223-extern WindowPtr screen_window;
224-#endif
225-
226-#include <math.h>
227-#include <string.h>
228-#include <stdlib.h>
229-
230-// LP additions for decomposition of this code:
231-#include "RenderVisTree.h"
232-#include "RenderSortPoly.h"
233-#include "RenderPlaceObjs.h"
234-#include "RenderRasterize.h"
235-#include "Rasterizer_SW.h"
236-#ifdef HAVE_OPENGL
237-#include "Rasterizer_OGL.h"
238-#include "RenderRasterize_Shader.h"
239-#include "Rasterizer_Shader.h"
240-#endif
241-#include "preferences.h"
242-#include "screen.h"
243-
244-#ifdef env68k
245-#pragma segment render
246-#endif
247-
248-/* use native alignment */
249-#if defined (powerc) || defined (__powerc)
250-#pragma options align=power
251-#endif
252-
253-/*
254-//render transparent walls (if a bit is set or if the transparent texture is non-NULL?)
255-//use side lightsources instead of taking them from their polygons
256-//respect dark side bit (darken light intensity by k)
257-//fix solid/opaque endpoint confusion (solidity does not imply opacity)
258-
259-there exists a problem where an object can overlap into a polygon which is clipped by something
260- behind the object but that will clip the object because clip windows are subtractive; how
261- is this solved?
262-itユs still possible to get ambiguous clip flags, usually in very narrow (e.g., 1 pixel) windows
263-the renderer has a maximum range beyond which it shits bricks yet which it allows to be exceeded
264-itユs still possible, especially in high-res full-screen, for points to end up (slightly) off
265- the screen (usually discarding these has no noticable effect on the scene)
266-whitespace results when two adjacent polygons are clipped to different vertical windows. this
267- is not trivially solved with the current implementation, and may be acceptable (?)
268-
269-//build_base_polygon_index_list() should discard lower polygons for objects above the viewer and
270-// higher polygons for objects below the viewer because we certainly donユt sort objects
271-// correctly in these cases
272-//in strange cases, objects are sorted out of order. this seems to involve players in some way
273-// (i.e., parasitic objects).
274-*/
275-
276-/* ---------- constants */
277-
278-#define EXPLOSION_EFFECT_RANGE (WORLD_ONE/12)
279-
280-/* ---------- clip buffer */
281-// Not used for anything
282-#define CLIP_INDEX_BUFFER_SIZE 4096
283-
284-vector<uint16> RenderFlagList;
285-
286-// uint16 *render_flags;
287-
288-// LP additions: decomposition of the rendering code into various objects
289-
290-static RenderVisTreeClass RenderVisTree; // Visibility-tree object
291-static RenderSortPolyClass RenderSortPoly; // Polygon-sorting object
292-static RenderPlaceObjsClass RenderPlaceObjs; // Object-placement object
293-static RenderRasterizerClass Render_Classic; // Clipping and rasterization class
294-
295-static Rasterizer_SW_Class Rasterizer_SW; // Software rasterizer
296-#ifdef HAVE_OPENGL
297-static Rasterizer_OGL_Class Rasterizer_OGL; // OpenGL rasterizer
298-static Rasterizer_Shader_Class Rasterizer_Shader; // Shader rasterizer
299-static RenderRasterize_Shader Render_Shader; // Shader clipping and rasterization class
300-#endif
301-
302-void OGL_Rasterizer_Init() {
303-
304-#ifdef HAVE_OPENGL
305- if (graphics_preferences->screen_mode.acceleration == _shader_acceleration)
306- Render_Shader.setupGL();
307-#endif
308-}
309-
310-/* ---------- private prototypes */
311-
312-static void update_view_data(struct view_data *view);
313-static void update_render_effect(struct view_data *view);
314-static void shake_view_origin(struct view_data *view, world_distance delta);
315-
316-static void render_viewer_sprite_layer(view_data *view, RasterizerClass *RasPtr);
317-static void position_sprite_axis(short *x0, short *x1, short scale_width, short screen_width,
318- short positioning_mode, _fixed position, bool flip, world_distance world_left, world_distance world_right);
319-
320-
321-#ifdef QUICKDRAW_DEBUG
322-static void debug_flagged_points(flagged_world_point2d *points, short count);
323-static void debug_flagged_points3d(flagged_world_point3d *points, short count);
324-static void debug_vector(world_vector2d *v);
325-static void debug_x_line(world_distance x);
326-#endif
327-
328-/* ---------- code */
329-
330-void allocate_render_memory(
331- void)
332-{
333- assert(NUMBER_OF_RENDER_FLAGS<=16);
334- RenderFlagList.resize(RENDER_FLAGS_BUFFER_SIZE);
335-
336- // LP addition: check out pointer-arithmetic hack
337- assert(sizeof(void *) == sizeof(POINTER_DATA));
338-
339- // LP change: do max allocation
340- RenderVisTree.Resize(MAXIMUM_ENDPOINTS_PER_MAP,MAXIMUM_LINES_PER_MAP);
341- RenderSortPoly.Resize(MAXIMUM_POLYGONS_PER_MAP);
342-
343- // LP change: set up pointers
344- RenderSortPoly.RVPtr = &RenderVisTree;
345- RenderPlaceObjs.RVPtr = &RenderVisTree;
346- RenderPlaceObjs.RSPtr = &RenderSortPoly;
347-#ifdef HAVE_OPENGL
348- Render_Classic.RSPtr = Render_Shader.RSPtr = &RenderSortPoly;
349-#else
350- Render_Classic.RSPtr = &RenderSortPoly;
351-#endif
352-}
353-
354-/* just in case anyone was wondering, standard_screen_width will usually be the same as
355- screen_width. the renderer assumes that the given field_of_view matches the standard
356- width provided (so if the actual width provided is larger, you'll be able to see more;
357- if it's smaller you'll be able to see less). this allows the destination bitmap to not
358- only grow and shrink while maintaining a constant aspect ratio, but to also change in
359- geometry without effecting the image being projected onto it. if you don't understand
360- this, pass standard_width==width */
361-void initialize_view_data(
362- struct view_data *view)
363-{
364- double two_pi= 8.0*atan(1.0);
365- double half_cone= view->field_of_view*(two_pi/360.0)/2;
366- /* half_cone needs to be extended for non oblique perspective projection (gluPerspective).
367- this is required because the viewing angle is different for about the same field of view */
368- if (graphics_preferences->screen_mode.acceleration == _shader_acceleration)
369- half_cone= (view->field_of_view * 1.3)*(two_pi/360.0)/2;
370-
371- double adjusted_half_cone= View_FOV_FixHorizontalNotVertical() ?
372- half_cone :
373- atan(view->screen_width*tan(half_cone)/view->standard_screen_width);
374- double world_to_screen;
375-
376- view->half_screen_width= view->screen_width/2;
377- view->half_screen_height= view->screen_height/2;
378-
379- /* if thereユs a round-off error in half_cone, we want to make the cone too big (so when we clip
380- lines ヤto the edge of the screenユ theyユre actually off the screen, thus +1.0) */
381- view->half_cone= (angle) (adjusted_half_cone*((double)NUMBER_OF_ANGLES)/two_pi+1.0);
382-
383- // LP change: find the adjusted yaw for the landscapes;
384- // this is the effective yaw value for the left edge.
385- // A landscape rotation can also be added if desired.
386- view->landscape_yaw = view->yaw - view->half_cone;
387-
388- /* calculate world_to_screen; we could calculate this with standard_screen_width/2 and
389- the old half_cone and get the same result */
390- world_to_screen= view->half_screen_width/tan(adjusted_half_cone);
391- view->world_to_screen_x= view->real_world_to_screen_x= (short) ((world_to_screen/view->horizontal_scale)+0.5);
392- view->world_to_screen_y= view->real_world_to_screen_y= (short) ((world_to_screen/view->vertical_scale)+0.5);
393-
394- /* calculate the vertical cone angle; again, overflow instead of underflow when rounding */
395- view->half_vertical_cone= (angle) (NUMBER_OF_ANGLES*atan(((double)view->half_screen_height*view->vertical_scale)/world_to_screen)/two_pi+1.0);
396-
397- /* calculate left edge vector */
398- view->untransformed_left_edge.i= view->world_to_screen_x;
399- view->untransformed_left_edge.j= - view->half_screen_width;
400-
401- /* calculate right edge vector (negative, so it clips in the right direction) */
402- view->untransformed_right_edge.i= - view->world_to_screen_x;
403- view->untransformed_right_edge.j= - view->half_screen_width;
404-
405- /* reset any active effects */
406- // LP: this is now called in render_screen(), so we need to disable the initializing
407-}
408-
409-/* origin,origin_polygon_index,yaw,pitch,roll,etc. have probably changed since last call */
410-void render_view(
411- struct view_data *view,
412- struct bitmap_definition *destination)
413-{
414- update_view_data(view);
415-
416- /* clear the render flags */
417- objlist_clear(render_flags, RENDER_FLAGS_BUFFER_SIZE);
418-
419- ResetOverheadMap();
420-/*
421-#ifdef AUTOMAP_DEBUG
422- memset(automap_lines, 0, (dynamic_world->line_count/8+((dynamic_world->line_count%8)?1:0)*sizeof(byte)));
423- memset(automap_polygons, 0, (dynamic_world->polygon_count/8+((dynamic_world->polygon_count%8)?1:0)*sizeof(byte)));
424-#endif
425-*/
426-
427- if(view->terminal_mode_active)
428- {
429- /* Render the computer interface. */
430- render_computer_interface(view);
431- }
432- else
433- {
434- // LP: the render objects have a pointer to the current view in them,
435- // so that one can get rid of redundant references to it in them.
436-
437- // LP: now from the visibility-tree class
438- /* build the render tree, regardless of map mode, so the automap updates while active */
439- RenderVisTree.view = view;
440- RenderVisTree.build_render_tree();
441-
442- /* do something complicated and difficult to explain */
443- if (!view->overhead_map_active || map_is_translucent())
444- {
445- // LP: now from the polygon-sorter class
446- /* sort the render tree (so we have a depth-ordering of polygons) and accumulate
447- clipping information for each polygon */
448- RenderSortPoly.view = view;
449- RenderSortPoly.sort_render_tree();
450-
451- // LP: now from the object-placement class
452- /* build the render object list by looking at the sorted render tree */
453- RenderPlaceObjs.view = view;
454- RenderPlaceObjs.build_render_object_list();
455-
456- // LP addition: set the current rasterizer to whichever is appropriate here
457- RasterizerClass *RasPtr;
458-#ifdef HAVE_OPENGL
459- if (OGL_IsActive())
460- RasPtr = (graphics_preferences->screen_mode.acceleration == _shader_acceleration) ? &Rasterizer_Shader : &Rasterizer_OGL;
461- else
462- {
463-#endif
464- // The software renderer needs this but the OpenGL one doesn't...
465- Rasterizer_SW.screen = destination;
466- RasPtr = &Rasterizer_SW;
467-#ifdef HAVE_OPENGL
468- }
469-#endif
470-
471- // Set its view:
472- RasPtr->SetView(*view);
473-
474- // Start rendering main view
475- RasPtr->Begin();
476-
477- // LP: now from the clipping/rasterizer class
478-#ifdef HAVE_OPENGL
479- RenderRasterizerClass *RenPtr = (graphics_preferences->screen_mode.acceleration == _shader_acceleration) ? &Render_Shader : &Render_Classic;
480-#else
481- RenderRasterizerClass *RenPtr = &Render_Classic;
482-#endif
483- /* render the object list, back to front, doing clipping on each surface before passing
484- it to the texture-mapping code */
485- RenPtr->view = view;
486- RenPtr->RasPtr = RasPtr;
487- RenPtr->render_tree();
488-
489- // LP: won't put this into a separate class
490- /* render the playerユs weapons, etc. */
491- render_viewer_sprite_layer(view, RasPtr);
492-
493- // Finish rendering main view
494- RasPtr->End();
495- }
496-
497- if (view->overhead_map_active)
498- {
499- /* if the overhead map is active, render it */
500- render_overhead_map(view);
501- }
502- }
503-}
504-
505-void start_render_effect(
506- struct view_data *view,
507- short effect)
508-{
509- view->effect= effect;
510- view->effect_phase= NONE;
511-}
512-
513-/* ---------- private code */
514-
515-static void update_view_data(
516- struct view_data *view)
517-{
518- angle theta;
519-
520- // LP change: doing all the FOV changes here:
521- View_AdjustFOV(view->field_of_view,view->target_field_of_view);
522-
523- if (view->effect==NONE)
524- {
525- view->world_to_screen_x= view->real_world_to_screen_x;
526- view->world_to_screen_y= view->real_world_to_screen_y;
527- }
528- else
529- {
530- update_render_effect(view);
531- }
532-
533- view->untransformed_left_edge.i= view->world_to_screen_x;
534- view->untransformed_right_edge.i= - view->world_to_screen_x;
535-
536- /* calculate world_to_screen_y*tan(pitch) */
537- view->dtanpitch= (view->world_to_screen_y*sine_table[view->pitch])/cosine_table[view->pitch];
538-
539- /* calculate left cone vector */
540- theta= NORMALIZE_ANGLE(view->yaw-view->half_cone);
541- view->left_edge.i= cosine_table[theta], view->left_edge.j= sine_table[theta];
542-
543- /* calculate right cone vector */
544- theta= NORMALIZE_ANGLE(view->yaw+view->half_cone);
545- view->right_edge.i= cosine_table[theta], view->right_edge.j= sine_table[theta];
546-
547- /* calculate top cone vector (negative to clip the right direction) */
548- view->top_edge.i= - view->world_to_screen_y;
549- view->top_edge.j= - (view->half_screen_height + view->dtanpitch); /* ==k */
550-
551- /* calculate bottom cone vector */
552- view->bottom_edge.i= view->world_to_screen_y;
553- view->bottom_edge.j= - view->half_screen_height + view->dtanpitch; /* ==k */
554-
555- /* if weユre sitting on one of the endpoints in our origin polygon, move us back slightly (ア1) into
556- that polygon. when we split rays weユre assuming that weユll never pass through a given
557- vertex in different directions (because if we do the tree becomes a graph) but when
558- we start on a vertex this can happen. this is a destructive modification of the origin. */
559- {
560- short i;
561- struct polygon_data *polygon= get_polygon_data(view->origin_polygon_index);
562-
563- for (i= 0;i<polygon->vertex_count;++i)
564- {
565- struct world_point2d *vertex= &get_endpoint_data(polygon->endpoint_indexes[i])->vertex;
566-
567- if (vertex->x==view->origin.x && vertex->y==view->origin.y)
568- {
569- world_point2d *ccw_vertex= &get_endpoint_data(polygon->endpoint_indexes[WRAP_LOW(i, polygon->vertex_count-1)])->vertex;
570- world_point2d *cw_vertex= &get_endpoint_data(polygon->endpoint_indexes[WRAP_HIGH(i, polygon->vertex_count-1)])->vertex;
571- world_vector2d inset_vector;
572-
573- inset_vector.i= (ccw_vertex->x-vertex->x) + (cw_vertex->x-vertex->x);
574- inset_vector.j= (ccw_vertex->y-vertex->y) + (cw_vertex->y-vertex->y);
575- view->origin.x+= SGN(inset_vector.i);
576- view->origin.y+= SGN(inset_vector.j);
577-
578- break;
579- }
580- }
581-
582- /* determine whether we are under or over the media boundary of our polygon; we will see all
583- other media boundaries from this orientation (above or below) or fail to draw them. */
584- if (polygon->media_index==NONE)
585- {
586- view->under_media_boundary= false;
587- }
588- else
589- {
590- struct media_data *media= get_media_data(polygon->media_index);
591-
592- // LP change: idiot-proofing
593- if (media)
594- {
595- view->under_media_boundary= UNDER_MEDIA(media, view->origin.z);
596- view->under_media_index= polygon->media_index;
597- } else {
598- view->under_media_boundary= false;
599- }
600- }
601- }
602-}
603-
604-static void update_render_effect(
605- struct view_data *view)
606-{
607- short effect= view->effect;
608- short phase= view->effect_phase==NONE ? 0 : (view->effect_phase+view->ticks_elapsed);
609- short period;
610-
611- view->effect_phase= phase;
612-
613- switch (effect)
614- {
615- // LP change: suppressed all the FOV changes
616- case _render_effect_fold_in: case _render_effect_fold_out: period= TICKS_PER_SECOND/2; break;
617- case _render_effect_explosion: period= TICKS_PER_SECOND; break;
618- default:
619- assert(false);
620- break;
621- }
622-
623- if (phase>period)
624- {
625- view->effect= NONE;
626- }
627- else
628- {
629- switch (effect)
630- {
631- case _render_effect_explosion:
632- shake_view_origin(view, EXPLOSION_EFFECT_RANGE - ((EXPLOSION_EFFECT_RANGE/2)*phase)/period);
633- break;
634-
635- case _render_effect_fold_in:
636- phase= period-phase;
637- case _render_effect_fold_out:
638- /* calculate world_to_screen based on phase */
639- view->world_to_screen_x= view->real_world_to_screen_x + (4*view->real_world_to_screen_x*phase)/period;
640- view->world_to_screen_y= view->real_world_to_screen_y - (view->real_world_to_screen_y*phase)/(period+period/4);
641- break;
642- }
643- }
644-}
645-
646-
647-/* ---------- transfer modes */
648-
649-/* given a transfer mode and phase, cause whatever changes it should cause to a rectangle_definition
650- structure */
651-void instantiate_rectangle_transfer_mode(
652- view_data *view,
653- rectangle_definition *rectangle,
654- short transfer_mode,
655- _fixed transfer_phase)
656-{
657- // For the 3D-model code
658- rectangle->HorizScale = 1;
659-
660- switch (transfer_mode)
661- {
662- case _xfer_invisibility:
663- case _xfer_subtle_invisibility:
664- if (view->shading_mode!=_shading_infravision)
665- {
666- rectangle->transfer_mode= _tinted_transfer;
667- rectangle->shading_tables= get_global_shading_table();
668- rectangle->transfer_data= (transfer_mode==_xfer_invisibility) ? 0x000f : 0x0018;
669- break;
670- }
671- /* if we have infravision, fall through to _textured_transfer (i see you...) */
672- case _xfer_normal:
673- rectangle->transfer_mode= _textured_transfer;
674- break;
675-
676- case _xfer_static:
677- case _xfer_50percent_static:
678- rectangle->transfer_mode= _static_transfer;
679- rectangle->transfer_data= (transfer_mode==_xfer_static) ? 0x0000 : 0x8000;
680- break;
681-
682- case _xfer_fade_out_static:
683- rectangle->transfer_mode= _static_transfer;
684- rectangle->transfer_data= transfer_phase;
685- break;
686-
687- case _xfer_pulsating_static:
688- rectangle->transfer_mode= _static_transfer;
689- rectangle->transfer_data= 0x8000+((0x6000*sine_table[FIXED_INTEGERAL_PART(transfer_phase*NUMBER_OF_ANGLES)])>>TRIG_SHIFT);
690- break;
691-
692- case _xfer_fold_in:
693- transfer_phase= FIXED_ONE-transfer_phase; /* do everything backwards */
694- case _xfer_fold_out:
695- if (View_DoStaticEffect())
696- {
697- // Corrected the teleport shrinkage so that the sprite/object
698- // shrinks to its object position and not to its sprite center
699- short delta0= FIXED_INTEGERAL_PART(((rectangle->xc-rectangle->x0)-1)*transfer_phase);
700- short delta1= FIXED_INTEGERAL_PART(((rectangle->x1-rectangle->xc)-1)*transfer_phase);
701- // short delta= FIXED_INTEGERAL_PART((((rectangle->x1-rectangle->x0)>>1)-1)*transfer_phase);
702-
703- rectangle->transfer_mode= _static_transfer;
704- rectangle->transfer_data= (transfer_phase>>1);
705- rectangle->x0+= delta0;
706- rectangle->x1-= delta1;
707- rectangle->HorizScale = 1 - float(transfer_phase)/float(FIXED_ONE);
708- }
709- else
710- rectangle->transfer_mode= _textured_transfer;
711- break;
712-
713-#if 0
714- case _xfer_fade_out_to_black:
715- rectangle->shading_tables= get_global_shading_table();
716- if (transfer_phase<FIXED_ONE_HALF)
717- {
718- /* fade to black */
719- rectangle->ambient_shade= (rectangle->ambient_shade*(transfer_phase-FIXED_ONE_HALF))>>(FIXED_FRACTIONAL_BITS-1);
720- rectangle->transfer_mode= _textured_transfer;
721- }
722- else
723- {
724- /* vanish */
725- rectangle->transfer_mode= _tinted_transfer;
726- rectangle->transfer_data= 0x1f - ((0x1f*(FIXED_ONE_HALF-transfer_phase))>>(FIXED_FRACTIONAL_BITS-1));
727- }
728- break;
729-#endif
730-
731- // LP change: made an unrecognized mode act like normal
732- default:
733- rectangle->transfer_mode= _textured_transfer;
734- break;
735- }
736-}
737-
738-/* given a transfer mode and phase, cause whatever changes it should cause to a polygon_definition
739- structure (unfortunately we need to know whether this is a horizontal or vertical polygon) */
740-void instantiate_polygon_transfer_mode(
741- struct view_data *view,
742- struct polygon_definition *polygon,
743- short transfer_mode,
744- bool horizontal)
745-{
746- world_distance x0, y0;
747- world_distance vector_magnitude;
748- short alternate_transfer_phase;
749- short transfer_phase = view->tick_count;
750-
751- polygon->transfer_mode= _textured_transfer;
752- switch (transfer_mode)
753- {
754- case _xfer_fast_horizontal_slide:
755- case _xfer_horizontal_slide:
756- case _xfer_vertical_slide:
757- case _xfer_fast_vertical_slide:
758- case _xfer_wander:
759- case _xfer_fast_wander:
760- x0= y0= 0;
761- switch (transfer_mode)
762- {
763- case _xfer_fast_horizontal_slide: transfer_phase<<= 1;
764- case _xfer_horizontal_slide: x0= (transfer_phase<<2)&(WORLD_ONE-1); break;
765-
766- case _xfer_fast_vertical_slide: transfer_phase<<= 1;
767- case _xfer_vertical_slide: y0= (transfer_phase<<2)&(WORLD_ONE-1); break;
768-
769- case _xfer_fast_wander: transfer_phase<<= 1;
770- case _xfer_wander:
771- alternate_transfer_phase= transfer_phase%(10*FULL_CIRCLE);
772- transfer_phase= transfer_phase%(6*FULL_CIRCLE);
773- x0= (cosine_table[NORMALIZE_ANGLE(alternate_transfer_phase)] +
774- (cosine_table[NORMALIZE_ANGLE(2*alternate_transfer_phase)]>>1) +
775- (cosine_table[NORMALIZE_ANGLE(5*alternate_transfer_phase)]>>1))>>(WORLD_FRACTIONAL_BITS-TRIG_SHIFT+2);
776- y0= (sine_table[NORMALIZE_ANGLE(transfer_phase)] +
777- (sine_table[NORMALIZE_ANGLE(2*transfer_phase)]>>1) +
778- (sine_table[NORMALIZE_ANGLE(3*transfer_phase)]>>1))>>(WORLD_FRACTIONAL_BITS-TRIG_SHIFT+2);
779- break;
780- }
781- if (horizontal)
782- {
783- polygon->origin.x+= x0;
784- polygon->origin.y+= y0;
785- }
786- else
787- {
788- vector_magnitude= isqrt(polygon->vector.i*polygon->vector.i + polygon->vector.j*polygon->vector.j);
789- polygon->origin.x+= (polygon->vector.i*x0)/vector_magnitude;
790- polygon->origin.y+= (polygon->vector.j*x0)/vector_magnitude;
791- polygon->origin.z-= y0;
792- }
793- break;
794-
795- case _xfer_pulsate:
796- case _xfer_wobble:
797- case _xfer_fast_wobble:
798- if (transfer_mode==_xfer_fast_wobble) transfer_phase*= 15;
799- transfer_phase&= WORLD_ONE/16-1;
800- transfer_phase= (transfer_phase>=WORLD_ONE/32) ? (WORLD_ONE/32+WORLD_ONE/64 - transfer_phase) : (transfer_phase - WORLD_ONE/64);
801- if (horizontal)
802- {
803- polygon->origin.z+= transfer_phase;
804- }
805- else
806- {
807- if (transfer_mode==_xfer_pulsate) /* translate .origin perpendicular to .vector */
808- {
809- world_vector2d offset;
810- world_distance vector_magnitude= isqrt(polygon->vector.i*polygon->vector.i + polygon->vector.j*polygon->vector.j);
811-
812- offset.i= (polygon->vector.j*transfer_phase)/vector_magnitude;
813- offset.j= (polygon->vector.i*transfer_phase)/vector_magnitude;
814-
815- polygon->origin.x+= offset.i;
816- polygon->origin.y+= offset.j;
817- }
818- else /* ==_xfer_wobble, wobble .vector */
819- {
820- polygon->vector.i+= transfer_phase;
821- polygon->vector.j+= transfer_phase;
822- }
823- }
824- break;
825-
826- case _xfer_normal:
827- break;
828-
829- case _xfer_smear:
830- polygon->transfer_mode= _solid_transfer;
831- break;
832-
833- case _xfer_static:
834- polygon->transfer_mode= _static_transfer;
835- polygon->transfer_data= 0x0000;
836- break;
837-
838- case _xfer_landscape:
839- polygon->transfer_mode= _big_landscaped_transfer;
840- break;
841-// case _xfer_big_landscape:
842-// polygon->transfer_mode= _big_landscaped_transfer;
843-// break;
844-
845- default:
846- // LP change: made an unrecognized mode act like normal
847- break;
848- }
849-}
850-
851-/* ---------- viewer sprite layer (i.e., weapons) */
852-
853-static void render_viewer_sprite_layer(view_data *view, RasterizerClass *RasPtr)
854-{
855- rectangle_definition textured_rectangle;
856- weapon_display_information display_data;
857- shape_information_data *shape_information;
858- short count;
859-
860- // LP change: bug out if weapons-in-hand are not to be displayed
861- if (!view->show_weapons_in_hand) return;
862-
863- // Need to set this...
864- RasPtr->SetForeground();
865-
866- // No models here, and completely opaque
867- textured_rectangle.ModelPtr = NULL;
868- textured_rectangle.Opacity = 1;
869-
870- /* get_weapon_display_information() returns true if there is a weapon to be drawn. it
871- should initially be passed a count of zero. it returns the weaponユs texture and
872- enough information to draw it correctly. */
873- count= 0;
874- while (get_weapon_display_information(&count, &display_data))
875- {
876- /* fetch relevant shape data */
877- // LP: model-setup code is cribbed from
878- // RenderPlaceObjsClass::build_render_object() in RenderPlaceObjs.cpp
879-#ifdef HAVE_OPENGL
880- // Find which 3D model will take the place of this sprite, if any
881- short ModelSequence;
882- OGL_ModelData *ModelPtr =
883- OGL_GetModelData(GET_COLLECTION(display_data.collection),display_data.shape_index,ModelSequence);
884-#endif
885- shape_information= extended_get_shape_information(display_data.collection, display_data.low_level_shape_index);
886- // Nonexistent frame: skip
887- if (!shape_information) continue;
888- // No need for a fake sprite rectangle, since models are foreground objects
889-
890- // LP change: for the convenience of the OpenGL renderer
891- textured_rectangle.ShapeDesc = BUILD_DESCRIPTOR(display_data.collection,0);
892- textured_rectangle.LowLevelShape = display_data.low_level_shape_index;
893-#ifdef HAVE_OPENGL
894- textured_rectangle.ModelPtr = ModelPtr;
895- if (ModelPtr)
896- {
897- textured_rectangle.ModelSequence = ModelSequence;
898- textured_rectangle.ModelFrame = display_data.Frame;
899- textured_rectangle.NextModelFrame = display_data.NextFrame;
900- textured_rectangle.MixFrac = display_data.Ticks > 0 ?
901- float(display_data.Phase)/float(display_data.Ticks) : 0;
902- const world_point3d Zero = {0, 0, 0};
903- textured_rectangle.Position = Zero;
904- textured_rectangle.Azimuth = 0;
905- textured_rectangle.Scale = 1;
906- textured_rectangle.LightDepth = 0;
907- const GLfloat LightDirection[3] = {0, 1, 0}; // y is forward
908- objlist_copy(textured_rectangle.LightDirection,LightDirection,3);
909- RasPtr->SetForegroundView(display_data.flip_horizontal);
910- }
911-#endif
912-
913- if (shape_information->flags&_X_MIRRORED_BIT) display_data.flip_horizontal= !display_data.flip_horizontal;
914- if (shape_information->flags&_Y_MIRRORED_BIT) display_data.flip_vertical= !display_data.flip_vertical;
915-
916- /* calculate shape rectangle */
917- position_sprite_axis(&textured_rectangle.x0, &textured_rectangle.x1, view->screen_height, view->screen_width, display_data.horizontal_positioning_mode,
918- display_data.horizontal_position, display_data.flip_horizontal, shape_information->world_left, shape_information->world_right);
919- position_sprite_axis(&textured_rectangle.y0, &textured_rectangle.y1, view->screen_height, view->screen_height, display_data.vertical_positioning_mode,
920- display_data.vertical_position, display_data.flip_vertical, -shape_information->world_top, -shape_information->world_bottom);
921-
922- /* set rectangle bitmap and shading table */
923- extended_get_shape_bitmap_and_shading_table(display_data.collection, display_data.low_level_shape_index, &textured_rectangle.texture, &textured_rectangle.shading_tables, view->shading_mode);
924- if (!textured_rectangle.texture) continue;
925-
926- textured_rectangle.flags= 0;
927-
928- /* initialize clipping window to full screen */
929- textured_rectangle.clip_left= 0;
930- textured_rectangle.clip_right= view->screen_width;
931- textured_rectangle.clip_top= 0;
932- textured_rectangle.clip_bottom= view->screen_height;
933-
934- /* copy mirror flags */
935- textured_rectangle.flip_horizontal= display_data.flip_horizontal;
936- textured_rectangle.flip_vertical= display_data.flip_vertical;
937-
938- /* lighting: depth of zero in the cameraユs polygon index */
939- textured_rectangle.depth= 0;
940- textured_rectangle.ambient_shade= get_light_intensity(get_polygon_data(view->origin_polygon_index)->floor_lightsource_index);
941- textured_rectangle.ambient_shade= MAX(shape_information->minimum_light_intensity, textured_rectangle.ambient_shade);
942- if (view->shading_mode==_shading_infravision) textured_rectangle.flags|= _SHADELESS_BIT;
943-
944- // Calculate the object's horizontal position
945- // for the convenience of doing teleport-in/teleport-out
946- textured_rectangle.xc = (textured_rectangle.x0 + textured_rectangle.x1) >> 1;
947-
948- /* make the weapon reflect the ownerユs transfer mode */
949- instantiate_rectangle_transfer_mode(view, &textured_rectangle, display_data.transfer_mode, display_data.transfer_phase);
950-
951- /* and draw it */
952- // LP: added OpenGL support
953- RasPtr->texture_rectangle(textured_rectangle);
954- }
955-}
956-
957-static void position_sprite_axis(
958- short *x0,
959- short *x1,
960- short scale_width,
961- short screen_width,
962- short positioning_mode,
963- _fixed position,
964- bool flip,
965- world_distance world_left,
966- world_distance world_right)
967-{
968- short origin;
969-
970- /* if this shape is mirrored, reverse the left/right world coordinates */
971- if (flip)
972- {
973- world_distance swap= world_left;
974- world_left= -world_right, world_right= -swap;
975- }
976-
977- switch (positioning_mode)
978- {
979- case _position_center:
980- /* origin is the screen coordinate where the logical center of the shape will be drawn */
981- origin= (screen_width*position)>>FIXED_FRACTIONAL_BITS;
982- break;
983- case _position_low:
984- case _position_high:
985- /* origin is in [0,WORLD_ONE] and represents the amount of the weapon visible off the side */
986- origin= ((world_right-world_left)*position)>>FIXED_FRACTIONAL_BITS;
987- break;
988-
989- default:
990- assert(false);
991- break;
992- }
993-
994- switch (positioning_mode)
995- {
996- case _position_high:
997- *x0= screen_width - ((origin*scale_width)>>WORLD_FRACTIONAL_BITS);
998- *x1= *x0 + (((world_right-world_left)*scale_width)>>WORLD_FRACTIONAL_BITS);
999- break;
1000- case _position_low:
1001- *x1= ((origin*scale_width)>>WORLD_FRACTIONAL_BITS);
1002- *x0= *x1 - (((world_right-world_left)*scale_width)>>WORLD_FRACTIONAL_BITS);
1003- break;
1004-
1005- case _position_center:
1006- *x0= origin + ((world_left*scale_width)>>WORLD_FRACTIONAL_BITS);
1007- *x1= origin + ((world_right*scale_width)>>WORLD_FRACTIONAL_BITS);
1008- break;
1009-
1010- default:
1011- assert(false);
1012- break;
1013- }
1014-}
1015-
1016-static void shake_view_origin(
1017- struct view_data *view,
1018- world_distance delta)
1019-{
1020- world_point3d new_origin= view->origin;
1021- short half_delta= delta>>1;
1022-
1023- new_origin.x+= half_delta - ((delta*sine_table[NORMALIZE_ANGLE((view->tick_count&~3)*(7*FULL_CIRCLE))])>>TRIG_SHIFT);
1024- new_origin.y+= half_delta - ((delta*sine_table[NORMALIZE_ANGLE(((view->tick_count+5*TICKS_PER_SECOND)&~3)*(7*FULL_CIRCLE))])>>TRIG_SHIFT);
1025- new_origin.z+= half_delta - ((delta*sine_table[NORMALIZE_ANGLE(((view->tick_count+7*TICKS_PER_SECOND)&~3)*(7*FULL_CIRCLE))])>>TRIG_SHIFT);
1026-
1027- /* only use the new origin if we didnユt cross a polygon boundary */
1028- if (find_line_crossed_leaving_polygon(view->origin_polygon_index, (world_point2d *) &view->origin,
1029- (world_point2d *) &new_origin)==NONE)
1030- {
1031- view->origin= new_origin;
1032- }
1033-}
1034-
1035-// LP: begin no-compile
1036-#if 0
1037-
1038-/* ---------- mac-specific debugging calls */
1039-
1040-#ifdef QUICKDRAW_DEBUG
1041-
1042-#define SCALEF 5
1043-
1044-static void debug_flagged_points(
1045- flagged_world_point2d *points,
1046- short count)
1047-{
1048- short i;
1049-
1050- SetPort(screen_window);
1051- PenSize(1, 1);
1052- RGBForeColor(&rgb_black);
1053- RGBBackColor(&rgb_white);
1054- EraseRect(&screen_window->portRect);
1055- SetOrigin(-640/2, -480/2);
1056- MoveTo(-320, 0); LineTo(320, 0);
1057- MoveTo(0, 240); LineTo(0, -240);
1058- PenSize(2, 2);
1059- MoveTo(points[count-1].y>>SCALEF, - (points[count-1].x>>SCALEF));
1060- for (i=0;i<count;++i)
1061- {
1062- LineTo(points[i].y>>SCALEF, - (points[i].x>>SCALEF));
1063- psprintf(ptemporary, "%d", i);
1064- DrawString(temporary);
1065- MoveTo(points[i].y>>SCALEF, - (points[i].x>>SCALEF));
1066- }
1067-}
1068-
1069-static void debug_flagged_points3d(
1070- flagged_world_point3d *points,
1071- short count)
1072-{
1073- short i;
1074-
1075- SetPort(screen_window);
1076- PenSize(1, 1);
1077- RGBForeColor(&rgb_black);
1078- RGBBackColor(&rgb_white);
1079- EraseRect(&screen_window->portRect);
1080- SetOrigin(-640/2, -480/2);
1081- MoveTo(-320, 0); LineTo(320, 0);
1082- MoveTo(0, 240); LineTo(0, -240);
1083- PenSize(2, 2);
1084- MoveTo(points[count-1].z>>SCALEF, - (points[count-1].x>>SCALEF));
1085- for (i=0;i<count;++i)
1086- {
1087- LineTo(points[i].z>>SCALEF, - (points[i].x>>SCALEF));
1088- psprintf(ptemporary, "%d", i);
1089- DrawString(temporary);
1090- MoveTo(points[i].z>>SCALEF, - (points[i].x>>SCALEF));
1091- }
1092-}
1093-
1094-static void debug_vector(
1095- world_vector2d *v)
1096-{
1097- PenSize(1, 1);
1098- MoveTo(0, 0);
1099- LineTo(v->j, - v->i);
1100- MoveTo(0, 0);
1101- LineTo(- v->j, v->i);
1102-
1103- while (!Button()); while (Button());
1104-}
1105-
1106-static void debug_x_line(
1107- world_distance x)
1108-{
1109- PenSize(1, 1);
1110- MoveTo(-320, - x>>SCALEF);
1111- LineTo(320, - x>>SCALEF);
1112-
1113- while (!Button()); while (Button());
1114-}
1115-
1116-#endif /* QUICKDRAW DEBUG */
1117-
1118-// LP: end no-compile
1119-#endif
1+/*
2+RENDER.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, September 8, 1994 1:58:20 PM (Jason')
22+
23+Friday, September 9, 1994 1:36:15 PM (Jason')
24+ on the quads, in the sun.
25+Sunday, September 11, 1994 7:32:49 PM (Jason')
26+ the clock on the 540 was wrong, yesterday was Saturday (not Friday). on quads again, but
27+ back home now. something will draw before i go to bed tonight. dinner at the nile?
28+Tuesday, September 13, 1994 2:54:56 AM (Jason')
29+ no fair!ムム itユs still monday, really. with the aid of some graphical debugging the clipping
30+ all works now and iユm trying to have the entire floor/ceiling thing going tonight (the nile
31+ was closed by the time i got around to taking a shower and heading out).
32+Friday, September 16, 1994 4:06:17 AM (Jason')
33+ walls, floors and ceilings texture, wobble, etc. contemplating objects ... maybe this will
34+ work after all.
35+Monday, September 19, 1994 11:03:49 AM (Jason')
36+ unified xz_clip_vertical_polygon() and z_clip_horizontal_polygon() to get rid of the last
37+ known whitespace problem. canユt wait to see what others i have. objects now respect the
38+ clipping windows of all nodes they cross.
39+Monday, October 24, 1994 4:35:38 PM (Jason)
40+ fixed render sorting problem with objects of equal depth (i.e., parasitic objects).
41+Tuesday, October 25, 1994 5:14:27 PM (Jason')
42+ fixed object sort order with respect to nodes and height.
43+Wednesday, October 26, 1994 3:18:59 PM (Jason)
44+ fixed half of the object sort order back so that it worked: in order to correctly handle
45+ objects below the viewer projecting into higher polygons we need to sort objects inside
46+ nodes (to be draw after their walls and ceilings but before their floors).
47+Wednesday, November 2, 1994 3:49:57 PM (Jason)
48+ the bottom panel of short split sides sometimes takes on the ceiling lightsource.
49+Tuesday, November 8, 1994 5:29:12 PM (Jason')
50+ implemented new transfer modes: _slide, _wander. _render_effect_earthquake doesnユt work
51+ yet because the player can shake behind his own shape.
52+Thursday, December 15, 1994 12:15:55 AM (Jason)
53+ the object depth sort order problem ocurrs with multiple objects in the same polygon,
54+ is some function of relative depths and overlap, and does not seem to involve objects at
55+ the same depth. also, it seems to sort many further objects in front of a single closer
56+ one.
57+Monday, January 23, 1995 6:53:26 AM (Jason')
58+ the way to fix the render object sorting problem is to ignore overlap and sort everything
59+ by depth, regardless. imagine: two, far, non-overlapping objects; by the old algorithm their
60+ drawing order is irrelevant. when a closer object which overlaps both of them is sorted, it
61+ only attempts to lie in front of the closest of the two (leaving the farthest one in an
62+ uncertain position). unfortunately this will cause us to do unnecessary promotion and might
63+ look stupid.
64+Sunday, March 26, 1995 12:57:39 AM (Jason')
65+ media modifications for marathon2; the object sort order problem still exists (the above
66+ solution indeed looked stupid).
67+Thursday, March 30, 1995 11:23:35 PM (Jason')
68+ tried to fix object sort problem by attempting to assure that objects are always drawn in
69+ depth-order within a node.
70+Monday, June 5, 1995 8:37:42 AM (Jason)
71+ blood and fire (baby).
72+
73+Jan 30, 2000 (Loren Petrich):
74+ Added some typecasts
75+ Increased MAXIMUM_NODE_ALIASES to 32
76+ Added an "assert" for when DEBUG is off in aliases-building section in sort_render_tree().
77+
78+Feb 1, 2000 (Loren Petrich):
79+ Added growable list of node aliases; replaced static-list node-alias code
80+
81+Feb 4, 2000 (Loren Petrich):
82+ Changed halt() to assert(false) for better debugging
83+
84+Feb 5, 2000 (Loren Petrich):
85+ Added growable lists of nodes and also clips for endpoints and lines.
86+
87+Feb 6, 2000 (Loren Petrich):
88+ Doing initial allocations of the growable lists of various quantities as a defensive measure
89+ against memory leaks that seem to occur.
90+
91+Feb 9, 2000 (Loren Petrich):
92+ Suppressed ambiguous-clip-flag debugging statement;
93+ it gets activated only for excessively distant objects
94+
95+Feb 10, 2000 (Loren Petrich):
96+ Added dynamic-limits setting of MAXIMUM_RENDER_OBJECTS
97+
98+Feb 14, 2000 (Loren Petrich):
99+ Added test for other-side polygon to LINE_IS_TRANSPARENT() check in next_polygon_along_line()
100+
101+Feb 16, 2000 (Loren Petrich):
102+ Put in handling of overflow digits for the purpose of doing long distance correctly;
103+ also turning several horizontal-coordinate short integers into long ones.
104+
105+Feb 17, 2000 (Loren Petrich):
106+ Made the sprites long-distance-friendly; there is a bug where they flip around when they
107+ go past half the world size, but that's a short-integer wraparound, and the relevant routine
108+ is in map.c.
109+
110+Feb 18, 2000 (Loren Petrich):
111+ Added support for conditional display of weapons-in-hand; so as to support third-person
112+ as well as first-person view.
113+
114+Feb 21, 2000 (Loren Petrich):
115+ Idiot-proofed next_polygon_along_line(), making it quit a loop if it searches a whole circle.
116+
117+Feb 24, 2000 (Loren Petrich):
118+ Added animated-texture support
119+
120+Mar 3, 2000 (Loren Petrich):
121+ Set view to normal in initialize_view_data();
122+ squashed persistent-extravision bug.
123+
124+Mar 5, 2000 (Loren Petrich):
125+ Moved extravision-persistence bug fix out of this file.
126+
127+Mar 9, 2000 (Loren Petrich):
128+ Sorted the nodes by polygon index in sort_render_tree() and used them to speed up searches
129+ for nodes with the same polygon index; maps with slowed-down visibility calculations,
130+ such as Desla, can become twice as fast.
131+
132+Mar 12, 2000 (Loren Petrich):
133+ Added OpenGL support
134+
135+Mar 14, 2000 (Loren Petrich):
136+ Modified data transmitted to OpenGL renderer; it's now collection/color/frame for
137+ both walls and sprites. Also added transmission of view data.
138+
139+Mar 24, 2000 (Loren Petrich):
140+ Added landscape_yaw calculation; this is the yaw of the landscapes' left edges
141+
142+Mar 30, 2000 (Loren Petrich):
143+ Inspired by Rhys Hill's work, I've created a second tree to contain the visibility nodes;
144+ in addition to their visibility tree, they have a polygon-sort tree.
145+ This tree is implemented by setting up some additional members of node_data
146+ for indicating its structure; there are members for polygon >, polygon <,
147+ and the next member of a chain that shares polygon-index values.
148+ As a result, the node-aliases list can now be abolished once and for all.
149+
150+Jun 11, 2000 (Loren Petrich):
151+ Added support for see-through liquids; this requires several changes.
152+ The rendering of each map polygon had to be changed so that there would be a
153+ separate liquid surface; it would no longer replace the floor or the ceiling.
154+ Next, the inhabitant objects had to be done in two passes, one other side, and one view side.
155+ Also, whether there is void on the other side had to be indicated, so that
156+ waterfalls and the like may look right.
157+
158+Jun 28, 2000 (Loren Petrich):
159+ Fixed Aaron Davies bug; if a polygon is completely below a liquid, it will not be rendered
160+ if the viewpoint is above the liquid; the bug was that it was not rendered if the viewpoint
161+ was below the liquid. This only happened if semitransparent liquid surfaces was turned off.
162+
163+Jul 10, 2000 (Loren Petrich):
164+ Fixed liquid visibility bug in render_tree() that happens when liquid surfaces are not semitransparent;
165+ rendering is skipped if the viewpoint is under a liquid and the polygon is high and dry,
166+ or else if the viewpoint is above a liquid and the polygon is submerged.
167+
168+Jul 17, 2000 (Loren Petrich):
169+ Suppressed view-effect resetting in initialize_view_data(),
170+ in order to make teleport view-stretching work correctly.
171+
172+Aug 9, 2000 (Loren Petrich):
173+ Moved most of the rendering code here into separate files with these classes:
174+
175+ RenderVisTreeClass --
176+ creates the visibility tree (which polygons can be seen from which other ones)
177+ RenderSortPolyClass --
178+ uses that tree to sort the polygons into appropriate depth order
179+ RenderPlaceObjsClass --
180+ finds which objects are visible and places them into appropriately sorted order
181+ RenderRasterize --
182+ handles the clipping of each object and requests those objects' rasterization
183+
184+ Added a rasterizer class; currently, it does everything from the base class,
185+ though what it does will be moved into subclasses.
186+
187+Sep 2, 2000 (Loren Petrich):
188+ Added some idiot-proofing, since the shapes accessor now returns NULL for nonexistent bitmaps
189+
190+Nov 12, 2000 (Loren Petrich):
191+ Added automap reset before rendering
192+
193+Nov 29, 2000 (Loren Petrich):
194+ Made teleport static/fold effect optional
195+
196+Jan 17, 2001 (Loren Petrich):
197+ Added vertical flipping
198+*/
199+
200+
201+#ifdef QUICKDRAW_DEBUG
202+#include "macintosh_cseries.h"
203+#else
204+#include "cseries.h"
205+#endif
206+
207+#include "map.h"
208+#include "render.h"
209+#include "interface.h"
210+#include "lightsource.h"
211+#include "media.h"
212+#include "weapons.h"
213+
214+// LP additions
215+#include "dynamic_limits.h"
216+#include "AnimatedTextures.h"
217+#ifdef HAVE_OPENGL
218+#include "OGL_Render.h"
219+#endif
220+
221+#ifdef QUICKDRAW_DEBUG
222+#include "shell.h"
223+extern WindowPtr screen_window;
224+#endif
225+
226+#include <math.h>
227+#include <string.h>
228+#include <stdlib.h>
229+
230+// LP additions for decomposition of this code:
231+#include "RenderVisTree.h"
232+#include "RenderSortPoly.h"
233+#include "RenderPlaceObjs.h"
234+#include "RenderRasterize.h"
235+#include "Rasterizer_SW.h"
236+#ifdef HAVE_OPENGL
237+#include "Rasterizer_OGL.h"
238+#include "RenderRasterize_Shader.h"
239+#include "Rasterizer_Shader.h"
240+#endif
241+#include "preferences.h"
242+#include "screen.h"
243+
244+#ifdef env68k
245+#pragma segment render
246+#endif
247+
248+/* use native alignment */
249+#if defined (powerc) || defined (__powerc)
250+#pragma options align=power
251+#endif
252+
253+/*
254+//render transparent walls (if a bit is set or if the transparent texture is non-NULL?)
255+//use side lightsources instead of taking them from their polygons
256+//respect dark side bit (darken light intensity by k)
257+//fix solid/opaque endpoint confusion (solidity does not imply opacity)
258+
259+there exists a problem where an object can overlap into a polygon which is clipped by something
260+ behind the object but that will clip the object because clip windows are subtractive; how
261+ is this solved?
262+itユs still possible to get ambiguous clip flags, usually in very narrow (e.g., 1 pixel) windows
263+the renderer has a maximum range beyond which it shits bricks yet which it allows to be exceeded
264+itユs still possible, especially in high-res full-screen, for points to end up (slightly) off
265+ the screen (usually discarding these has no noticable effect on the scene)
266+whitespace results when two adjacent polygons are clipped to different vertical windows. this
267+ is not trivially solved with the current implementation, and may be acceptable (?)
268+
269+//build_base_polygon_index_list() should discard lower polygons for objects above the viewer and
270+// higher polygons for objects below the viewer because we certainly donユt sort objects
271+// correctly in these cases
272+//in strange cases, objects are sorted out of order. this seems to involve players in some way
273+// (i.e., parasitic objects).
274+*/
275+
276+/* ---------- constants */
277+
278+#define EXPLOSION_EFFECT_RANGE (WORLD_ONE/12)
279+
280+/* ---------- clip buffer */
281+// Not used for anything
282+#define CLIP_INDEX_BUFFER_SIZE 4096
283+
284+vector<uint16> RenderFlagList;
285+
286+// uint16 *render_flags;
287+
288+// LP additions: decomposition of the rendering code into various objects
289+
290+static RenderVisTreeClass RenderVisTree; // Visibility-tree object
291+static RenderSortPolyClass RenderSortPoly; // Polygon-sorting object
292+static RenderPlaceObjsClass RenderPlaceObjs; // Object-placement object
293+static RenderRasterizerClass Render_Classic; // Clipping and rasterization class
294+
295+static Rasterizer_SW_Class Rasterizer_SW; // Software rasterizer
296+#ifdef HAVE_OPENGL
297+static Rasterizer_OGL_Class Rasterizer_OGL; // OpenGL rasterizer
298+static Rasterizer_Shader_Class Rasterizer_Shader; // Shader rasterizer
299+static RenderRasterize_Shader Render_Shader; // Shader clipping and rasterization class
300+#endif
301+
302+void OGL_Rasterizer_Init() {
303+
304+#ifdef HAVE_OPENGL
305+ if (graphics_preferences->screen_mode.acceleration == _shader_acceleration)
306+ Render_Shader.setupGL();
307+#endif
308+}
309+
310+/* ---------- private prototypes */
311+
312+static void update_view_data(struct view_data *view);
313+static void update_render_effect(struct view_data *view);
314+static void shake_view_origin(struct view_data *view, world_distance delta);
315+
316+static void render_viewer_sprite_layer(view_data *view, RasterizerClass *RasPtr);
317+static void position_sprite_axis(short *x0, short *x1, short scale_width, short screen_width,
318+ short positioning_mode, _fixed position, bool flip, world_distance world_left, world_distance world_right);
319+
320+
321+#ifdef QUICKDRAW_DEBUG
322+static void debug_flagged_points(flagged_world_point2d *points, short count);
323+static void debug_flagged_points3d(flagged_world_point3d *points, short count);
324+static void debug_vector(world_vector2d *v);
325+static void debug_x_line(world_distance x);
326+#endif
327+
328+/* ---------- code */
329+
330+void allocate_render_memory(
331+ void)
332+{
333+ assert(NUMBER_OF_RENDER_FLAGS<=16);
334+ RenderFlagList.resize(RENDER_FLAGS_BUFFER_SIZE);
335+
336+ // LP addition: check out pointer-arithmetic hack
337+ assert(sizeof(void *) == sizeof(POINTER_DATA));
338+
339+ // LP change: do max allocation
340+ RenderVisTree.Resize(MAXIMUM_ENDPOINTS_PER_MAP,MAXIMUM_LINES_PER_MAP);
341+ RenderSortPoly.Resize(MAXIMUM_POLYGONS_PER_MAP);
342+
343+ // LP change: set up pointers
344+ RenderSortPoly.RVPtr = &RenderVisTree;
345+ RenderPlaceObjs.RVPtr = &RenderVisTree;
346+ RenderPlaceObjs.RSPtr = &RenderSortPoly;
347+#ifdef HAVE_OPENGL
348+ Render_Classic.RSPtr = Render_Shader.RSPtr = &RenderSortPoly;
349+#else
350+ Render_Classic.RSPtr = &RenderSortPoly;
351+#endif
352+}
353+
354+/* just in case anyone was wondering, standard_screen_width will usually be the same as
355+ screen_width. the renderer assumes that the given field_of_view matches the standard
356+ width provided (so if the actual width provided is larger, you'll be able to see more;
357+ if it's smaller you'll be able to see less). this allows the destination bitmap to not
358+ only grow and shrink while maintaining a constant aspect ratio, but to also change in
359+ geometry without effecting the image being projected onto it. if you don't understand
360+ this, pass standard_width==width */
361+void initialize_view_data(
362+ struct view_data *view)
363+{
364+ double two_pi= 8.0*atan(1.0);
365+ double half_cone= view->field_of_view*(two_pi/360.0)/2;
366+ /* half_cone needs to be extended for non oblique perspective projection (gluPerspective).
367+ this is required because the viewing angle is different for about the same field of view */
368+ if (graphics_preferences->screen_mode.acceleration == _shader_acceleration)
369+ half_cone= (view->field_of_view * 1.3)*(two_pi/360.0)/2;
370+
371+ double adjusted_half_cone= View_FOV_FixHorizontalNotVertical() ?
372+ half_cone :
373+ atan(view->screen_width*tan(half_cone)/view->standard_screen_width);
374+ double world_to_screen;
375+
376+ view->half_screen_width= view->screen_width/2;
377+ view->half_screen_height= view->screen_height/2;
378+
379+ /* if thereユs a round-off error in half_cone, we want to make the cone too big (so when we clip
380+ lines ヤto the edge of the screenユ theyユre actually off the screen, thus +1.0) */
381+ view->half_cone= (angle) (adjusted_half_cone*((double)NUMBER_OF_ANGLES)/two_pi+1.0);
382+
383+ // LP change: find the adjusted yaw for the landscapes;
384+ // this is the effective yaw value for the left edge.
385+ // A landscape rotation can also be added if desired.
386+ view->landscape_yaw = view->yaw - view->half_cone;
387+
388+ /* calculate world_to_screen; we could calculate this with standard_screen_width/2 and
389+ the old half_cone and get the same result */
390+ world_to_screen= view->half_screen_width/tan(adjusted_half_cone);
391+ view->world_to_screen_x= view->real_world_to_screen_x= (short) ((world_to_screen/view->horizontal_scale)+0.5);
392+ view->world_to_screen_y= view->real_world_to_screen_y= (short) ((world_to_screen/view->vertical_scale)+0.5);
393+
394+ /* calculate the vertical cone angle; again, overflow instead of underflow when rounding */
395+ view->half_vertical_cone= (angle) (NUMBER_OF_ANGLES*atan(((double)view->half_screen_height*view->vertical_scale)/world_to_screen)/two_pi+1.0);
396+
397+ /* calculate left edge vector */
398+ view->untransformed_left_edge.i= view->world_to_screen_x;
399+ view->untransformed_left_edge.j= - view->half_screen_width;
400+
401+ /* calculate right edge vector (negative, so it clips in the right direction) */
402+ view->untransformed_right_edge.i= - view->world_to_screen_x;
403+ view->untransformed_right_edge.j= - view->half_screen_width;
404+
405+ /* reset any active effects */
406+ // LP: this is now called in render_screen(), so we need to disable the initializing
407+}
408+
409+/* origin,origin_polygon_index,yaw,pitch,roll,etc. have probably changed since last call */
410+void render_view(
411+ struct view_data *view,
412+ struct bitmap_definition *destination)
413+{
414+ update_view_data(view);
415+
416+ /* clear the render flags */
417+ objlist_clear(render_flags, RENDER_FLAGS_BUFFER_SIZE);
418+
419+ ResetOverheadMap();
420+/*
421+#ifdef AUTOMAP_DEBUG
422+ memset(automap_lines, 0, (dynamic_world->line_count/8+((dynamic_world->line_count%8)?1:0)*sizeof(byte)));
423+ memset(automap_polygons, 0, (dynamic_world->polygon_count/8+((dynamic_world->polygon_count%8)?1:0)*sizeof(byte)));
424+#endif
425+*/
426+
427+ if(view->terminal_mode_active)
428+ {
429+ /* Render the computer interface. */
430+ render_computer_interface(view);
431+ }
432+ else
433+ {
434+ // LP: the render objects have a pointer to the current view in them,
435+ // so that one can get rid of redundant references to it in them.
436+
437+ // LP: now from the visibility-tree class
438+ /* build the render tree, regardless of map mode, so the automap updates while active */
439+ RenderVisTree.view = view;
440+ RenderVisTree.build_render_tree();
441+
442+ /* do something complicated and difficult to explain */
443+ if (!view->overhead_map_active || map_is_translucent())
444+ {
445+ // LP: now from the polygon-sorter class
446+ /* sort the render tree (so we have a depth-ordering of polygons) and accumulate
447+ clipping information for each polygon */
448+ RenderSortPoly.view = view;
449+ RenderSortPoly.sort_render_tree();
450+
451+ // LP: now from the object-placement class
452+ /* build the render object list by looking at the sorted render tree */
453+ RenderPlaceObjs.view = view;
454+ RenderPlaceObjs.build_render_object_list();
455+
456+ // LP addition: set the current rasterizer to whichever is appropriate here
457+ RasterizerClass *RasPtr;
458+#ifdef HAVE_OPENGL
459+ if (OGL_IsActive())
460+ RasPtr = (graphics_preferences->screen_mode.acceleration == _shader_acceleration) ? &Rasterizer_Shader : &Rasterizer_OGL;
461+ else
462+ {
463+#endif
464+ // The software renderer needs this but the OpenGL one doesn't...
465+ Rasterizer_SW.screen = destination;
466+ RasPtr = &Rasterizer_SW;
467+#ifdef HAVE_OPENGL
468+ }
469+#endif
470+
471+ // Set its view:
472+ RasPtr->SetView(*view);
473+
474+ // Start rendering main view
475+ RasPtr->Begin();
476+
477+ // LP: now from the clipping/rasterizer class
478+#ifdef HAVE_OPENGL
479+ RenderRasterizerClass *RenPtr = (graphics_preferences->screen_mode.acceleration == _shader_acceleration) ? &Render_Shader : &Render_Classic;
480+#else
481+ RenderRasterizerClass *RenPtr = &Render_Classic;
482+#endif
483+ /* render the object list, back to front, doing clipping on each surface before passing
484+ it to the texture-mapping code */
485+ RenPtr->view = view;
486+ RenPtr->RasPtr = RasPtr;
487+ RenPtr->render_tree();
488+
489+ // LP: won't put this into a separate class
490+ /* render the playerユs weapons, etc. */
491+ render_viewer_sprite_layer(view, RasPtr);
492+
493+ // Finish rendering main view
494+ RasPtr->End();
495+ }
496+
497+ if (view->overhead_map_active)
498+ {
499+ /* if the overhead map is active, render it */
500+ render_overhead_map(view);
501+ }
502+ }
503+}
504+
505+void start_render_effect(
506+ struct view_data *view,
507+ short effect)
508+{
509+ view->effect= effect;
510+ view->effect_phase= NONE;
511+}
512+
513+/* ---------- private code */
514+
515+static void update_view_data(
516+ struct view_data *view)
517+{
518+ angle theta;
519+
520+ // LP change: doing all the FOV changes here:
521+ View_AdjustFOV(view->field_of_view,view->target_field_of_view);
522+
523+ if (view->effect==NONE)
524+ {
525+ view->world_to_screen_x= view->real_world_to_screen_x;
526+ view->world_to_screen_y= view->real_world_to_screen_y;
527+ }
528+ else
529+ {
530+ update_render_effect(view);
531+ }
532+
533+ view->untransformed_left_edge.i= view->world_to_screen_x;
534+ view->untransformed_right_edge.i= - view->world_to_screen_x;
535+
536+ /* calculate world_to_screen_y*tan(pitch) */
537+ view->dtanpitch= (view->world_to_screen_y*sine_table[view->pitch])/cosine_table[view->pitch];
538+
539+ /* calculate left cone vector */
540+ theta= NORMALIZE_ANGLE(view->yaw-view->half_cone);
541+ view->left_edge.i= cosine_table[theta], view->left_edge.j= sine_table[theta];
542+
543+ /* calculate right cone vector */
544+ theta= NORMALIZE_ANGLE(view->yaw+view->half_cone);
545+ view->right_edge.i= cosine_table[theta], view->right_edge.j= sine_table[theta];
546+
547+ /* calculate top cone vector (negative to clip the right direction) */
548+ view->top_edge.i= - view->world_to_screen_y;
549+ view->top_edge.j= - (view->half_screen_height + view->dtanpitch); /* ==k */
550+
551+ /* calculate bottom cone vector */
552+ view->bottom_edge.i= view->world_to_screen_y;
553+ view->bottom_edge.j= - view->half_screen_height + view->dtanpitch; /* ==k */
554+
555+ /* if weユre sitting on one of the endpoints in our origin polygon, move us back slightly (ア1) into
556+ that polygon. when we split rays weユre assuming that weユll never pass through a given
557+ vertex in different directions (because if we do the tree becomes a graph) but when
558+ we start on a vertex this can happen. this is a destructive modification of the origin. */
559+ {
560+ short i;
561+ struct polygon_data *polygon= get_polygon_data(view->origin_polygon_index);
562+
563+ for (i= 0;i<polygon->vertex_count;++i)
564+ {
565+ struct world_point2d *vertex= &get_endpoint_data(polygon->endpoint_indexes[i])->vertex;
566+
567+ if (vertex->x==view->origin.x && vertex->y==view->origin.y)
568+ {
569+ world_point2d *ccw_vertex= &get_endpoint_data(polygon->endpoint_indexes[WRAP_LOW(i, polygon->vertex_count-1)])->vertex;
570+ world_point2d *cw_vertex= &get_endpoint_data(polygon->endpoint_indexes[WRAP_HIGH(i, polygon->vertex_count-1)])->vertex;
571+ world_vector2d inset_vector;
572+
573+ inset_vector.i= (ccw_vertex->x-vertex->x) + (cw_vertex->x-vertex->x);
574+ inset_vector.j= (ccw_vertex->y-vertex->y) + (cw_vertex->y-vertex->y);
575+ view->origin.x+= SGN(inset_vector.i);
576+ view->origin.y+= SGN(inset_vector.j);
577+
578+ break;
579+ }
580+ }
581+
582+ /* determine whether we are under or over the media boundary of our polygon; we will see all
583+ other media boundaries from this orientation (above or below) or fail to draw them. */
584+ if (polygon->media_index==NONE)
585+ {
586+ view->under_media_boundary= false;
587+ }
588+ else
589+ {
590+ struct media_data *media= get_media_data(polygon->media_index);
591+
592+ // LP change: idiot-proofing
593+ if (media)
594+ {
595+ view->under_media_boundary= UNDER_MEDIA(media, view->origin.z);
596+ view->under_media_index= polygon->media_index;
597+ } else {
598+ view->under_media_boundary= false;
599+ }
600+ }
601+ }
602+}
603+
604+static void update_render_effect(
605+ struct view_data *view)
606+{
607+ short effect= view->effect;
608+ short phase= view->effect_phase==NONE ? 0 : (view->effect_phase+view->ticks_elapsed);
609+ short period;
610+
611+ view->effect_phase= phase;
612+
613+ switch (effect)
614+ {
615+ // LP change: suppressed all the FOV changes
616+ case _render_effect_fold_in: case _render_effect_fold_out: period= TICKS_PER_SECOND/2; break;
617+ case _render_effect_explosion: period= TICKS_PER_SECOND; break;
618+ default:
619+ assert(false);
620+ break;
621+ }
622+
623+ if (phase>period)
624+ {
625+ view->effect= NONE;
626+ }
627+ else
628+ {
629+ switch (effect)
630+ {
631+ case _render_effect_explosion:
632+ shake_view_origin(view, EXPLOSION_EFFECT_RANGE - ((EXPLOSION_EFFECT_RANGE/2)*phase)/period);
633+ break;
634+
635+ case _render_effect_fold_in:
636+ phase= period-phase;
637+ case _render_effect_fold_out:
638+ /* calculate world_to_screen based on phase */
639+ view->world_to_screen_x= view->real_world_to_screen_x + (4*view->real_world_to_screen_x*phase)/period;
640+ view->world_to_screen_y= view->real_world_to_screen_y - (view->real_world_to_screen_y*phase)/(period+period/4);
641+ break;
642+ }
643+ }
644+}
645+
646+
647+/* ---------- transfer modes */
648+
649+/* given a transfer mode and phase, cause whatever changes it should cause to a rectangle_definition
650+ structure */
651+void instantiate_rectangle_transfer_mode(
652+ view_data *view,
653+ rectangle_definition *rectangle,
654+ short transfer_mode,
655+ _fixed transfer_phase)
656+{
657+ // For the 3D-model code
658+ rectangle->HorizScale = 1;
659+
660+ switch (transfer_mode)
661+ {
662+ case _xfer_invisibility:
663+ case _xfer_subtle_invisibility:
664+ if (view->shading_mode!=_shading_infravision)
665+ {
666+ rectangle->transfer_mode= _tinted_transfer;
667+ rectangle->shading_tables= get_global_shading_table();
668+ rectangle->transfer_data= (transfer_mode==_xfer_invisibility) ? 0x000f : 0x0018;
669+ break;
670+ }
671+ /* if we have infravision, fall through to _textured_transfer (i see you...) */
672+ case _xfer_normal:
673+ rectangle->transfer_mode= _textured_transfer;
674+ break;
675+
676+ case _xfer_static:
677+ case _xfer_50percent_static:
678+ rectangle->transfer_mode= _static_transfer;
679+ rectangle->transfer_data= (transfer_mode==_xfer_static) ? 0x0000 : 0x8000;
680+ break;
681+
682+ case _xfer_fade_out_static:
683+ rectangle->transfer_mode= _static_transfer;
684+ rectangle->transfer_data= transfer_phase;
685+ break;
686+
687+ case _xfer_pulsating_static:
688+ rectangle->transfer_mode= _static_transfer;
689+ rectangle->transfer_data= 0x8000+((0x6000*sine_table[FIXED_INTEGERAL_PART(transfer_phase*NUMBER_OF_ANGLES)])>>TRIG_SHIFT);
690+ break;
691+
692+ case _xfer_fold_in:
693+ transfer_phase= FIXED_ONE-transfer_phase; /* do everything backwards */
694+ case _xfer_fold_out:
695+ if (View_DoStaticEffect())
696+ {
697+ // Corrected the teleport shrinkage so that the sprite/object
698+ // shrinks to its object position and not to its sprite center
699+ short delta0= FIXED_INTEGERAL_PART(((rectangle->xc-rectangle->x0)-1)*transfer_phase);
700+ short delta1= FIXED_INTEGERAL_PART(((rectangle->x1-rectangle->xc)-1)*transfer_phase);
701+ // short delta= FIXED_INTEGERAL_PART((((rectangle->x1-rectangle->x0)>>1)-1)*transfer_phase);
702+
703+ rectangle->transfer_mode= _static_transfer;
704+ rectangle->transfer_data= (transfer_phase>>1);
705+ rectangle->x0+= delta0;
706+ rectangle->x1-= delta1;
707+ rectangle->HorizScale = 1 - float(transfer_phase)/float(FIXED_ONE);
708+ }
709+ else
710+ rectangle->transfer_mode= _textured_transfer;
711+ break;
712+
713+#if 0
714+ case _xfer_fade_out_to_black:
715+ rectangle->shading_tables= get_global_shading_table();
716+ if (transfer_phase<FIXED_ONE_HALF)
717+ {
718+ /* fade to black */
719+ rectangle->ambient_shade= (rectangle->ambient_shade*(transfer_phase-FIXED_ONE_HALF))>>(FIXED_FRACTIONAL_BITS-1);
720+ rectangle->transfer_mode= _textured_transfer;
721+ }
722+ else
723+ {
724+ /* vanish */
725+ rectangle->transfer_mode= _tinted_transfer;
726+ rectangle->transfer_data= 0x1f - ((0x1f*(FIXED_ONE_HALF-transfer_phase))>>(FIXED_FRACTIONAL_BITS-1));
727+ }
728+ break;
729+#endif
730+
731+ // LP change: made an unrecognized mode act like normal
732+ default:
733+ rectangle->transfer_mode= _textured_transfer;
734+ break;
735+ }
736+}
737+
738+/* given a transfer mode and phase, cause whatever changes it should cause to a polygon_definition
739+ structure (unfortunately we need to know whether this is a horizontal or vertical polygon) */
740+void instantiate_polygon_transfer_mode(
741+ struct view_data *view,
742+ struct polygon_definition *polygon,
743+ short transfer_mode,
744+ bool horizontal)
745+{
746+ world_distance x0, y0;
747+ world_distance vector_magnitude;
748+ short alternate_transfer_phase;
749+ short transfer_phase = view->tick_count;
750+
751+ polygon->transfer_mode= _textured_transfer;
752+ switch (transfer_mode)
753+ {
754+ case _xfer_fast_horizontal_slide:
755+ case _xfer_horizontal_slide:
756+ case _xfer_vertical_slide:
757+ case _xfer_fast_vertical_slide:
758+ case _xfer_wander:
759+ case _xfer_fast_wander:
760+ x0= y0= 0;
761+ switch (transfer_mode)
762+ {
763+ case _xfer_fast_horizontal_slide: transfer_phase<<= 1;
764+ case _xfer_horizontal_slide: x0= (transfer_phase<<2)&(WORLD_ONE-1); break;
765+
766+ case _xfer_fast_vertical_slide: transfer_phase<<= 1;
767+ case _xfer_vertical_slide: y0= (transfer_phase<<2)&(WORLD_ONE-1); break;
768+
769+ case _xfer_fast_wander: transfer_phase<<= 1;
770+ case _xfer_wander:
771+ alternate_transfer_phase= transfer_phase%(10*FULL_CIRCLE);
772+ transfer_phase= transfer_phase%(6*FULL_CIRCLE);
773+ x0= (cosine_table[NORMALIZE_ANGLE(alternate_transfer_phase)] +
774+ (cosine_table[NORMALIZE_ANGLE(2*alternate_transfer_phase)]>>1) +
775+ (cosine_table[NORMALIZE_ANGLE(5*alternate_transfer_phase)]>>1))>>(WORLD_FRACTIONAL_BITS-TRIG_SHIFT+2);
776+ y0= (sine_table[NORMALIZE_ANGLE(transfer_phase)] +
777+ (sine_table[NORMALIZE_ANGLE(2*transfer_phase)]>>1) +
778+ (sine_table[NORMALIZE_ANGLE(3*transfer_phase)]>>1))>>(WORLD_FRACTIONAL_BITS-TRIG_SHIFT+2);
779+ break;
780+ }
781+ if (horizontal)
782+ {
783+ polygon->origin.x+= x0;
784+ polygon->origin.y+= y0;
785+ }
786+ else
787+ {
788+ vector_magnitude= isqrt(polygon->vector.i*polygon->vector.i + polygon->vector.j*polygon->vector.j);
789+ polygon->origin.x+= (polygon->vector.i*x0)/vector_magnitude;
790+ polygon->origin.y+= (polygon->vector.j*x0)/vector_magnitude;
791+ polygon->origin.z-= y0;
792+ }
793+ break;
794+
795+ case _xfer_pulsate:
796+ case _xfer_wobble:
797+ case _xfer_fast_wobble:
798+ if (transfer_mode==_xfer_fast_wobble) transfer_phase*= 15;
799+ transfer_phase&= WORLD_ONE/16-1;
800+ transfer_phase= (transfer_phase>=WORLD_ONE/32) ? (WORLD_ONE/32+WORLD_ONE/64 - transfer_phase) : (transfer_phase - WORLD_ONE/64);
801+ if (horizontal)
802+ {
803+ polygon->origin.z+= transfer_phase;
804+ }
805+ else
806+ {
807+ if (transfer_mode==_xfer_pulsate) /* translate .origin perpendicular to .vector */
808+ {
809+ world_vector2d offset;
810+ world_distance vector_magnitude= isqrt(polygon->vector.i*polygon->vector.i + polygon->vector.j*polygon->vector.j);
811+
812+ offset.i= (polygon->vector.j*transfer_phase)/vector_magnitude;
813+ offset.j= (polygon->vector.i*transfer_phase)/vector_magnitude;
814+
815+ polygon->origin.x+= offset.i;
816+ polygon->origin.y+= offset.j;
817+ }
818+ else /* ==_xfer_wobble, wobble .vector */
819+ {
820+ polygon->vector.i+= transfer_phase;
821+ polygon->vector.j+= transfer_phase;
822+ }
823+ }
824+ break;
825+
826+ case _xfer_normal:
827+ break;
828+
829+ case _xfer_smear:
830+ polygon->transfer_mode= _solid_transfer;
831+ break;
832+
833+ case _xfer_static:
834+ polygon->transfer_mode= _static_transfer;
835+ polygon->transfer_data= 0x0000;
836+ break;
837+
838+ case _xfer_landscape:
839+ polygon->transfer_mode= _big_landscaped_transfer;
840+ break;
841+// case _xfer_big_landscape:
842+// polygon->transfer_mode= _big_landscaped_transfer;
843+// break;
844+
845+ default:
846+ // LP change: made an unrecognized mode act like normal
847+ break;
848+ }
849+}
850+
851+/* ---------- viewer sprite layer (i.e., weapons) */
852+
853+static void render_viewer_sprite_layer(view_data *view, RasterizerClass *RasPtr)
854+{
855+ rectangle_definition textured_rectangle;
856+ weapon_display_information display_data;
857+ shape_information_data *shape_information;
858+ short count;
859+
860+ // LP change: bug out if weapons-in-hand are not to be displayed
861+ if (!view->show_weapons_in_hand) return;
862+
863+ // Need to set this...
864+ RasPtr->SetForeground();
865+
866+ // No models here, and completely opaque
867+ textured_rectangle.ModelPtr = NULL;
868+ textured_rectangle.Opacity = 1;
869+
870+ /* get_weapon_display_information() returns true if there is a weapon to be drawn. it
871+ should initially be passed a count of zero. it returns the weaponユs texture and
872+ enough information to draw it correctly. */
873+ count= 0;
874+ while (get_weapon_display_information(&count, &display_data))
875+ {
876+ /* fetch relevant shape data */
877+ // LP: model-setup code is cribbed from
878+ // RenderPlaceObjsClass::build_render_object() in RenderPlaceObjs.cpp
879+#ifdef HAVE_OPENGL
880+ // Find which 3D model will take the place of this sprite, if any
881+ short ModelSequence;
882+ OGL_ModelData *ModelPtr =
883+ OGL_GetModelData(GET_COLLECTION(display_data.collection),display_data.shape_index,ModelSequence);
884+#endif
885+ shape_information= extended_get_shape_information(display_data.collection, display_data.low_level_shape_index);
886+ // Nonexistent frame: skip
887+ if (!shape_information) continue;
888+ // No need for a fake sprite rectangle, since models are foreground objects
889+
890+ // LP change: for the convenience of the OpenGL renderer
891+ textured_rectangle.ShapeDesc = BUILD_DESCRIPTOR(display_data.collection,0);
892+ textured_rectangle.LowLevelShape = display_data.low_level_shape_index;
893+#ifdef HAVE_OPENGL
894+ textured_rectangle.ModelPtr = ModelPtr;
895+ if (ModelPtr)
896+ {
897+ textured_rectangle.ModelSequence = ModelSequence;
898+ textured_rectangle.ModelFrame = display_data.Frame;
899+ textured_rectangle.NextModelFrame = display_data.NextFrame;
900+ textured_rectangle.MixFrac = display_data.Ticks > 0 ?
901+ float(display_data.Phase)/float(display_data.Ticks) : 0;
902+ const world_point3d Zero = {0, 0, 0};
903+ textured_rectangle.Position = Zero;
904+ textured_rectangle.Azimuth = 0;
905+ textured_rectangle.Scale = 1;
906+ textured_rectangle.LightDepth = 0;
907+ const GLfloat LightDirection[3] = {0, 1, 0}; // y is forward
908+ objlist_copy(textured_rectangle.LightDirection,LightDirection,3);
909+ RasPtr->SetForegroundView(display_data.flip_horizontal);
910+ }
911+#endif
912+
913+ if (shape_information->flags&_X_MIRRORED_BIT) display_data.flip_horizontal= !display_data.flip_horizontal;
914+ if (shape_information->flags&_Y_MIRRORED_BIT) display_data.flip_vertical= !display_data.flip_vertical;
915+
916+ /* calculate shape rectangle */
917+ position_sprite_axis(&textured_rectangle.x0, &textured_rectangle.x1, view->screen_height, view->screen_width, display_data.horizontal_positioning_mode,
918+ display_data.horizontal_position, display_data.flip_horizontal, shape_information->world_left, shape_information->world_right);
919+ position_sprite_axis(&textured_rectangle.y0, &textured_rectangle.y1, view->screen_height, view->screen_height, display_data.vertical_positioning_mode,
920+ display_data.vertical_position, display_data.flip_vertical, -shape_information->world_top, -shape_information->world_bottom);
921+
922+ /* set rectangle bitmap and shading table */
923+ extended_get_shape_bitmap_and_shading_table(display_data.collection, display_data.low_level_shape_index, &textured_rectangle.texture, &textured_rectangle.shading_tables, view->shading_mode);
924+ if (!textured_rectangle.texture) continue;
925+
926+ textured_rectangle.flags= 0;
927+
928+ /* initialize clipping window to full screen */
929+ textured_rectangle.clip_left= 0;
930+ textured_rectangle.clip_right= view->screen_width;
931+ textured_rectangle.clip_top= 0;
932+ textured_rectangle.clip_bottom= view->screen_height;
933+
934+ /* copy mirror flags */
935+ textured_rectangle.flip_horizontal= display_data.flip_horizontal;
936+ textured_rectangle.flip_vertical= display_data.flip_vertical;
937+
938+ /* lighting: depth of zero in the cameraユs polygon index */
939+ textured_rectangle.depth= 0;
940+ textured_rectangle.ambient_shade= get_light_intensity(get_polygon_data(view->origin_polygon_index)->floor_lightsource_index);
941+ textured_rectangle.ambient_shade= MAX(shape_information->minimum_light_intensity, textured_rectangle.ambient_shade);
942+ if (view->shading_mode==_shading_infravision) textured_rectangle.flags|= _SHADELESS_BIT;
943+
944+ // Calculate the object's horizontal position
945+ // for the convenience of doing teleport-in/teleport-out
946+ textured_rectangle.xc = (textured_rectangle.x0 + textured_rectangle.x1) >> 1;
947+
948+ /* make the weapon reflect the ownerユs transfer mode */
949+ instantiate_rectangle_transfer_mode(view, &textured_rectangle, display_data.transfer_mode, display_data.transfer_phase);
950+
951+ /* and draw it */
952+ // LP: added OpenGL support
953+ RasPtr->texture_rectangle(textured_rectangle);
954+ }
955+}
956+
957+static void position_sprite_axis(
958+ short *x0,
959+ short *x1,
960+ short scale_width,
961+ short screen_width,
962+ short positioning_mode,
963+ _fixed position,
964+ bool flip,
965+ world_distance world_left,
966+ world_distance world_right)
967+{
968+ short origin;
969+
970+ /* if this shape is mirrored, reverse the left/right world coordinates */
971+ if (flip)
972+ {
973+ world_distance swap= world_left;
974+ world_left= -world_right, world_right= -swap;
975+ }
976+
977+ switch (positioning_mode)
978+ {
979+ case _position_center:
980+ /* origin is the screen coordinate where the logical center of the shape will be drawn */
981+ origin= (screen_width*position)>>FIXED_FRACTIONAL_BITS;
982+ break;
983+ case _position_low:
984+ case _position_high:
985+ /* origin is in [0,WORLD_ONE] and represents the amount of the weapon visible off the side */
986+ origin= ((world_right-world_left)*position)>>FIXED_FRACTIONAL_BITS;
987+ break;
988+
989+ default:
990+ assert(false);
991+ break;
992+ }
993+
994+ switch (positioning_mode)
995+ {
996+ case _position_high:
997+ *x0= screen_width - ((origin*scale_width)>>WORLD_FRACTIONAL_BITS);
998+ *x1= *x0 + (((world_right-world_left)*scale_width)>>WORLD_FRACTIONAL_BITS);
999+ break;
1000+ case _position_low:
1001+ *x1= ((origin*scale_width)>>WORLD_FRACTIONAL_BITS);
1002+ *x0= *x1 - (((world_right-world_left)*scale_width)>>WORLD_FRACTIONAL_BITS);
1003+ break;
1004+
1005+ case _position_center:
1006+ *x0= origin + ((world_left*scale_width)>>WORLD_FRACTIONAL_BITS);
1007+ *x1= origin + ((world_right*scale_width)>>WORLD_FRACTIONAL_BITS);
1008+ break;
1009+
1010+ default:
1011+ assert(false);
1012+ break;
1013+ }
1014+}
1015+
1016+static void shake_view_origin(
1017+ struct view_data *view,
1018+ world_distance delta)
1019+{
1020+ world_point3d new_origin= view->origin;
1021+ short half_delta= delta>>1;
1022+
1023+ new_origin.x+= half_delta - ((delta*sine_table[NORMALIZE_ANGLE((view->tick_count&~3)*(7*FULL_CIRCLE))])>>TRIG_SHIFT);
1024+ new_origin.y+= half_delta - ((delta*sine_table[NORMALIZE_ANGLE(((view->tick_count+5*TICKS_PER_SECOND)&~3)*(7*FULL_CIRCLE))])>>TRIG_SHIFT);
1025+ new_origin.z+= half_delta - ((delta*sine_table[NORMALIZE_ANGLE(((view->tick_count+7*TICKS_PER_SECOND)&~3)*(7*FULL_CIRCLE))])>>TRIG_SHIFT);
1026+
1027+ /* only use the new origin if we didnユt cross a polygon boundary */
1028+ if (find_line_crossed_leaving_polygon(view->origin_polygon_index, (world_point2d *) &view->origin,
1029+ (world_point2d *) &new_origin)==NONE)
1030+ {
1031+ view->origin= new_origin;
1032+ }
1033+}
1034+
1035+// LP: begin no-compile
1036+#if 0
1037+
1038+/* ---------- mac-specific debugging calls */
1039+
1040+#ifdef QUICKDRAW_DEBUG
1041+
1042+#define SCALEF 5
1043+
1044+static void debug_flagged_points(
1045+ flagged_world_point2d *points,
1046+ short count)
1047+{
1048+ short i;
1049+
1050+ SetPort(screen_window);
1051+ PenSize(1, 1);
1052+ RGBForeColor(&rgb_black);
1053+ RGBBackColor(&rgb_white);
1054+ EraseRect(&screen_window->portRect);
1055+ SetOrigin(-640/2, -480/2);
1056+ MoveTo(-320, 0); LineTo(320, 0);
1057+ MoveTo(0, 240); LineTo(0, -240);
1058+ PenSize(2, 2);
1059+ MoveTo(points[count-1].y>>SCALEF, - (points[count-1].x>>SCALEF));
1060+ for (i=0;i<count;++i)
1061+ {
1062+ LineTo(points[i].y>>SCALEF, - (points[i].x>>SCALEF));
1063+ psprintf(ptemporary, "%d", i);
1064+ DrawString(temporary);
1065+ MoveTo(points[i].y>>SCALEF, - (points[i].x>>SCALEF));
1066+ }
1067+}
1068+
1069+static void debug_flagged_points3d(
1070+ flagged_world_point3d *points,
1071+ short count)
1072+{
1073+ short i;
1074+
1075+ SetPort(screen_window);
1076+ PenSize(1, 1);
1077+ RGBForeColor(&rgb_black);
1078+ RGBBackColor(&rgb_white);
1079+ EraseRect(&screen_window->portRect);
1080+ SetOrigin(-640/2, -480/2);
1081+ MoveTo(-320, 0); LineTo(320, 0);
1082+ MoveTo(0, 240); LineTo(0, -240);
1083+ PenSize(2, 2);
1084+ MoveTo(points[count-1].z>>SCALEF, - (points[count-1].x>>SCALEF));
1085+ for (i=0;i<count;++i)
1086+ {
1087+ LineTo(points[i].z>>SCALEF, - (points[i].x>>SCALEF));
1088+ psprintf(ptemporary, "%d", i);
1089+ DrawString(temporary);
1090+ MoveTo(points[i].z>>SCALEF, - (points[i].x>>SCALEF));
1091+ }
1092+}
1093+
1094+static void debug_vector(
1095+ world_vector2d *v)
1096+{
1097+ PenSize(1, 1);
1098+ MoveTo(0, 0);
1099+ LineTo(v->j, - v->i);
1100+ MoveTo(0, 0);
1101+ LineTo(- v->j, v->i);
1102+
1103+ while (!Button()); while (Button());
1104+}
1105+
1106+static void debug_x_line(
1107+ world_distance x)
1108+{
1109+ PenSize(1, 1);
1110+ MoveTo(-320, - x>>SCALEF);
1111+ LineTo(320, - x>>SCALEF);
1112+
1113+ while (!Button()); while (Button());
1114+}
1115+
1116+#endif /* QUICKDRAW DEBUG */
1117+
1118+// LP: end no-compile
1119+#endif
--- marathon/trunk/Source_Files/RenderMain/OGL_Model_Def.cpp (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/OGL_Model_Def.cpp (revision 530)
@@ -1,1032 +1,1032 @@
1-/*
2-
3- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4- and the "Aleph One" developers.
5-
6- This program is free software; you can redistribute it and/or modify
7- it under the terms of the GNU General Public License as published by
8- the Free Software Foundation; either version 3 of the License, or
9- (at your option) any later version.
10-
11- This program is distributed in the hope that it will be useful,
12- but WITHOUT ANY WARRANTY; without even the implied warranty of
13- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14- GNU General Public License for more details.
15-
16- This license is contained in the file "COPYING",
17- which is included with this source code; it is available online at
18- http://www.gnu.org/licenses/gpl.html
19-
20- OpenGL Model-Definition File
21- by Loren Petrich,
22- May 11, 2003
23-
24- This contains the definitions of all the OpenGL models and skins
25-*/
26-
27-#include "cseries.h"
28-#include "OGL_Model_Def.h"
29-#include "OGL_Setup.h"
30-
31-#ifdef HAVE_OPENGL
32-
33-#include <cmath>
34-
35-#include "Dim3_Loader.h"
36-#include "StudioLoader.h"
37-#include "WavefrontLoader.h"
38-#include "QD3D_Loader.h"
39-
40-
41-// Model-data stuff;
42-// defaults for whatever might need them
43-// Including skin stuff for convenience here
44-static OGL_ModelData DefaultModelData;
45-static OGL_SkinData DefaultSkinData;
46-
47-
48-// For mapping Marathon-physics sequences onto model sequences
49-struct SequenceMapEntry
50-{
51- int16 Sequence;
52- int16 ModelSequence;
53-};
54-
55-
56-// Store model-data stuff in a set of STL vectors
57-struct ModelDataEntry
58-{
59- // Which Marathon-engine sequence gets translated into this model,
60- // if static, or the neutral sequence, if dynamic
61- short Sequence;
62-
63- vector<SequenceMapEntry> SequenceMap;
64-
65- // Make a member for more convenient access
66- OGL_ModelData ModelData;
67-
68- ModelDataEntry(): Sequence(NONE) {}
69-};
70-
71-
72-// Separate model-data sequence lists for each collection ID,
73-// to speed up searching
74-static vector<ModelDataEntry> MdlList[NUMBER_OF_COLLECTIONS];
75-
76-// Will look up both the model index and its sequence
77-struct ModelHashEntry
78-{
79- int16 ModelIndex;
80- int16 ModelSeqTabIndex;
81-};
82-
83-// Model-data hash table for extra-fast searching:
84-static vector<ModelHashEntry> MdlHash[NUMBER_OF_COLLECTIONS];
85-
86-// Hash-table size and function
87-const int MdlHashSize = 1 << 8;
88-const int MdlHashMask = MdlHashSize - 1;
89-inline uint8 MdlHashFunc(short Sequence)
90-{
91- // E-Z
92- return (uint8)(Sequence & MdlHashMask);
93-}
94-
95-
96-// Deletes a collection's model-data sequences
97-static void MdlDelete(short Collection)
98-{
99- int c = Collection;
100- MdlList[c].clear();
101- MdlHash[c].clear();
102-}
103-
104-// Deletes all of them
105-static void MdlDeleteAll()
106-{
107- for (int c=0; c<NUMBER_OF_COLLECTIONS; c++) MdlDelete(c);
108-}
109-
110-
111-OGL_ModelData *OGL_GetModelData(short Collection, short Sequence, short& ModelSequence)
112-{
113- // Model is neutral unless specified otherwise
114- ModelSequence = NONE;
115-
116- // Initialize the hash table if necessary
117- if (MdlHash[Collection].empty())
118- {
119- MdlHash[Collection].resize(MdlHashSize);
120- objlist_set(&MdlHash[Collection][0],NONE,MdlHashSize);
121- }
122-
123- // Set up a *reference* to the appropriate hashtable entry;
124- // this makes setting this entry a bit more convenient
125- ModelHashEntry& HashVal = MdlHash[Collection][MdlHashFunc(Sequence)];
126-
127- // Check to see if the model-data entry is correct;
128- // if it is, then we're done.
129- if (HashVal.ModelIndex != NONE)
130- {
131- // First, check in the sequence-map table
132- vector<ModelDataEntry>::iterator MdlIter = MdlList[Collection].begin() + HashVal.ModelIndex;
133- size_t MSTIndex = static_cast<size_t>(HashVal.ModelSeqTabIndex); // Cast only safe b/c of following check
134- if (MSTIndex < MdlIter->SequenceMap.size())
135- {
136- vector<SequenceMapEntry>::iterator SMIter = MdlIter->SequenceMap.begin() + MSTIndex;
137- if (SMIter->Sequence == Sequence)
138- {
139- ModelSequence = SMIter->ModelSequence;
140- return MdlIter->ModelData.ModelPresent() ? &MdlIter->ModelData : NULL;
141- }
142- }
143-
144- // Now check the neutral sequence
145- if (MdlIter->Sequence == Sequence)
146- {
147- return MdlIter->ModelData.ModelPresent() ? &MdlIter->ModelData : NULL;
148- }
149- }
150-
151- // Fallback for the case of a hashtable miss;
152- // do a linear search and then update the hash entry appropriately.
153- vector<ModelDataEntry>& ML = MdlList[Collection];
154- int16 Indx = 0;
155- for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++, Indx++)
156- {
157- // First, search the sequence-map table
158- int16 SMIndx = 0;
159- vector<SequenceMapEntry>& SM = MdlIter->SequenceMap;
160- for (vector<SequenceMapEntry>::iterator SMIter = SM.begin(); SMIter < SM.end(); SMIter++, SMIndx++)
161- {
162- if (SMIter->Sequence == Sequence)
163- {
164- HashVal.ModelIndex = Indx;
165- HashVal.ModelSeqTabIndex = SMIndx;
166- ModelSequence = SMIter->ModelSequence;
167- return MdlIter->ModelData.ModelPresent() ? &MdlIter->ModelData : NULL;
168- }
169- }
170-
171- // Now check the neutral sequence
172- if (MdlIter->Sequence == Sequence)
173- {
174- HashVal.ModelIndex = Indx;
175- HashVal.ModelSeqTabIndex = NONE;
176- return MdlIter->ModelData.ModelPresent() ? &MdlIter->ModelData : NULL;
177- }
178- }
179-
180- // None found!
181- return NULL;
182-}
183-
184-int OGL_SkinData::GetMaxSize()
185-{
186- return Get_OGL_ConfigureData().ModelConfig.MaxSize;
187-}
188-
189-
190-// Any easy STL ways of doing this mapping of functions onto members of arrays?
191-
192-void OGL_SkinManager::Load()
193-{
194- for (vector<OGL_SkinData>::iterator SkinIter = SkinData.begin(); SkinIter < SkinData.end(); SkinIter++)
195- SkinIter->Load();
196-}
197-
198-
199-void OGL_SkinManager::Unload()
200-{
201- for (vector<OGL_SkinData>::iterator SkinIter = SkinData.begin(); SkinIter < SkinData.end(); SkinIter++)
202- SkinIter->Unload();
203-}
204-
205-
206-void OGL_SkinManager::Reset(bool Clear_OGL_Txtrs)
207-{
208- if (Clear_OGL_Txtrs)
209- {
210- for (int k=0; k<NUMBER_OF_OPENGL_BITMAP_SETS; k++)
211- for (int l=0; l<NUMBER_OF_TEXTURES; l++)
212- {
213- if (IDsInUse[k][l])
214- glDeleteTextures(1,&IDs[k][l]);
215- }
216- }
217-
218- // Mass clearing
219- objlist_clear(IDsInUse[0],NUMBER_OF_OPENGL_BITMAP_SETS*NUMBER_OF_TEXTURES);
220-}
221-
222-
223-OGL_SkinData *OGL_SkinManager::GetSkin(short CLUT)
224-{
225- for (unsigned k=0; k<SkinData.size(); k++)
226- {
227- OGL_SkinData& Skin = SkinData[k];
228- if (Skin.CLUT == CLUT || Skin.CLUT == ALL_CLUTS)
229- return &Skin;
230- }
231-
232- return NULL;
233-}
234-
235-
236-bool OGL_SkinManager::Use(short CLUT, short Which)
237-{
238- // References so they can be written into
239- GLuint& TxtrID = IDs[CLUT][Which];
240- bool& InUse = IDsInUse[CLUT][Which];
241- bool LoadSkin = false;
242- if (!InUse)
243- {
244- glGenTextures(1,&TxtrID);
245- InUse = true;
246- LoadSkin = true;
247- }
248- glBindTexture(GL_TEXTURE_2D,TxtrID);
249- return LoadSkin;
250-}
251-
252-
253-// Circle constants
254-const double TWO_PI = 8*atan(1.0);
255-const double Degree2Radian = TWO_PI/360; // A circle is 2*pi radians
256-
257-// Matrix manipulation (can't trust OpenGL to be active, so won't be using OpenGL matrix stuff)
258-
259-// Src -> Dest
260-static void MatCopy(const GLfloat SrcMat[3][3], GLfloat DestMat[3][3])
261-{
262- objlist_copy(DestMat[0],SrcMat[0],9);
263-}
264-
265-// Sets the arg to that matrix
266-static void MatIdentity(GLfloat Mat[3][3])
267-{
268- const GLfloat IMat[3][3] = {{1,0,0},{0,1,0},{0,0,1}};
269- MatCopy(IMat,Mat);
270-}
271-
272-// Src1, Src2 -> Dest (cannot be one of the sources)
273-static void MatMult(const GLfloat Mat1[3][3], const GLfloat Mat2[3][3], GLfloat DestMat[3][3])
274-{
275- for (int k=0; k<3; k++)
276- for (int l=0; l<3; l++)
277- {
278- GLfloat Sum = 0;
279- for (int m=0; m<3; m++)
280- Sum += Mat1[k][m]*Mat2[m][l];
281- DestMat[k][l] = Sum;
282- }
283-}
284-
285-// Alters the matrix in place
286-static void MatScalMult(GLfloat Mat[3][3], const GLfloat Scale)
287-{
288- for (int k=0; k<3; k++)
289- {
290- GLfloat *MatRow = Mat[k];
291- for (int l=0; l<3; l++)
292- MatRow[l] *= Scale;
293- }
294-}
295-
296-// Src -> Dest vector (cannot be the same location)
297-static void MatVecMult(const GLfloat Mat[3][3], const GLfloat *SrcVec, GLfloat *DestVec)
298-{
299- for (int k=0; k<3; k++)
300- {
301- const GLfloat *MatRow = Mat[k];
302- GLfloat Sum = 0;
303- for (int l=0; l<3; l++)
304- Sum += MatRow[l]*SrcVec[l];
305- DestVec[k] = Sum;
306- }
307-}
308-
309-
310-inline bool StringPresent(vector<char>& String)
311-{
312- return (String.size() > 1);
313-}
314-
315-
316-void OGL_ModelData::Load()
317-{
318- // Already loaded?
319- if (ModelPresent()) return;
320-
321- // Load the model
322- Model.Clear();
323-
324- if (ModelFile == FileSpecifier()) return;
325- if (!ModelFile.Exists()) return;
326-
327- bool Success = false;
328-
329- char *Type = &ModelType[0];
330- if (StringsEqual(Type,"wave",4))
331- {
332- // Alias|Wavefront, backward compatible version
333- Success = LoadModel_Wavefront(ModelFile, Model);
334- }
335- else if (StringsEqual(Type,"obj",3))
336- {
337- // Alias|Wavefront, but with coordinate system conversion.
338- Success = LoadModel_Wavefront_RightHand(ModelFile, Model);
339- }
340- else if (StringsEqual(Type,"3ds",3))
341- {
342- // 3D Studio Max, backward compatible version
343- Success = LoadModel_Studio(ModelFile, Model);
344- }
345- else if (StringsEqual(Type,"max",3))
346- {
347- // 3D Studio Max, but with coordinate system conversion.
348- Success = LoadModel_Studio_RightHand(ModelFile, Model);
349- }
350- else if (StringsEqual(Type,"dim3",4))
351- {
352- // Brian Barnes's "Dim3" model format (first pass: model geometry)
353- Success = LoadModel_Dim3(ModelFile, Model, LoadModelDim3_First);
354-
355- // Second and third passes: frames and sequences
356- try
357- {
358- if (ModelFile1 == FileSpecifier()) throw 0;
359- if (!ModelFile1.Exists()) throw 0;
360- if (!LoadModel_Dim3(ModelFile1, Model, LoadModelDim3_Rest)) throw 0;
361- }
362- catch(...)
363- {}
364- //
365- try
366- {
367- if (ModelFile2 == FileSpecifier()) throw 0;
368- if (!ModelFile2.Exists()) throw 0;
369- if (!LoadModel_Dim3(ModelFile2, Model, LoadModelDim3_Rest)) throw 0;
370- }
371- catch(...)
372- {}
373- }
374-#if HAVE_QUESA
375- else if (StringsEqual(Type,"qd3d") || StringsEqual(Type,"3dmf") || StringsEqual(Type,"quesa"))
376- {
377- // QuickDraw 3D / Quesa
378- Success = LoadModel_QD3D(ModelFile, Model);
379- }
380-#endif
381-
382- if (!Success)
383- {
384- Model.Clear();
385- return;
386- }
387-
388- // Calculate transformation matrix
389- GLfloat Angle, Cosine, Sine;
390- GLfloat RotMatrix[3][3], NewRotMatrix[3][3], IndivRotMatrix[3][3];
391- MatIdentity(RotMatrix);
392-
393- MatIdentity(IndivRotMatrix);
394- Angle = (float)Degree2Radian*XRot;
395- Cosine = (float)cos(Angle);
396- Sine = (float)sin(Angle);
397- IndivRotMatrix[1][1] = Cosine;
398- IndivRotMatrix[1][2] = - Sine;
399- IndivRotMatrix[2][1] = Sine;
400- IndivRotMatrix[2][2] = Cosine;
401- MatMult(IndivRotMatrix,RotMatrix,NewRotMatrix);
402- MatCopy(NewRotMatrix,RotMatrix);
403-
404- MatIdentity(IndivRotMatrix);
405- Angle = (float)Degree2Radian*YRot;
406- Cosine = (float)cos(Angle);
407- Sine = (float)sin(Angle);
408- IndivRotMatrix[2][2] = Cosine;
409- IndivRotMatrix[2][0] = - Sine;
410- IndivRotMatrix[0][2] = Sine;
411- IndivRotMatrix[0][0] = Cosine;
412- MatMult(IndivRotMatrix,RotMatrix,NewRotMatrix);
413- MatCopy(NewRotMatrix,RotMatrix);
414-
415- MatIdentity(IndivRotMatrix);
416- Angle = (float)Degree2Radian*ZRot;
417- Cosine = (float)cos(Angle);
418- Sine = (float)sin(Angle);
419- IndivRotMatrix[0][0] = Cosine;
420- IndivRotMatrix[0][1] = - Sine;
421- IndivRotMatrix[1][0] = Sine;
422- IndivRotMatrix[1][1] = Cosine;
423- MatMult(IndivRotMatrix,RotMatrix,NewRotMatrix);
424- MatCopy(NewRotMatrix,RotMatrix);
425-
426- MatScalMult(NewRotMatrix,Scale); // For the position vertices
427- if (Scale < 0) MatScalMult(RotMatrix,-1); // For the normals
428-
429- // Is model animated or static?
430- // Test by trying to find neutral positions (useful for working with the normals later on)
431- if (Model.FindPositions_Neutral(false))
432- {
433- // Copy over the vector and normal transformation matrices:
434- for (int k=0; k<3; k++)
435- for (int l=0; l<3; l++)
436- {
437- Model.TransformPos.M[k][l] = NewRotMatrix[k][l];
438- Model.TransformNorm.M[k][l] = RotMatrix[k][l];
439- }
440-
441- Model.TransformPos.M[0][3] = XShift;
442- Model.TransformPos.M[1][3] = YShift;
443- Model.TransformPos.M[2][3] = ZShift;
444-
445- // Find the transformed bounding box:
446- bool RestOfCorners = false;
447- GLfloat NewBoundingBox[2][3];
448- // The indices i1, i2, and i3 are for selecting which of the box's two principal corners
449- // to get coordinates from
450- for (int i1=0; i1<2; i1++)
451- {
452- GLfloat X = Model.BoundingBox[i1][0];
453- for (int i2=0; i2<2; i2++)
454- {
455- GLfloat Y = Model.BoundingBox[i2][0];
456- for (int i3=0; i3<2; i3++)
457- {
458- GLfloat Z = Model.BoundingBox[i3][0];
459-
460- GLfloat Corner[3];
461- for (int ic=0; ic<3; ic++)
462- {
463- GLfloat *Row = Model.TransformPos.M[ic];
464- Corner[ic] = Row[0]*X + Row[1]*Y + Row[2]*Z + Row[3];
465- }
466-
467- if (RestOfCorners)
468- {
469- // Find minimum and maximum for each coordinate
470- for (int ic=0; ic<3; ic++)
471- {
472- NewBoundingBox[0][ic] = min(NewBoundingBox[0][ic],Corner[ic]);
473- NewBoundingBox[1][ic] = max(NewBoundingBox[1][ic],Corner[ic]);
474- }
475- }
476- else
477- {
478- // Simply copy it in:
479- for (int ic=0; ic<3; ic++)
480- NewBoundingBox[0][ic] = NewBoundingBox[1][ic] = Corner[ic];
481- RestOfCorners = true;
482- }
483- }
484- }
485- }
486-
487- for (int ic=0; ic<2; ic++)
488- objlist_copy(Model.BoundingBox[ic],NewBoundingBox[ic],3);
489- }
490- else
491- {
492- // Static model
493- size_t NumVerts = Model.Positions.size()/3;
494-
495- for (size_t k=0; k<NumVerts; k++)
496- {
497- GLfloat *Pos = Model.PosBase() + 3*k;
498- GLfloat NewPos[3];
499- MatVecMult(NewRotMatrix,Pos,NewPos); // Has the scaling
500- Pos[0] = NewPos[0] + XShift;
501- Pos[1] = NewPos[1] + YShift;
502- Pos[2] = NewPos[2] + ZShift;
503- }
504-
505- size_t NumNorms = Model.Normals.size()/3;
506- for (size_t k=0; k<NumNorms; k++)
507- {
508- GLfloat *Norms = Model.NormBase() + 3*k;
509- GLfloat NewNorms[3];
510- MatVecMult(RotMatrix,Norms,NewNorms); // Not scaled
511- objlist_copy(Norms,NewNorms,3);
512- }
513-
514- // So as to be consistent with the new points
515- Model.FindBoundingBox();
516- }
517-
518- Model.AdjustNormals(NormalType,NormalSplit);
519- Model.CalculateTangents();
520-
521- // Don't forget the skins
522- OGL_SkinManager::Load();
523-}
524-
525-
526-void OGL_ModelData::Unload()
527-{
528- Model.Clear();
529- OGL_ResetForceSpriteDepth();
530-
531- // Don't forget the skins
532- OGL_SkinManager::Unload();
533-}
534-
535-int OGL_CountModels(short Collection)
536-{
537- return MdlList[Collection].size();
538-}
539-
540-extern void OGL_ProgressCallback(int);
541-
542-static bool ForcingSpriteDepth = false;
543-void OGL_ResetForceSpriteDepth() { ForcingSpriteDepth = false; }
544-bool OGL_ForceSpriteDepth() { return ForcingSpriteDepth; }
545-
546-// for managing the model and image loading and unloading
547-void OGL_LoadModels(short Collection)
548-{
549- vector<ModelDataEntry>& ML = MdlList[Collection];
550- for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++)
551- {
552- MdlIter->ModelData.Load();
553- if (MdlIter->ModelData.ForceSpriteDepth)
554- {
555- ForcingSpriteDepth = true;
556- }
557- OGL_ProgressCallback(1);
558- }
559-}
560-
561-void OGL_UnloadModels(short Collection)
562-{
563- vector<ModelDataEntry>& ML = MdlList[Collection];
564- for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++)
565- {
566- MdlIter->ModelData.Unload();
567- }
568-}
569-
570-
571-// Reset model skins; used in OGL_ResetTextures() in OGL_Textures.cpp
572-void OGL_ResetModelSkins(bool Clear_OGL_Txtrs)
573-{
574- for (int ic=0; ic<MAXIMUM_COLLECTIONS; ic++)
575- {
576- vector<ModelDataEntry>& ML = MdlList[ic];
577- for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++)
578- {
579- MdlIter->ModelData.Reset(Clear_OGL_Txtrs);
580- }
581- }
582-}
583-
584-class XML_SkinDataParser: public XML_ElementParser
585-{
586- short CLUT;
587-
588- OGL_SkinData Data;
589-public:
590- bool Start();
591- bool HandleAttribute(const char *Tag, const char *Value);
592- bool AttributesDone();
593-
594- vector<OGL_SkinData> *SkinDataPtr;
595-
596- XML_SkinDataParser(): XML_ElementParser("skin"), SkinDataPtr(NULL) {}
597-};
598-
599-bool XML_SkinDataParser::Start()
600-{
601- Data = DefaultSkinData;
602-
603- return true;
604-}
605-
606-bool XML_SkinDataParser::HandleAttribute(const char *Tag, const char *Value)
607-{
608- if (StringsEqual(Tag,"clut"))
609- {
610- return ReadBoundedInt16Value(Value,Data.CLUT,short(ALL_CLUTS),short(SILHOUETTE_BITMAP_SET));
611- }
612- else if (StringsEqual(Tag,"opac_type"))
613- {
614- return ReadBoundedInt16Value(Value,Data.OpacityType,0,OGL_NUMBER_OF_OPACITY_TYPES-1);
615- }
616- else if (StringsEqual(Tag,"opac_scale"))
617- {
618- return ReadFloatValue(Value,Data.OpacityScale);
619- }
620- else if (StringsEqual(Tag,"opac_shift"))
621- {
622- return ReadFloatValue(Value,Data.OpacityShift);
623- }
624- else if (StringsEqual(Tag,"normal_image"))
625- {
626- Data.NormalColors.SetNameWithPath(Value);
627- return true;
628- }
629- else if (StringsEqual(Tag,"offset_image"))
630- {
631- Data.OffsetMap.SetNameWithPath(Value);
632- return true;
633- }
634- else if (StringsEqual(Tag,"normal_mask"))
635- {
636- Data.NormalMask.SetNameWithPath(Value);
637- return true;
638- }
639- else if (StringsEqual(Tag,"glow_image"))
640- {
641- Data.GlowColors.SetNameWithPath(Value);
642- return true;
643- }
644- else if (StringsEqual(Tag,"glow_mask"))
645- {
646- Data.GlowMask.SetNameWithPath(Value);
647- return true;
648- }
649- else if (StringsEqual(Tag,"normal_blend"))
650- {
651- return ReadBoundedInt16Value(Value,Data.NormalBlend,0,OGL_NUMBER_OF_BLEND_TYPES-1);
652- }
653- else if (StringsEqual(Tag,"glow_blend"))
654- {
655- return ReadBoundedInt16Value(Value,Data.GlowBlend,0,OGL_NUMBER_OF_BLEND_TYPES-1);
656- }
657- else if (StringsEqual(Tag,"normal_bloom_scale"))
658- {
659- return ReadFloatValue(Value,Data.BloomScale);
660- }
661- else if (StringsEqual(Tag,"normal_bloom_shift"))
662- {
663- return ReadFloatValue(Value,Data.BloomShift);
664- }
665- else if (StringsEqual(Tag,"glow_bloom_scale"))
666- {
667- return ReadFloatValue(Value,Data.GlowBloomScale);
668- }
669- else if (StringsEqual(Tag,"glow_bloom_shift"))
670- {
671- return ReadFloatValue(Value,Data.GlowBloomShift);
672- }
673- else if (StringsEqual(Tag,"minimum_glow_intensity"))
674- {
675- return ReadFloatValue(Value,Data.MinGlowIntensity);
676- }
677- UnrecognizedTag();
678- return false;
679-}
680-
681-bool XML_SkinDataParser::AttributesDone()
682-{
683- // Check to see if a frame is already accounted for
684- assert(SkinDataPtr);
685- vector<OGL_SkinData>& SkinData = *SkinDataPtr;
686- for (vector<OGL_SkinData>::iterator SDIter = SkinData.begin(); SDIter < SkinData.end(); SDIter++)
687- {
688- if (SDIter->CLUT == Data.CLUT)
689- {
690- // Replace the data
691- *SDIter = Data;
692- return true;
693- }
694- }
695-
696- // If not, then add a new frame entry
697- SkinData.push_back(Data);
698-
699- return true;
700-}
701-
702-static XML_SkinDataParser SkinDataParser;
703-
704-
705-// For mapping Marathon-engine sequences onto model sequences
706-class XML_SequenceMapParser: public XML_ElementParser
707-{
708- bool SeqIsPresent, ModelSeqIsPresent;
709- SequenceMapEntry Data;
710-
711-public:
712- bool Start();
713- bool HandleAttribute(const char *Tag, const char *Value);
714- bool AttributesDone();
715-
716- vector<SequenceMapEntry> *SeqMapPtr;
717-
718- XML_SequenceMapParser(): XML_ElementParser("seq_map") {}
719-};
720-
721-bool XML_SequenceMapParser::Start()
722-{
723- Data.Sequence = Data.ModelSequence = NONE;
724- SeqIsPresent = ModelSeqIsPresent = false;
725- return true;
726-}
727-
728-bool XML_SequenceMapParser::HandleAttribute(const char *Tag, const char *Value)
729-{
730- if (StringsEqual(Tag,"seq"))
731- {
732- if (ReadBoundedInt16Value(Value,Data.Sequence,0,MAXIMUM_SHAPES_PER_COLLECTION-1))
733- {
734- SeqIsPresent = true;
735- return true;
736- }
737- else return false;
738- }
739- else if (StringsEqual(Tag,"model_seq"))
740- {
741- if (ReadBoundedInt16Value(Value,Data.ModelSequence,NONE,MAXIMUM_SHAPES_PER_COLLECTION-1))
742- {
743- ModelSeqIsPresent = true;
744- return true;
745- }
746- else return false;
747- }
748- UnrecognizedTag();
749- return false;
750-}
751-
752-bool XML_SequenceMapParser::AttributesDone()
753-{
754- // Verify...
755- if (!SeqIsPresent || !ModelSeqIsPresent)
756- {
757- AttribsMissing();
758- return false;
759- }
760-
761- // Add the entry
762- vector<SequenceMapEntry>& SeqMap = *SeqMapPtr;
763- SeqMap.push_back(Data);
764- return true;
765-}
766-
767-static XML_SequenceMapParser SequenceMapParser;
768-
769-
770-class XML_MdlClearParser: public XML_ElementParser
771-{
772- bool IsPresent;
773- short Collection;
774-
775-public:
776- bool Start();
777- bool HandleAttribute(const char *Tag, const char *Value);
778- bool AttributesDone();
779-
780- XML_MdlClearParser(): XML_ElementParser("model_clear") {}
781-};
782-
783-bool XML_MdlClearParser::Start()
784-{
785- IsPresent = false;
786- return true;
787-}
788-
789-bool XML_MdlClearParser::HandleAttribute(const char *Tag, const char *Value)
790-{
791- if (StringsEqual(Tag,"coll"))
792- {
793- if (ReadBoundedInt16Value(Value,Collection,0,NUMBER_OF_COLLECTIONS-1))
794- {
795- IsPresent = true;
796- return true;
797- }
798- else return false;
799- }
800- UnrecognizedTag();
801- return false;
802-}
803-
804-bool XML_MdlClearParser::AttributesDone()
805-{
806- if (IsPresent)
807- MdlDelete(Collection);
808- else
809- MdlDeleteAll();
810-
811- return true;
812-}
813-
814-static XML_MdlClearParser Mdl_ClearParser;
815-
816-
817-class XML_ModelDataParser: public XML_ElementParser
818-{
819- bool CollIsPresent;
820- short Collection, Sequence;
821- vector<SequenceMapEntry> SequenceMap;
822-
823- OGL_ModelData Data;
824-
825-public:
826- bool Start();
827- bool ReadSignValue(const char *String, int16& Value);
828- bool HandleAttribute(const char *Tag, const char *Value);
829- bool AttributesDone();
830- bool ResetValues();
831- bool End();
832-
833- XML_ModelDataParser(): XML_ElementParser("model") {}
834-};
835-
836-bool XML_ModelDataParser::Start()
837-{
838- Data = DefaultModelData;
839- CollIsPresent = false;
840- Sequence = NONE;
841- SequenceMap.clear();
842-
843- // For doing the model skins
844- SkinDataParser.SkinDataPtr = &Data.SkinData;
845-
846- // For doing the sequence mapping
847- SequenceMapParser.SeqMapPtr = &SequenceMap;
848-
849- return true;
850-}
851-
852-bool XML_ModelDataParser::ReadSignValue(const char *String, int16& Value)
853-{
854- if (StringsEqual(String, "+"))
855- {
856- Value = 1;
857- return true;
858- }
859- else if (StringsEqual(String, "-"))
860- {
861- Value = -1;
862- return true;
863- }
864- return ReadInt16Value(String, Value);
865-}
866-
867-bool XML_ModelDataParser::HandleAttribute(const char *Tag, const char *Value)
868-{
869- if (StringsEqual(Tag,"coll"))
870- {
871- if (ReadBoundedInt16Value(Value,Collection,0,NUMBER_OF_COLLECTIONS-1))
872- {
873- CollIsPresent = true;
874- return true;
875- }
876- else return false;
877- }
878- else if (StringsEqual(Tag,"seq"))
879- {
880- return (ReadBoundedInt16Value(Value,Sequence,0,MAXIMUM_SHAPES_PER_COLLECTION-1));
881- }
882- else if (StringsEqual(Tag,"scale"))
883- {
884- return ReadFloatValue(Value,Data.Scale);
885- }
886- else if (StringsEqual(Tag,"x_rot"))
887- {
888- return ReadFloatValue(Value,Data.XRot);
889- }
890- else if (StringsEqual(Tag,"y_rot"))
891- {
892- return ReadFloatValue(Value,Data.YRot);
893- }
894- else if (StringsEqual(Tag,"z_rot"))
895- {
896- return ReadFloatValue(Value,Data.ZRot);
897- }
898- else if (StringsEqual(Tag,"x_shift"))
899- {
900- return ReadFloatValue(Value,Data.XShift);
901- }
902- else if (StringsEqual(Tag,"y_shift"))
903- {
904- return ReadFloatValue(Value,Data.YShift);
905- }
906- else if (StringsEqual(Tag,"z_shift"))
907- {
908- return ReadFloatValue(Value,Data.ZShift);
909- }
910- else if (StringsEqual(Tag,"side"))
911- {
912- return ReadSignValue(Value,Data.Sidedness);
913- }
914- else if (StringsEqual(Tag,"norm_type"))
915- {
916- return ReadBoundedInt16Value(Value,Data.NormalType,0,Model3D::NUMBER_OF_NORMAL_TYPES-1);
917- }
918- else if (StringsEqual(Tag,"norm_split"))
919- {
920- return ReadFloatValue(Value,Data.NormalSplit);
921- }
922- else if (StringsEqual(Tag,"light_type"))
923- {
924- return ReadBoundedInt16Value(Value,Data.LightType,0,NUMBER_OF_MODEL_LIGHT_TYPES-1);
925- }
926- else if (StringsEqual(Tag,"depth_type"))
927- {
928- return ReadSignValue(Value,Data.DepthType);
929- }
930- else if (StringsEqual(Tag,"force_sprite_depth"))
931- {
932- return ReadBooleanValue(Value,Data.ForceSpriteDepth);
933- }
934- else if (StringsEqual(Tag,"file"))
935- {
936- Data.ModelFile.SetNameWithPath(Value);
937- return true;
938- }
939- else if (StringsEqual(Tag,"file1"))
940- {
941- Data.ModelFile1.SetNameWithPath(Value);
942- return true;
943- }
944- else if (StringsEqual(Tag,"file2"))
945- {
946- Data.ModelFile2.SetNameWithPath(Value);
947- return true;
948- }
949- else if (StringsEqual(Tag,"type"))
950- {
951- size_t nchars = strlen(Value)+1;
952- Data.ModelType.resize(nchars);
953- memcpy(&Data.ModelType[0],Value,nchars);
954- return true;
955- }
956- UnrecognizedTag();
957- return false;
958-}
959-
960-bool XML_ModelDataParser::AttributesDone()
961-{
962- // Verify...
963- if (!CollIsPresent)
964- {
965- AttribsMissing();
966- return false;
967- }
968- return true;
969-}
970-
971-bool XML_ModelDataParser::ResetValues()
972-{
973- MdlDeleteAll();
974- return true;
975-}
976-
977-bool XML_ModelDataParser::End()
978-{
979- // Do this at the end because the model data will then include the skin data
980-
981- // Check to see if a frame is already accounted for
982- vector<ModelDataEntry>& ML = MdlList[Collection];
983- for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++)
984- {
985- // Run a gauntlet of equality tests
986- if (MdlIter->Sequence != Sequence) continue;
987-
988- if (MdlIter->SequenceMap.size() != SequenceMap.size()) continue;
989-
990- // Ought to sort, then compare, for correct results
991- bool AllEqual = true;
992- for (size_t q=0; q<SequenceMap.size(); q++)
993- {
994- SequenceMapEntry& MS = MdlIter->SequenceMap[q];
995- SequenceMapEntry& S = SequenceMap[q];
996- if (MS.Sequence != S.Sequence || MS.ModelSequence != S.ModelSequence)
997- {
998- AllEqual = false;
999- break;
1000- }
1001- }
1002- if (!AllEqual) continue;
1003-
1004- // Replace the data; it passed the tests
1005- MdlIter->ModelData = Data;
1006- return true;
1007- }
1008-
1009- // If not, then add a new frame entry
1010- ModelDataEntry DataEntry;
1011- DataEntry.Sequence = Sequence;
1012- DataEntry.SequenceMap.swap(SequenceMap); // Quick transfer of contents in desired direction
1013- DataEntry.ModelData = Data;
1014- ML.push_back(DataEntry);
1015-
1016- return true;
1017-}
1018-
1019-static XML_ModelDataParser ModelDataParser;
1020-
1021-
1022-// XML-parser support:
1023-XML_ElementParser *ModelData_GetParser()
1024-{
1025- ModelDataParser.AddChild(&SkinDataParser);
1026- ModelDataParser.AddChild(&SequenceMapParser);
1027-
1028- return &ModelDataParser;
1029-}
1030-XML_ElementParser *Mdl_Clear_GetParser() {return &Mdl_ClearParser;}
1031-
1032-#endif
1+/*
2+
3+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4+ and the "Aleph One" developers.
5+
6+ This program is free software; you can redistribute it and/or modify
7+ it under the terms of the GNU General Public License as published by
8+ the Free Software Foundation; either version 3 of the License, or
9+ (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU General Public License for more details.
15+
16+ This license is contained in the file "COPYING",
17+ which is included with this source code; it is available online at
18+ http://www.gnu.org/licenses/gpl.html
19+
20+ OpenGL Model-Definition File
21+ by Loren Petrich,
22+ May 11, 2003
23+
24+ This contains the definitions of all the OpenGL models and skins
25+*/
26+
27+#include "cseries.h"
28+#include "OGL_Model_Def.h"
29+#include "OGL_Setup.h"
30+
31+#ifdef HAVE_OPENGL
32+
33+#include <cmath>
34+
35+#include "Dim3_Loader.h"
36+#include "StudioLoader.h"
37+#include "WavefrontLoader.h"
38+#include "QD3D_Loader.h"
39+
40+
41+// Model-data stuff;
42+// defaults for whatever might need them
43+// Including skin stuff for convenience here
44+static OGL_ModelData DefaultModelData;
45+static OGL_SkinData DefaultSkinData;
46+
47+
48+// For mapping Marathon-physics sequences onto model sequences
49+struct SequenceMapEntry
50+{
51+ int16 Sequence;
52+ int16 ModelSequence;
53+};
54+
55+
56+// Store model-data stuff in a set of STL vectors
57+struct ModelDataEntry
58+{
59+ // Which Marathon-engine sequence gets translated into this model,
60+ // if static, or the neutral sequence, if dynamic
61+ short Sequence;
62+
63+ vector<SequenceMapEntry> SequenceMap;
64+
65+ // Make a member for more convenient access
66+ OGL_ModelData ModelData;
67+
68+ ModelDataEntry(): Sequence(NONE) {}
69+};
70+
71+
72+// Separate model-data sequence lists for each collection ID,
73+// to speed up searching
74+static vector<ModelDataEntry> MdlList[NUMBER_OF_COLLECTIONS];
75+
76+// Will look up both the model index and its sequence
77+struct ModelHashEntry
78+{
79+ int16 ModelIndex;
80+ int16 ModelSeqTabIndex;
81+};
82+
83+// Model-data hash table for extra-fast searching:
84+static vector<ModelHashEntry> MdlHash[NUMBER_OF_COLLECTIONS];
85+
86+// Hash-table size and function
87+const int MdlHashSize = 1 << 8;
88+const int MdlHashMask = MdlHashSize - 1;
89+inline uint8 MdlHashFunc(short Sequence)
90+{
91+ // E-Z
92+ return (uint8)(Sequence & MdlHashMask);
93+}
94+
95+
96+// Deletes a collection's model-data sequences
97+static void MdlDelete(short Collection)
98+{
99+ int c = Collection;
100+ MdlList[c].clear();
101+ MdlHash[c].clear();
102+}
103+
104+// Deletes all of them
105+static void MdlDeleteAll()
106+{
107+ for (int c=0; c<NUMBER_OF_COLLECTIONS; c++) MdlDelete(c);
108+}
109+
110+
111+OGL_ModelData *OGL_GetModelData(short Collection, short Sequence, short& ModelSequence)
112+{
113+ // Model is neutral unless specified otherwise
114+ ModelSequence = NONE;
115+
116+ // Initialize the hash table if necessary
117+ if (MdlHash[Collection].empty())
118+ {
119+ MdlHash[Collection].resize(MdlHashSize);
120+ objlist_set(&MdlHash[Collection][0],NONE,MdlHashSize);
121+ }
122+
123+ // Set up a *reference* to the appropriate hashtable entry;
124+ // this makes setting this entry a bit more convenient
125+ ModelHashEntry& HashVal = MdlHash[Collection][MdlHashFunc(Sequence)];
126+
127+ // Check to see if the model-data entry is correct;
128+ // if it is, then we're done.
129+ if (HashVal.ModelIndex != NONE)
130+ {
131+ // First, check in the sequence-map table
132+ vector<ModelDataEntry>::iterator MdlIter = MdlList[Collection].begin() + HashVal.ModelIndex;
133+ size_t MSTIndex = static_cast<size_t>(HashVal.ModelSeqTabIndex); // Cast only safe b/c of following check
134+ if (MSTIndex < MdlIter->SequenceMap.size())
135+ {
136+ vector<SequenceMapEntry>::iterator SMIter = MdlIter->SequenceMap.begin() + MSTIndex;
137+ if (SMIter->Sequence == Sequence)
138+ {
139+ ModelSequence = SMIter->ModelSequence;
140+ return MdlIter->ModelData.ModelPresent() ? &MdlIter->ModelData : NULL;
141+ }
142+ }
143+
144+ // Now check the neutral sequence
145+ if (MdlIter->Sequence == Sequence)
146+ {
147+ return MdlIter->ModelData.ModelPresent() ? &MdlIter->ModelData : NULL;
148+ }
149+ }
150+
151+ // Fallback for the case of a hashtable miss;
152+ // do a linear search and then update the hash entry appropriately.
153+ vector<ModelDataEntry>& ML = MdlList[Collection];
154+ int16 Indx = 0;
155+ for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++, Indx++)
156+ {
157+ // First, search the sequence-map table
158+ int16 SMIndx = 0;
159+ vector<SequenceMapEntry>& SM = MdlIter->SequenceMap;
160+ for (vector<SequenceMapEntry>::iterator SMIter = SM.begin(); SMIter < SM.end(); SMIter++, SMIndx++)
161+ {
162+ if (SMIter->Sequence == Sequence)
163+ {
164+ HashVal.ModelIndex = Indx;
165+ HashVal.ModelSeqTabIndex = SMIndx;
166+ ModelSequence = SMIter->ModelSequence;
167+ return MdlIter->ModelData.ModelPresent() ? &MdlIter->ModelData : NULL;
168+ }
169+ }
170+
171+ // Now check the neutral sequence
172+ if (MdlIter->Sequence == Sequence)
173+ {
174+ HashVal.ModelIndex = Indx;
175+ HashVal.ModelSeqTabIndex = NONE;
176+ return MdlIter->ModelData.ModelPresent() ? &MdlIter->ModelData : NULL;
177+ }
178+ }
179+
180+ // None found!
181+ return NULL;
182+}
183+
184+int OGL_SkinData::GetMaxSize()
185+{
186+ return Get_OGL_ConfigureData().ModelConfig.MaxSize;
187+}
188+
189+
190+// Any easy STL ways of doing this mapping of functions onto members of arrays?
191+
192+void OGL_SkinManager::Load()
193+{
194+ for (vector<OGL_SkinData>::iterator SkinIter = SkinData.begin(); SkinIter < SkinData.end(); SkinIter++)
195+ SkinIter->Load();
196+}
197+
198+
199+void OGL_SkinManager::Unload()
200+{
201+ for (vector<OGL_SkinData>::iterator SkinIter = SkinData.begin(); SkinIter < SkinData.end(); SkinIter++)
202+ SkinIter->Unload();
203+}
204+
205+
206+void OGL_SkinManager::Reset(bool Clear_OGL_Txtrs)
207+{
208+ if (Clear_OGL_Txtrs)
209+ {
210+ for (int k=0; k<NUMBER_OF_OPENGL_BITMAP_SETS; k++)
211+ for (int l=0; l<NUMBER_OF_TEXTURES; l++)
212+ {
213+ if (IDsInUse[k][l])
214+ glDeleteTextures(1,&IDs[k][l]);
215+ }
216+ }
217+
218+ // Mass clearing
219+ objlist_clear(IDsInUse[0],NUMBER_OF_OPENGL_BITMAP_SETS*NUMBER_OF_TEXTURES);
220+}
221+
222+
223+OGL_SkinData *OGL_SkinManager::GetSkin(short CLUT)
224+{
225+ for (unsigned k=0; k<SkinData.size(); k++)
226+ {
227+ OGL_SkinData& Skin = SkinData[k];
228+ if (Skin.CLUT == CLUT || Skin.CLUT == ALL_CLUTS)
229+ return &Skin;
230+ }
231+
232+ return NULL;
233+}
234+
235+
236+bool OGL_SkinManager::Use(short CLUT, short Which)
237+{
238+ // References so they can be written into
239+ GLuint& TxtrID = IDs[CLUT][Which];
240+ bool& InUse = IDsInUse[CLUT][Which];
241+ bool LoadSkin = false;
242+ if (!InUse)
243+ {
244+ glGenTextures(1,&TxtrID);
245+ InUse = true;
246+ LoadSkin = true;
247+ }
248+ glBindTexture(GL_TEXTURE_2D,TxtrID);
249+ return LoadSkin;
250+}
251+
252+
253+// Circle constants
254+const double TWO_PI = 8*atan(1.0);
255+const double Degree2Radian = TWO_PI/360; // A circle is 2*pi radians
256+
257+// Matrix manipulation (can't trust OpenGL to be active, so won't be using OpenGL matrix stuff)
258+
259+// Src -> Dest
260+static void MatCopy(const GLfloat SrcMat[3][3], GLfloat DestMat[3][3])
261+{
262+ objlist_copy(DestMat[0],SrcMat[0],9);
263+}
264+
265+// Sets the arg to that matrix
266+static void MatIdentity(GLfloat Mat[3][3])
267+{
268+ const GLfloat IMat[3][3] = {{1,0,0},{0,1,0},{0,0,1}};
269+ MatCopy(IMat,Mat);
270+}
271+
272+// Src1, Src2 -> Dest (cannot be one of the sources)
273+static void MatMult(const GLfloat Mat1[3][3], const GLfloat Mat2[3][3], GLfloat DestMat[3][3])
274+{
275+ for (int k=0; k<3; k++)
276+ for (int l=0; l<3; l++)
277+ {
278+ GLfloat Sum = 0;
279+ for (int m=0; m<3; m++)
280+ Sum += Mat1[k][m]*Mat2[m][l];
281+ DestMat[k][l] = Sum;
282+ }
283+}
284+
285+// Alters the matrix in place
286+static void MatScalMult(GLfloat Mat[3][3], const GLfloat Scale)
287+{
288+ for (int k=0; k<3; k++)
289+ {
290+ GLfloat *MatRow = Mat[k];
291+ for (int l=0; l<3; l++)
292+ MatRow[l] *= Scale;
293+ }
294+}
295+
296+// Src -> Dest vector (cannot be the same location)
297+static void MatVecMult(const GLfloat Mat[3][3], const GLfloat *SrcVec, GLfloat *DestVec)
298+{
299+ for (int k=0; k<3; k++)
300+ {
301+ const GLfloat *MatRow = Mat[k];
302+ GLfloat Sum = 0;
303+ for (int l=0; l<3; l++)
304+ Sum += MatRow[l]*SrcVec[l];
305+ DestVec[k] = Sum;
306+ }
307+}
308+
309+
310+inline bool StringPresent(vector<char>& String)
311+{
312+ return (String.size() > 1);
313+}
314+
315+
316+void OGL_ModelData::Load()
317+{
318+ // Already loaded?
319+ if (ModelPresent()) return;
320+
321+ // Load the model
322+ Model.Clear();
323+
324+ if (ModelFile == FileSpecifier()) return;
325+ if (!ModelFile.Exists()) return;
326+
327+ bool Success = false;
328+
329+ char *Type = &ModelType[0];
330+ if (StringsEqual(Type,"wave",4))
331+ {
332+ // Alias|Wavefront, backward compatible version
333+ Success = LoadModel_Wavefront(ModelFile, Model);
334+ }
335+ else if (StringsEqual(Type,"obj",3))
336+ {
337+ // Alias|Wavefront, but with coordinate system conversion.
338+ Success = LoadModel_Wavefront_RightHand(ModelFile, Model);
339+ }
340+ else if (StringsEqual(Type,"3ds",3))
341+ {
342+ // 3D Studio Max, backward compatible version
343+ Success = LoadModel_Studio(ModelFile, Model);
344+ }
345+ else if (StringsEqual(Type,"max",3))
346+ {
347+ // 3D Studio Max, but with coordinate system conversion.
348+ Success = LoadModel_Studio_RightHand(ModelFile, Model);
349+ }
350+ else if (StringsEqual(Type,"dim3",4))
351+ {
352+ // Brian Barnes's "Dim3" model format (first pass: model geometry)
353+ Success = LoadModel_Dim3(ModelFile, Model, LoadModelDim3_First);
354+
355+ // Second and third passes: frames and sequences
356+ try
357+ {
358+ if (ModelFile1 == FileSpecifier()) throw 0;
359+ if (!ModelFile1.Exists()) throw 0;
360+ if (!LoadModel_Dim3(ModelFile1, Model, LoadModelDim3_Rest)) throw 0;
361+ }
362+ catch(...)
363+ {}
364+ //
365+ try
366+ {
367+ if (ModelFile2 == FileSpecifier()) throw 0;
368+ if (!ModelFile2.Exists()) throw 0;
369+ if (!LoadModel_Dim3(ModelFile2, Model, LoadModelDim3_Rest)) throw 0;
370+ }
371+ catch(...)
372+ {}
373+ }
374+#if HAVE_QUESA
375+ else if (StringsEqual(Type,"qd3d") || StringsEqual(Type,"3dmf") || StringsEqual(Type,"quesa"))
376+ {
377+ // QuickDraw 3D / Quesa
378+ Success = LoadModel_QD3D(ModelFile, Model);
379+ }
380+#endif
381+
382+ if (!Success)
383+ {
384+ Model.Clear();
385+ return;
386+ }
387+
388+ // Calculate transformation matrix
389+ GLfloat Angle, Cosine, Sine;
390+ GLfloat RotMatrix[3][3], NewRotMatrix[3][3], IndivRotMatrix[3][3];
391+ MatIdentity(RotMatrix);
392+
393+ MatIdentity(IndivRotMatrix);
394+ Angle = (float)Degree2Radian*XRot;
395+ Cosine = (float)cos(Angle);
396+ Sine = (float)sin(Angle);
397+ IndivRotMatrix[1][1] = Cosine;
398+ IndivRotMatrix[1][2] = - Sine;
399+ IndivRotMatrix[2][1] = Sine;
400+ IndivRotMatrix[2][2] = Cosine;
401+ MatMult(IndivRotMatrix,RotMatrix,NewRotMatrix);
402+ MatCopy(NewRotMatrix,RotMatrix);
403+
404+ MatIdentity(IndivRotMatrix);
405+ Angle = (float)Degree2Radian*YRot;
406+ Cosine = (float)cos(Angle);
407+ Sine = (float)sin(Angle);
408+ IndivRotMatrix[2][2] = Cosine;
409+ IndivRotMatrix[2][0] = - Sine;
410+ IndivRotMatrix[0][2] = Sine;
411+ IndivRotMatrix[0][0] = Cosine;
412+ MatMult(IndivRotMatrix,RotMatrix,NewRotMatrix);
413+ MatCopy(NewRotMatrix,RotMatrix);
414+
415+ MatIdentity(IndivRotMatrix);
416+ Angle = (float)Degree2Radian*ZRot;
417+ Cosine = (float)cos(Angle);
418+ Sine = (float)sin(Angle);
419+ IndivRotMatrix[0][0] = Cosine;
420+ IndivRotMatrix[0][1] = - Sine;
421+ IndivRotMatrix[1][0] = Sine;
422+ IndivRotMatrix[1][1] = Cosine;
423+ MatMult(IndivRotMatrix,RotMatrix,NewRotMatrix);
424+ MatCopy(NewRotMatrix,RotMatrix);
425+
426+ MatScalMult(NewRotMatrix,Scale); // For the position vertices
427+ if (Scale < 0) MatScalMult(RotMatrix,-1); // For the normals
428+
429+ // Is model animated or static?
430+ // Test by trying to find neutral positions (useful for working with the normals later on)
431+ if (Model.FindPositions_Neutral(false))
432+ {
433+ // Copy over the vector and normal transformation matrices:
434+ for (int k=0; k<3; k++)
435+ for (int l=0; l<3; l++)
436+ {
437+ Model.TransformPos.M[k][l] = NewRotMatrix[k][l];
438+ Model.TransformNorm.M[k][l] = RotMatrix[k][l];
439+ }
440+
441+ Model.TransformPos.M[0][3] = XShift;
442+ Model.TransformPos.M[1][3] = YShift;
443+ Model.TransformPos.M[2][3] = ZShift;
444+
445+ // Find the transformed bounding box:
446+ bool RestOfCorners = false;
447+ GLfloat NewBoundingBox[2][3];
448+ // The indices i1, i2, and i3 are for selecting which of the box's two principal corners
449+ // to get coordinates from
450+ for (int i1=0; i1<2; i1++)
451+ {
452+ GLfloat X = Model.BoundingBox[i1][0];
453+ for (int i2=0; i2<2; i2++)
454+ {
455+ GLfloat Y = Model.BoundingBox[i2][0];
456+ for (int i3=0; i3<2; i3++)
457+ {
458+ GLfloat Z = Model.BoundingBox[i3][0];
459+
460+ GLfloat Corner[3];
461+ for (int ic=0; ic<3; ic++)
462+ {
463+ GLfloat *Row = Model.TransformPos.M[ic];
464+ Corner[ic] = Row[0]*X + Row[1]*Y + Row[2]*Z + Row[3];
465+ }
466+
467+ if (RestOfCorners)
468+ {
469+ // Find minimum and maximum for each coordinate
470+ for (int ic=0; ic<3; ic++)
471+ {
472+ NewBoundingBox[0][ic] = min(NewBoundingBox[0][ic],Corner[ic]);
473+ NewBoundingBox[1][ic] = max(NewBoundingBox[1][ic],Corner[ic]);
474+ }
475+ }
476+ else
477+ {
478+ // Simply copy it in:
479+ for (int ic=0; ic<3; ic++)
480+ NewBoundingBox[0][ic] = NewBoundingBox[1][ic] = Corner[ic];
481+ RestOfCorners = true;
482+ }
483+ }
484+ }
485+ }
486+
487+ for (int ic=0; ic<2; ic++)
488+ objlist_copy(Model.BoundingBox[ic],NewBoundingBox[ic],3);
489+ }
490+ else
491+ {
492+ // Static model
493+ size_t NumVerts = Model.Positions.size()/3;
494+
495+ for (size_t k=0; k<NumVerts; k++)
496+ {
497+ GLfloat *Pos = Model.PosBase() + 3*k;
498+ GLfloat NewPos[3];
499+ MatVecMult(NewRotMatrix,Pos,NewPos); // Has the scaling
500+ Pos[0] = NewPos[0] + XShift;
501+ Pos[1] = NewPos[1] + YShift;
502+ Pos[2] = NewPos[2] + ZShift;
503+ }
504+
505+ size_t NumNorms = Model.Normals.size()/3;
506+ for (size_t k=0; k<NumNorms; k++)
507+ {
508+ GLfloat *Norms = Model.NormBase() + 3*k;
509+ GLfloat NewNorms[3];
510+ MatVecMult(RotMatrix,Norms,NewNorms); // Not scaled
511+ objlist_copy(Norms,NewNorms,3);
512+ }
513+
514+ // So as to be consistent with the new points
515+ Model.FindBoundingBox();
516+ }
517+
518+ Model.AdjustNormals(NormalType,NormalSplit);
519+ Model.CalculateTangents();
520+
521+ // Don't forget the skins
522+ OGL_SkinManager::Load();
523+}
524+
525+
526+void OGL_ModelData::Unload()
527+{
528+ Model.Clear();
529+ OGL_ResetForceSpriteDepth();
530+
531+ // Don't forget the skins
532+ OGL_SkinManager::Unload();
533+}
534+
535+int OGL_CountModels(short Collection)
536+{
537+ return MdlList[Collection].size();
538+}
539+
540+extern void OGL_ProgressCallback(int);
541+
542+static bool ForcingSpriteDepth = false;
543+void OGL_ResetForceSpriteDepth() { ForcingSpriteDepth = false; }
544+bool OGL_ForceSpriteDepth() { return ForcingSpriteDepth; }
545+
546+// for managing the model and image loading and unloading
547+void OGL_LoadModels(short Collection)
548+{
549+ vector<ModelDataEntry>& ML = MdlList[Collection];
550+ for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++)
551+ {
552+ MdlIter->ModelData.Load();
553+ if (MdlIter->ModelData.ForceSpriteDepth)
554+ {
555+ ForcingSpriteDepth = true;
556+ }
557+ OGL_ProgressCallback(1);
558+ }
559+}
560+
561+void OGL_UnloadModels(short Collection)
562+{
563+ vector<ModelDataEntry>& ML = MdlList[Collection];
564+ for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++)
565+ {
566+ MdlIter->ModelData.Unload();
567+ }
568+}
569+
570+
571+// Reset model skins; used in OGL_ResetTextures() in OGL_Textures.cpp
572+void OGL_ResetModelSkins(bool Clear_OGL_Txtrs)
573+{
574+ for (int ic=0; ic<MAXIMUM_COLLECTIONS; ic++)
575+ {
576+ vector<ModelDataEntry>& ML = MdlList[ic];
577+ for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++)
578+ {
579+ MdlIter->ModelData.Reset(Clear_OGL_Txtrs);
580+ }
581+ }
582+}
583+
584+class XML_SkinDataParser: public XML_ElementParser
585+{
586+ short CLUT;
587+
588+ OGL_SkinData Data;
589+public:
590+ bool Start();
591+ bool HandleAttribute(const char *Tag, const char *Value);
592+ bool AttributesDone();
593+
594+ vector<OGL_SkinData> *SkinDataPtr;
595+
596+ XML_SkinDataParser(): XML_ElementParser("skin"), SkinDataPtr(NULL) {}
597+};
598+
599+bool XML_SkinDataParser::Start()
600+{
601+ Data = DefaultSkinData;
602+
603+ return true;
604+}
605+
606+bool XML_SkinDataParser::HandleAttribute(const char *Tag, const char *Value)
607+{
608+ if (StringsEqual(Tag,"clut"))
609+ {
610+ return ReadBoundedInt16Value(Value,Data.CLUT,short(ALL_CLUTS),short(SILHOUETTE_BITMAP_SET));
611+ }
612+ else if (StringsEqual(Tag,"opac_type"))
613+ {
614+ return ReadBoundedInt16Value(Value,Data.OpacityType,0,OGL_NUMBER_OF_OPACITY_TYPES-1);
615+ }
616+ else if (StringsEqual(Tag,"opac_scale"))
617+ {
618+ return ReadFloatValue(Value,Data.OpacityScale);
619+ }
620+ else if (StringsEqual(Tag,"opac_shift"))
621+ {
622+ return ReadFloatValue(Value,Data.OpacityShift);
623+ }
624+ else if (StringsEqual(Tag,"normal_image"))
625+ {
626+ Data.NormalColors.SetNameWithPath(Value);
627+ return true;
628+ }
629+ else if (StringsEqual(Tag,"offset_image"))
630+ {
631+ Data.OffsetMap.SetNameWithPath(Value);
632+ return true;
633+ }
634+ else if (StringsEqual(Tag,"normal_mask"))
635+ {
636+ Data.NormalMask.SetNameWithPath(Value);
637+ return true;
638+ }
639+ else if (StringsEqual(Tag,"glow_image"))
640+ {
641+ Data.GlowColors.SetNameWithPath(Value);
642+ return true;
643+ }
644+ else if (StringsEqual(Tag,"glow_mask"))
645+ {
646+ Data.GlowMask.SetNameWithPath(Value);
647+ return true;
648+ }
649+ else if (StringsEqual(Tag,"normal_blend"))
650+ {
651+ return ReadBoundedInt16Value(Value,Data.NormalBlend,0,OGL_NUMBER_OF_BLEND_TYPES-1);
652+ }
653+ else if (StringsEqual(Tag,"glow_blend"))
654+ {
655+ return ReadBoundedInt16Value(Value,Data.GlowBlend,0,OGL_NUMBER_OF_BLEND_TYPES-1);
656+ }
657+ else if (StringsEqual(Tag,"normal_bloom_scale"))
658+ {
659+ return ReadFloatValue(Value,Data.BloomScale);
660+ }
661+ else if (StringsEqual(Tag,"normal_bloom_shift"))
662+ {
663+ return ReadFloatValue(Value,Data.BloomShift);
664+ }
665+ else if (StringsEqual(Tag,"glow_bloom_scale"))
666+ {
667+ return ReadFloatValue(Value,Data.GlowBloomScale);
668+ }
669+ else if (StringsEqual(Tag,"glow_bloom_shift"))
670+ {
671+ return ReadFloatValue(Value,Data.GlowBloomShift);
672+ }
673+ else if (StringsEqual(Tag,"minimum_glow_intensity"))
674+ {
675+ return ReadFloatValue(Value,Data.MinGlowIntensity);
676+ }
677+ UnrecognizedTag();
678+ return false;
679+}
680+
681+bool XML_SkinDataParser::AttributesDone()
682+{
683+ // Check to see if a frame is already accounted for
684+ assert(SkinDataPtr);
685+ vector<OGL_SkinData>& SkinData = *SkinDataPtr;
686+ for (vector<OGL_SkinData>::iterator SDIter = SkinData.begin(); SDIter < SkinData.end(); SDIter++)
687+ {
688+ if (SDIter->CLUT == Data.CLUT)
689+ {
690+ // Replace the data
691+ *SDIter = Data;
692+ return true;
693+ }
694+ }
695+
696+ // If not, then add a new frame entry
697+ SkinData.push_back(Data);
698+
699+ return true;
700+}
701+
702+static XML_SkinDataParser SkinDataParser;
703+
704+
705+// For mapping Marathon-engine sequences onto model sequences
706+class XML_SequenceMapParser: public XML_ElementParser
707+{
708+ bool SeqIsPresent, ModelSeqIsPresent;
709+ SequenceMapEntry Data;
710+
711+public:
712+ bool Start();
713+ bool HandleAttribute(const char *Tag, const char *Value);
714+ bool AttributesDone();
715+
716+ vector<SequenceMapEntry> *SeqMapPtr;
717+
718+ XML_SequenceMapParser(): XML_ElementParser("seq_map") {}
719+};
720+
721+bool XML_SequenceMapParser::Start()
722+{
723+ Data.Sequence = Data.ModelSequence = NONE;
724+ SeqIsPresent = ModelSeqIsPresent = false;
725+ return true;
726+}
727+
728+bool XML_SequenceMapParser::HandleAttribute(const char *Tag, const char *Value)
729+{
730+ if (StringsEqual(Tag,"seq"))
731+ {
732+ if (ReadBoundedInt16Value(Value,Data.Sequence,0,MAXIMUM_SHAPES_PER_COLLECTION-1))
733+ {
734+ SeqIsPresent = true;
735+ return true;
736+ }
737+ else return false;
738+ }
739+ else if (StringsEqual(Tag,"model_seq"))
740+ {
741+ if (ReadBoundedInt16Value(Value,Data.ModelSequence,NONE,MAXIMUM_SHAPES_PER_COLLECTION-1))
742+ {
743+ ModelSeqIsPresent = true;
744+ return true;
745+ }
746+ else return false;
747+ }
748+ UnrecognizedTag();
749+ return false;
750+}
751+
752+bool XML_SequenceMapParser::AttributesDone()
753+{
754+ // Verify...
755+ if (!SeqIsPresent || !ModelSeqIsPresent)
756+ {
757+ AttribsMissing();
758+ return false;
759+ }
760+
761+ // Add the entry
762+ vector<SequenceMapEntry>& SeqMap = *SeqMapPtr;
763+ SeqMap.push_back(Data);
764+ return true;
765+}
766+
767+static XML_SequenceMapParser SequenceMapParser;
768+
769+
770+class XML_MdlClearParser: public XML_ElementParser
771+{
772+ bool IsPresent;
773+ short Collection;
774+
775+public:
776+ bool Start();
777+ bool HandleAttribute(const char *Tag, const char *Value);
778+ bool AttributesDone();
779+
780+ XML_MdlClearParser(): XML_ElementParser("model_clear") {}
781+};
782+
783+bool XML_MdlClearParser::Start()
784+{
785+ IsPresent = false;
786+ return true;
787+}
788+
789+bool XML_MdlClearParser::HandleAttribute(const char *Tag, const char *Value)
790+{
791+ if (StringsEqual(Tag,"coll"))
792+ {
793+ if (ReadBoundedInt16Value(Value,Collection,0,NUMBER_OF_COLLECTIONS-1))
794+ {
795+ IsPresent = true;
796+ return true;
797+ }
798+ else return false;
799+ }
800+ UnrecognizedTag();
801+ return false;
802+}
803+
804+bool XML_MdlClearParser::AttributesDone()
805+{
806+ if (IsPresent)
807+ MdlDelete(Collection);
808+ else
809+ MdlDeleteAll();
810+
811+ return true;
812+}
813+
814+static XML_MdlClearParser Mdl_ClearParser;
815+
816+
817+class XML_ModelDataParser: public XML_ElementParser
818+{
819+ bool CollIsPresent;
820+ short Collection, Sequence;
821+ vector<SequenceMapEntry> SequenceMap;
822+
823+ OGL_ModelData Data;
824+
825+public:
826+ bool Start();
827+ bool ReadSignValue(const char *String, int16& Value);
828+ bool HandleAttribute(const char *Tag, const char *Value);
829+ bool AttributesDone();
830+ bool ResetValues();
831+ bool End();
832+
833+ XML_ModelDataParser(): XML_ElementParser("model") {}
834+};
835+
836+bool XML_ModelDataParser::Start()
837+{
838+ Data = DefaultModelData;
839+ CollIsPresent = false;
840+ Sequence = NONE;
841+ SequenceMap.clear();
842+
843+ // For doing the model skins
844+ SkinDataParser.SkinDataPtr = &Data.SkinData;
845+
846+ // For doing the sequence mapping
847+ SequenceMapParser.SeqMapPtr = &SequenceMap;
848+
849+ return true;
850+}
851+
852+bool XML_ModelDataParser::ReadSignValue(const char *String, int16& Value)
853+{
854+ if (StringsEqual(String, "+"))
855+ {
856+ Value = 1;
857+ return true;
858+ }
859+ else if (StringsEqual(String, "-"))
860+ {
861+ Value = -1;
862+ return true;
863+ }
864+ return ReadInt16Value(String, Value);
865+}
866+
867+bool XML_ModelDataParser::HandleAttribute(const char *Tag, const char *Value)
868+{
869+ if (StringsEqual(Tag,"coll"))
870+ {
871+ if (ReadBoundedInt16Value(Value,Collection,0,NUMBER_OF_COLLECTIONS-1))
872+ {
873+ CollIsPresent = true;
874+ return true;
875+ }
876+ else return false;
877+ }
878+ else if (StringsEqual(Tag,"seq"))
879+ {
880+ return (ReadBoundedInt16Value(Value,Sequence,0,MAXIMUM_SHAPES_PER_COLLECTION-1));
881+ }
882+ else if (StringsEqual(Tag,"scale"))
883+ {
884+ return ReadFloatValue(Value,Data.Scale);
885+ }
886+ else if (StringsEqual(Tag,"x_rot"))
887+ {
888+ return ReadFloatValue(Value,Data.XRot);
889+ }
890+ else if (StringsEqual(Tag,"y_rot"))
891+ {
892+ return ReadFloatValue(Value,Data.YRot);
893+ }
894+ else if (StringsEqual(Tag,"z_rot"))
895+ {
896+ return ReadFloatValue(Value,Data.ZRot);
897+ }
898+ else if (StringsEqual(Tag,"x_shift"))
899+ {
900+ return ReadFloatValue(Value,Data.XShift);
901+ }
902+ else if (StringsEqual(Tag,"y_shift"))
903+ {
904+ return ReadFloatValue(Value,Data.YShift);
905+ }
906+ else if (StringsEqual(Tag,"z_shift"))
907+ {
908+ return ReadFloatValue(Value,Data.ZShift);
909+ }
910+ else if (StringsEqual(Tag,"side"))
911+ {
912+ return ReadSignValue(Value,Data.Sidedness);
913+ }
914+ else if (StringsEqual(Tag,"norm_type"))
915+ {
916+ return ReadBoundedInt16Value(Value,Data.NormalType,0,Model3D::NUMBER_OF_NORMAL_TYPES-1);
917+ }
918+ else if (StringsEqual(Tag,"norm_split"))
919+ {
920+ return ReadFloatValue(Value,Data.NormalSplit);
921+ }
922+ else if (StringsEqual(Tag,"light_type"))
923+ {
924+ return ReadBoundedInt16Value(Value,Data.LightType,0,NUMBER_OF_MODEL_LIGHT_TYPES-1);
925+ }
926+ else if (StringsEqual(Tag,"depth_type"))
927+ {
928+ return ReadSignValue(Value,Data.DepthType);
929+ }
930+ else if (StringsEqual(Tag,"force_sprite_depth"))
931+ {
932+ return ReadBooleanValue(Value,Data.ForceSpriteDepth);
933+ }
934+ else if (StringsEqual(Tag,"file"))
935+ {
936+ Data.ModelFile.SetNameWithPath(Value);
937+ return true;
938+ }
939+ else if (StringsEqual(Tag,"file1"))
940+ {
941+ Data.ModelFile1.SetNameWithPath(Value);
942+ return true;
943+ }
944+ else if (StringsEqual(Tag,"file2"))
945+ {
946+ Data.ModelFile2.SetNameWithPath(Value);
947+ return true;
948+ }
949+ else if (StringsEqual(Tag,"type"))
950+ {
951+ size_t nchars = strlen(Value)+1;
952+ Data.ModelType.resize(nchars);
953+ memcpy(&Data.ModelType[0],Value,nchars);
954+ return true;
955+ }
956+ UnrecognizedTag();
957+ return false;
958+}
959+
960+bool XML_ModelDataParser::AttributesDone()
961+{
962+ // Verify...
963+ if (!CollIsPresent)
964+ {
965+ AttribsMissing();
966+ return false;
967+ }
968+ return true;
969+}
970+
971+bool XML_ModelDataParser::ResetValues()
972+{
973+ MdlDeleteAll();
974+ return true;
975+}
976+
977+bool XML_ModelDataParser::End()
978+{
979+ // Do this at the end because the model data will then include the skin data
980+
981+ // Check to see if a frame is already accounted for
982+ vector<ModelDataEntry>& ML = MdlList[Collection];
983+ for (vector<ModelDataEntry>::iterator MdlIter = ML.begin(); MdlIter < ML.end(); MdlIter++)
984+ {
985+ // Run a gauntlet of equality tests
986+ if (MdlIter->Sequence != Sequence) continue;
987+
988+ if (MdlIter->SequenceMap.size() != SequenceMap.size()) continue;
989+
990+ // Ought to sort, then compare, for correct results
991+ bool AllEqual = true;
992+ for (size_t q=0; q<SequenceMap.size(); q++)
993+ {
994+ SequenceMapEntry& MS = MdlIter->SequenceMap[q];
995+ SequenceMapEntry& S = SequenceMap[q];
996+ if (MS.Sequence != S.Sequence || MS.ModelSequence != S.ModelSequence)
997+ {
998+ AllEqual = false;
999+ break;
1000+ }
1001+ }
1002+ if (!AllEqual) continue;
1003+
1004+ // Replace the data; it passed the tests
1005+ MdlIter->ModelData = Data;
1006+ return true;
1007+ }
1008+
1009+ // If not, then add a new frame entry
1010+ ModelDataEntry DataEntry;
1011+ DataEntry.Sequence = Sequence;
1012+ DataEntry.SequenceMap.swap(SequenceMap); // Quick transfer of contents in desired direction
1013+ DataEntry.ModelData = Data;
1014+ ML.push_back(DataEntry);
1015+
1016+ return true;
1017+}
1018+
1019+static XML_ModelDataParser ModelDataParser;
1020+
1021+
1022+// XML-parser support:
1023+XML_ElementParser *ModelData_GetParser()
1024+{
1025+ ModelDataParser.AddChild(&SkinDataParser);
1026+ ModelDataParser.AddChild(&SequenceMapParser);
1027+
1028+ return &ModelDataParser;
1029+}
1030+XML_ElementParser *Mdl_Clear_GetParser() {return &Mdl_ClearParser;}
1031+
1032+#endif
--- marathon/trunk/Source_Files/RenderMain/Crosshairs.cpp (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/Crosshairs.cpp (revision 530)
@@ -1,185 +1,185 @@
1-/*
2-
3- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4- and the "Aleph One" developers.
5-
6- This program is free software; you can redistribute it and/or modify
7- it under the terms of the GNU General Public License as published by
8- the Free Software Foundation; either version 3 of the License, or
9- (at your option) any later version.
10-
11- This program is distributed in the hope that it will be useful,
12- but WITHOUT ANY WARRANTY; without even the implied warranty of
13- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14- GNU General Public License for more details.
15-
16- This license is contained in the file "COPYING",
17- which is included with this source code; it is available online at
18- http://www.gnu.org/licenses/gpl.html
19-
20- February 21, 2000 (Loren Petrich)
21-
22- Crosshairs-implementation file; contains Quickdraw crosshairs code.
23-
24-Jan 25, 2002 (Br'fin (Jeremy Parsons)):
25- Added accessors for datafields now opaque in Carbon
26-
27-Jun 26, 2002 (Loren Petrich):
28- Added support for crosshairs being circular and/or partially transparent
29-*/
30-
31-#include "cseries.h"
32-#include "Crosshairs.h"
33-
34-
35-static bool _Crosshairs_IsActive = false;
36-
37-bool Crosshairs_IsActive() {return _Crosshairs_IsActive;}
38-bool Crosshairs_SetActive(bool NewState) {return (_Crosshairs_IsActive = (NewState != 0));}
39-
40-
41-// Will draw in center of view rectangle in the current QD graphics context;
42-// modeled after fps display.
43-// It won't try to clip the ends of the lines.
44-bool Crosshairs_Render(Rect &ViewRect)
45-{
46- if (!_Crosshairs_IsActive) return _Crosshairs_IsActive;
47-
48- // Get the crosshair data
49- CrosshairData &Crosshairs = GetCrosshairData();
50-
51- // Push previous state
52- PenState OldPen;
53- RGBColor OldBackColor, OldForeColor;
54-
55- GetPenState(&OldPen);
56- GetBackColor(&OldBackColor);
57- GetForeColor(&OldForeColor);
58-
59- // Get ready to draw the crosshairs
60- PenNormal();
61-
62- // Drawing color
63- RGBForeColor(&Crosshairs.Color);
64-
65- // Get the center location from the view rectangle
66- // Shift it down one, so that even line widths can come out right.
67- short XCen = ((ViewRect.left + ViewRect.right) >> 1) - 1;
68- short YCen = ((ViewRect.top + ViewRect.bottom) >> 1) - 1;
69-
70- // Separate for X and Y; the points are three on top/left and three on top/right:
71- // Line-split position
72- // Octagon vertex (half-way)
73- // Farthest extent
74- short OctaPoints[2][6];
75- short Len;
76-
77- switch(Crosshairs.Shape)
78- {
79- case CHShape_RealCrosshairs:
80-
81- PenSize(1,Crosshairs.Thickness);
82-
83- // Left
84- MoveTo(XCen-Crosshairs.FromCenter+Crosshairs.Thickness-1,YCen);
85- Line(-Crosshairs.Length,0);
86-
87- // Right
88- MoveTo(XCen+Crosshairs.FromCenter,YCen);
89- Line(Crosshairs.Length,0);
90-
91- PenSize(Crosshairs.Thickness,1);
92-
93- // Top
94- MoveTo(XCen,YCen-Crosshairs.FromCenter+Crosshairs.Thickness-1);
95- Line(0,-Crosshairs.Length);
96-
97- // Bottom
98- MoveTo(XCen,YCen+Crosshairs.FromCenter);
99- Line(0,Crosshairs.Length);
100-
101- break;
102-
103- case CHShape_Circle:
104- // This will really be an octagon, for OpenGL-rendering convenience
105-
106- // Precalculate the line endpoints, for convenience
107-
108- Len = Crosshairs.Length;
109- OctaPoints[0][0] = XCen - Len;
110- OctaPoints[0][5] = XCen + Len;
111- OctaPoints[1][0] = YCen - Len;
112- OctaPoints[1][5] = YCen + Len;
113-
114- Len = Len/2;
115- OctaPoints[0][1] = XCen - Len;
116- OctaPoints[0][4] = XCen + Len;
117- OctaPoints[1][1] = YCen - Len;
118- OctaPoints[1][4] = YCen + Len;
119-
120- Len = MIN(Len,Crosshairs.FromCenter);
121- OctaPoints[0][2] = XCen - Len;
122- OctaPoints[0][3] = XCen + Len;
123- OctaPoints[1][2] = YCen - Len;
124- OctaPoints[1][3] = YCen + Len;
125-
126- // We need to do 12 line segments, so we do them in 2*2*3 fashion
127-
128- for (int ix=0; ix<2; ix++)
129- {
130- int ixi = (ix > 0) ? 5 : 0;
131- int ixid = (ix > 0) ? -1 : 1;
132- for (int iy=0; iy<2; iy++)
133- {
134- int iyi = (iy > 0) ? 5 : 0;
135- int iyid = (iy > 0) ? -1 : 1;
136-
137- // Vertical
138- PenSize(Crosshairs.Thickness,1);
139- MoveTo(OctaPoints[0][ixi],OctaPoints[1][iyi+2*iyid]);
140- LineTo(OctaPoints[0][ixi],OctaPoints[1][iyi+iyid]);
141-
142- // Diagonal
143- PenSize(Crosshairs.Thickness,Crosshairs.Thickness);
144- LineTo(OctaPoints[0][ixi+ixid],OctaPoints[1][iyi]);
145-
146- // Horizontal
147- PenSize(1,Crosshairs.Thickness);
148- LineTo(OctaPoints[0][ixi+2*ixid],OctaPoints[1][iyi]);
149- }
150- }
151-
152- break;
153- }
154-
155- // Pop previous state
156- SetPenState(&OldPen);
157- RGBBackColor(&OldBackColor);
158- RGBForeColor(&OldForeColor);
159-
160- return _Crosshairs_IsActive;
161-}
162-
163-// If a graphics context is also specified
164-bool Crosshairs_Render(GrafPtr Context, Rect &ViewRect)
165-{
166- // Push context
167- GrafPtr OldContext;
168- GetPort(&OldContext);
169- SetPort(Context);
170-
171- bool RetCode = Crosshairs_Render(ViewRect);
172-
173- // Pop context
174- SetPort(OldContext);
175-
176- return RetCode;
177-}
178-
179-// If no view rectangle is explicitly specified
180-bool Crosshairs_Render(GrafPtr Context)
181-{
182- Rect portRect;
183- GetPortBounds(Context, &portRect);
184- return Crosshairs_Render(Context, portRect);
185-}
1+/*
2+
3+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4+ and the "Aleph One" developers.
5+
6+ This program is free software; you can redistribute it and/or modify
7+ it under the terms of the GNU General Public License as published by
8+ the Free Software Foundation; either version 3 of the License, or
9+ (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU General Public License for more details.
15+
16+ This license is contained in the file "COPYING",
17+ which is included with this source code; it is available online at
18+ http://www.gnu.org/licenses/gpl.html
19+
20+ February 21, 2000 (Loren Petrich)
21+
22+ Crosshairs-implementation file; contains Quickdraw crosshairs code.
23+
24+Jan 25, 2002 (Br'fin (Jeremy Parsons)):
25+ Added accessors for datafields now opaque in Carbon
26+
27+Jun 26, 2002 (Loren Petrich):
28+ Added support for crosshairs being circular and/or partially transparent
29+*/
30+
31+#include "cseries.h"
32+#include "Crosshairs.h"
33+
34+
35+static bool _Crosshairs_IsActive = false;
36+
37+bool Crosshairs_IsActive() {return _Crosshairs_IsActive;}
38+bool Crosshairs_SetActive(bool NewState) {return (_Crosshairs_IsActive = (NewState != 0));}
39+
40+
41+// Will draw in center of view rectangle in the current QD graphics context;
42+// modeled after fps display.
43+// It won't try to clip the ends of the lines.
44+bool Crosshairs_Render(Rect &ViewRect)
45+{
46+ if (!_Crosshairs_IsActive) return _Crosshairs_IsActive;
47+
48+ // Get the crosshair data
49+ CrosshairData &Crosshairs = GetCrosshairData();
50+
51+ // Push previous state
52+ PenState OldPen;
53+ RGBColor OldBackColor, OldForeColor;
54+
55+ GetPenState(&OldPen);
56+ GetBackColor(&OldBackColor);
57+ GetForeColor(&OldForeColor);
58+
59+ // Get ready to draw the crosshairs
60+ PenNormal();
61+
62+ // Drawing color
63+ RGBForeColor(&Crosshairs.Color);
64+
65+ // Get the center location from the view rectangle
66+ // Shift it down one, so that even line widths can come out right.
67+ short XCen = ((ViewRect.left + ViewRect.right) >> 1) - 1;
68+ short YCen = ((ViewRect.top + ViewRect.bottom) >> 1) - 1;
69+
70+ // Separate for X and Y; the points are three on top/left and three on top/right:
71+ // Line-split position
72+ // Octagon vertex (half-way)
73+ // Farthest extent
74+ short OctaPoints[2][6];
75+ short Len;
76+
77+ switch(Crosshairs.Shape)
78+ {
79+ case CHShape_RealCrosshairs:
80+
81+ PenSize(1,Crosshairs.Thickness);
82+
83+ // Left
84+ MoveTo(XCen-Crosshairs.FromCenter+Crosshairs.Thickness-1,YCen);
85+ Line(-Crosshairs.Length,0);
86+
87+ // Right
88+ MoveTo(XCen+Crosshairs.FromCenter,YCen);
89+ Line(Crosshairs.Length,0);
90+
91+ PenSize(Crosshairs.Thickness,1);
92+
93+ // Top
94+ MoveTo(XCen,YCen-Crosshairs.FromCenter+Crosshairs.Thickness-1);
95+ Line(0,-Crosshairs.Length);
96+
97+ // Bottom
98+ MoveTo(XCen,YCen+Crosshairs.FromCenter);
99+ Line(0,Crosshairs.Length);
100+
101+ break;
102+
103+ case CHShape_Circle:
104+ // This will really be an octagon, for OpenGL-rendering convenience
105+
106+ // Precalculate the line endpoints, for convenience
107+
108+ Len = Crosshairs.Length;
109+ OctaPoints[0][0] = XCen - Len;
110+ OctaPoints[0][5] = XCen + Len;
111+ OctaPoints[1][0] = YCen - Len;
112+ OctaPoints[1][5] = YCen + Len;
113+
114+ Len = Len/2;
115+ OctaPoints[0][1] = XCen - Len;
116+ OctaPoints[0][4] = XCen + Len;
117+ OctaPoints[1][1] = YCen - Len;
118+ OctaPoints[1][4] = YCen + Len;
119+
120+ Len = MIN(Len,Crosshairs.FromCenter);
121+ OctaPoints[0][2] = XCen - Len;
122+ OctaPoints[0][3] = XCen + Len;
123+ OctaPoints[1][2] = YCen - Len;
124+ OctaPoints[1][3] = YCen + Len;
125+
126+ // We need to do 12 line segments, so we do them in 2*2*3 fashion
127+
128+ for (int ix=0; ix<2; ix++)
129+ {
130+ int ixi = (ix > 0) ? 5 : 0;
131+ int ixid = (ix > 0) ? -1 : 1;
132+ for (int iy=0; iy<2; iy++)
133+ {
134+ int iyi = (iy > 0) ? 5 : 0;
135+ int iyid = (iy > 0) ? -1 : 1;
136+
137+ // Vertical
138+ PenSize(Crosshairs.Thickness,1);
139+ MoveTo(OctaPoints[0][ixi],OctaPoints[1][iyi+2*iyid]);
140+ LineTo(OctaPoints[0][ixi],OctaPoints[1][iyi+iyid]);
141+
142+ // Diagonal
143+ PenSize(Crosshairs.Thickness,Crosshairs.Thickness);
144+ LineTo(OctaPoints[0][ixi+ixid],OctaPoints[1][iyi]);
145+
146+ // Horizontal
147+ PenSize(1,Crosshairs.Thickness);
148+ LineTo(OctaPoints[0][ixi+2*ixid],OctaPoints[1][iyi]);
149+ }
150+ }
151+
152+ break;
153+ }
154+
155+ // Pop previous state
156+ SetPenState(&OldPen);
157+ RGBBackColor(&OldBackColor);
158+ RGBForeColor(&OldForeColor);
159+
160+ return _Crosshairs_IsActive;
161+}
162+
163+// If a graphics context is also specified
164+bool Crosshairs_Render(GrafPtr Context, Rect &ViewRect)
165+{
166+ // Push context
167+ GrafPtr OldContext;
168+ GetPort(&OldContext);
169+ SetPort(Context);
170+
171+ bool RetCode = Crosshairs_Render(ViewRect);
172+
173+ // Pop context
174+ SetPort(OldContext);
175+
176+ return RetCode;
177+}
178+
179+// If no view rectangle is explicitly specified
180+bool Crosshairs_Render(GrafPtr Context)
181+{
182+ Rect portRect;
183+ GetPortBounds(Context, &portRect);
184+ return Crosshairs_Render(Context, portRect);
185+}
--- marathon/trunk/Source_Files/RenderMain/NewRenderPlaceObjs.h (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/NewRenderPlaceObjs.h (revision 530)
@@ -1 +1 @@
1-ゥ
1+ゥ
--- marathon/trunk/Source_Files/RenderMain/shapes.cpp (revision 529)
+++ marathon/trunk/Source_Files/RenderMain/shapes.cpp (revision 530)
@@ -1,2987 +1,2898 @@
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-

Part of diff was cut off due to size limit. Use your local client to view the full diff.

Show on old repository browser