• R/O
  • SSH
  • HTTPS

marathon: Commit


Commit MetaInfo

Revision530 (tree)
Zeit2012-06-02 14:44:12
Autorookawa_mi

Log Message

1.0.2対応
改行コード修正

Ändern Zusammenfassung

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 */