1 #include "Animation_Control.h"
2 #include "Animation_Data.h"
3 #include "Debug.h"
4 #include "English.h"
5 #include "Font.h"
6 #include "Font_Control.h"
7 #include "GameSettings.h"
8 #include "HImage.h"
9 #include "Handle_Items.h"
10 #include "Handle_UI.h"
11 #include "Interactive_Tiles.h"
12 #include "Interface.h"
13 #include "Interface_Control.h"
14 #include "Isometric_Utils.h"
15 #include "Local.h"
16 #include "Overhead.h"
17 #include "Radar_Screen.h"
18 #include "Render_Dirty.h"
19 #include "Render_Fun.h"
20 #include "RenderWorld.h"
21 #include "Rotting_Corpses.h"
22 #include "Shading.h"
23 #include "Soldier_Find.h"
24 #include "Sound_Control.h"
25 #include "Structure.h"
26 #include "SysUtil.h"
27 #include "Sys_Globals.h"
28 #include "TileDef.h"
29 #include "Tile_Cache.h"
30 #include "Timer_Control.h"
31 #include "VObject.h"
32 #include "VObject_Blitters.h"
33 #include "VSurface.h"
34 #include "WCheck.h"
35 #include "UILayout.h"
36 #include "GameState.h"
37 #include "Logger.h"
38 
39 #include <string_theory/format>
40 #include <string_theory/string>
41 
42 #include <algorithm>
43 #include <math.h>
44 #include <stdint.h>
45 
46 UINT16* gpZBuffer = NULL;
47 UINT16  gZBufferPitch = 0;
48 
49 static INT16 gsCurrentGlowFrame     = 0;
50 static INT16 gsCurrentItemGlowFrame = 0;
51 
52 
53 // VIEWPORT OFFSET VALUES
54 // NOTE: THESE VALUES MUST BE MULTIPLES OF TILE SIZES!
55 #define VIEWPORT_XOFFSET_S        (WORLD_TILE_X * 1)
56 #define VIEWPORT_YOFFSET_S        (WORLD_TILE_Y * 2)
57 #define LARGER_VIEWPORT_XOFFSET_S (VIEWPORT_XOFFSET_S * 3)
58 #define LARGER_VIEWPORT_YOFFSET_S (VIEWPORT_YOFFSET_S * 5)
59 
60 enum RenderTilesFlags
61 {
62 	TILES_NONE                      = 0,
63 	TILES_DYNAMIC_CHECKFOR_INT_TILE = 0x00000400,
64 	TILES_DIRTY                     = 0x80000000,
65 	TILES_MARKED                    = 0x10000000,
66 	TILES_OBSCURED                  = 0x01000000
67 };
68 
69 
70 #define MAX_RENDERED_ITEMS 2
71 
72 
73 // RENDERER FLAGS FOR DIFFERENT RENDER LEVELS
74 enum RenderLayerID
75 {
76 	RENDER_STATIC_LAND,
77 	RENDER_STATIC_OBJECTS,
78 	RENDER_STATIC_SHADOWS,
79 	RENDER_STATIC_STRUCTS,
80 	RENDER_STATIC_ROOF,
81 	RENDER_STATIC_ONROOF,
82 	RENDER_STATIC_TOPMOST,
83 	RENDER_DYNAMIC_LAND,
84 	RENDER_DYNAMIC_OBJECTS,
85 	RENDER_DYNAMIC_SHADOWS,
86 	RENDER_DYNAMIC_STRUCT_MERCS,
87 	RENDER_DYNAMIC_MERCS,
88 	RENDER_DYNAMIC_STRUCTS,
89 	RENDER_DYNAMIC_ROOF,
90 	RENDER_DYNAMIC_HIGHMERCS,
91 	RENDER_DYNAMIC_ONROOF,
92 	RENDER_DYNAMIC_TOPMOST,
93 	NUM_RENDER_FX_TYPES
94 };
95 
96 
97 #define NUM_ITEM_CYCLE_COLORS 20
98 
99 static UINT16 us16BPPItemCycleWhiteColors[NUM_ITEM_CYCLE_COLORS];
100 static UINT16 us16BPPItemCycleRedColors[NUM_ITEM_CYCLE_COLORS];
101 static UINT16 us16BPPItemCycleYellowColors[NUM_ITEM_CYCLE_COLORS];
102 
103 
104 static INT16 gusNormalItemOutlineColor;
105 static INT16 gusYellowItemOutlineColor;
106 
107 INT16   gsRenderHeight = 0;
108 BOOLEAN gfRenderFullThisFrame = 0;
109 
110 
111 UINT8   gubCurScrollSpeedID = 1;
112 BOOLEAN gfDoVideoScroll     = TRUE;
113 BOOLEAN gfScrollPending     = FALSE;
114 
115 static RenderLayerFlags uiLayerUsedFlags         = TILES_LAYER_ALL;
116 static RenderLayerFlags uiAdditiveLayerUsedFlags = TILES_LAYER_ALL;
117 
118 
119 static const UINT8 gsGlowFrames[] =
120 {
121 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123 	2, 4, 6, 8, 9, 8, 6, 4, 2, 0
124 };
125 
126 
127 INT16 gsTopLeftWorldX;                                  /**< Top left corner of the visible portion of the map (in map coordiantes). */
128 INT16 gsTopLeftWorldY;                                  /**< Top left corner of the visible portion of the map (in map coordiantes). */
129 INT16 gsBottomRightWorldX;                              /**< Bottom right corner of the visible portion of the map (in map coordiantes). */
130 INT16 gsBottomRightWorldY;                              /**< Bottom right corner of the visible portion of the map (in map coordiantes). */
131 BOOLEAN gfIgnoreScrolling = FALSE;
132 
133 BOOLEAN gfIgnoreScrollDueToCenterAdjust = FALSE;
134 
135 // Map coordiante system
136 // ---------------------
137 //   Center of the map independently of its size is always (0, 1625).
138 //
139 
140 // GLOBAL SCROLLING PARAMS
141 INT16 gCenterWorldX;
142 INT16 gCenterWorldY;
143 INT16 gsLeftX;      // Left edge of the current map in screen coordinates.
144 INT16 gsTopY;       // Top edge of the current map in screen coordinates.
145 INT16 gsRightX;     // Right edge of the current map in screen coordinates.
146 INT16 gsBottomY;    // Bottom edge of the current map in screen coordinates.
147 INT16 gsCX;         // Center of the map in screen coordinates (seems to be always 0).
148 INT16 gsCY;         // Center of the map in screen coordinates (seems to be always 1625).
149 double gdScaleX;
150 double gdScaleY;
151 
152 #define FASTMAPROWCOLTOPOS(r, c) ((r) * WORLD_COLS + (c))
153 
154 
155 bool g_scroll_inertia = false;
156 
157 
158 // GLOBALS FOR CALCULATING STARTING PARAMETERS
159 static INT16 gsStartPointX_S;
160 static INT16 gsStartPointY_S;
161 static INT16 gsStartPointX_M;
162 static INT16 gsStartPointY_M;
163 static INT16 gsEndXS;
164 static INT16 gsEndYS;
165 // LARGER OFFSET VERSION FOR GIVEN LAYERS
166 // NOTE: Larger viewport offset values are used for static world surface rendering. That surface is blitted
167 //       during scrolling to speed up rendering and make scrolling smoother.
168 // TODO: maxrd2 drop all of these when SDL blitting is done
169 static INT16 gsLStartPointX_S;
170 static INT16 gsLStartPointY_S;
171 static INT16 gsLStartPointX_M;
172 static INT16 gsLStartPointY_M;
173 static INT16 gsLEndXS;
174 static INT16 gsLEndYS;
175 
176 
177 INT16 gsScrollXIncrement;
178 INT16 gsScrollYIncrement;
179 
180 
181 // Rendering flags (full, partial, etc.)
182 static RenderFlags gRenderFlags = RENDER_FLAG_NONE;
183 
184 #define gClippingRect (g_ui.m_wordlClippingRect)
185 static SGPRect gOldClipRect;
186 INT16   gsRenderCenterX;
187 INT16   gsRenderCenterY;
188 INT16   gsRenderWorldOffsetX = 0;
189 INT16   gsRenderWorldOffsetY = 10;
190 
191 
192 struct RenderFXType
193 {
194 	BOOLEAN fDynamic;
195 	BOOLEAN fZWrite;
196 	BOOLEAN fZBlitter;
197 	BOOLEAN fShadowBlitter;
198 	BOOLEAN fLinkedListDirection;
199 	BOOLEAN fMerc;
200 	BOOLEAN fCheckForRedundency;
201 	BOOLEAN fObscured;
202 };
203 
204 
205 static const RenderFXType RenderFX[] =
206 {
207 	{ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,  FALSE }, // STATIC LAND
208 	{ FALSE, TRUE,  TRUE,  FALSE, TRUE,  FALSE, TRUE,  FALSE }, // STATIC OBJECTS
209 	{ FALSE, TRUE,  TRUE,  TRUE,  TRUE,  FALSE, FALSE, FALSE }, // STATIC SHADOWS
210 	{ FALSE, TRUE,  TRUE,  FALSE, TRUE,  FALSE, FALSE, TRUE  }, // STATIC STRUCTS
211 	{ FALSE, TRUE,  TRUE,  FALSE, TRUE,  FALSE, FALSE, FALSE }, // STATIC ROOF
212 	{ FALSE, TRUE,  TRUE,  FALSE, TRUE,  FALSE, FALSE, TRUE  }, // STATIC ONROOF
213 	{ FALSE, TRUE,  TRUE,  FALSE, TRUE,  FALSE, FALSE, FALSE }, // STATIC TOPMOST
214 	{ TRUE,  FALSE, TRUE,  FALSE, FALSE, FALSE, TRUE,  FALSE }, // DYNAMIC LAND
215 	{ TRUE,  FALSE, TRUE,  FALSE, TRUE,  FALSE, TRUE,  FALSE }, // DYNAMIC OBJECT
216 	{ TRUE,  FALSE, FALSE, TRUE,  TRUE,  FALSE, FALSE, FALSE }, // DYNAMIC SHADOW
217 	{ TRUE,  FALSE, TRUE,  FALSE, TRUE,  TRUE,  FALSE, FALSE }, // DYNAMIC STRUCT MERCS
218 	{ TRUE,  FALSE, TRUE,  FALSE, TRUE,  TRUE,  FALSE, FALSE }, // DYNAMIC MERCS
219 	{ TRUE,  FALSE, TRUE,  FALSE, TRUE,  FALSE, FALSE, FALSE }, // DYNAMIC STRUCT
220 	{ TRUE,  FALSE, TRUE,  FALSE, TRUE,  FALSE, FALSE, FALSE }, // DYNAMIC ROOF
221 	{ TRUE,  FALSE, TRUE,  FALSE, TRUE,  TRUE,  FALSE, FALSE }, // DYNAMIC HIGHMERCS
222 	{ TRUE,  FALSE, TRUE,  FALSE, TRUE,  FALSE, FALSE, FALSE }, // DYNAMIC ONROOF
223 	{ TRUE,  FALSE, TRUE,  FALSE, TRUE,  FALSE, FALSE, FALSE }  // DYNAMIC TOPMOST
224 };
225 
226 
227 static const UINT8 RenderFXStartIndex[] =
228 {
229 	LAND_START_INDEX,    // STATIC LAND
230 	OBJECT_START_INDEX,  // STATIC OBJECTS
231 	SHADOW_START_INDEX,  // STATIC SHADOWS
232 	STRUCT_START_INDEX,  // STATIC STRUCTS
233 	ROOF_START_INDEX,    // STATIC ROOF
234 	ONROOF_START_INDEX,  // STATIC ONROOF
235 	TOPMOST_START_INDEX, // STATIC TOPMOST
236 	LAND_START_INDEX,    // DYNAMIC LAND
237 	OBJECT_START_INDEX,  // DYNAMIC OBJECT
238 	SHADOW_START_INDEX,  // DYNAMIC SHADOW
239 	MERC_START_INDEX,    // DYNAMIC STRUCT MERCS
240 	MERC_START_INDEX,    // DYNAMIC MERCS
241 	STRUCT_START_INDEX,  // DYNAMIC STRUCT
242 	ROOF_START_INDEX,    // DYNAMIC ROOF
243 	MERC_START_INDEX,    // DYNAMIC HIGHMERCS
244 	ONROOF_START_INDEX,  // DYNAMIC ONROOF
245 	TOPMOST_START_INDEX, // DYNAMIC TOPMOST
246 };
247 
248 
249 static RenderLayerFlags const g_render_fx_layer_flags[] =
250 {
251 	TILES_STATIC_LAND,
252 	TILES_STATIC_OBJECTS,
253 	TILES_STATIC_SHADOWS,
254 	TILES_STATIC_STRUCTURES,
255 	TILES_STATIC_ROOF,
256 	TILES_STATIC_ONROOF,
257 	TILES_STATIC_TOPMOST,
258 	TILES_DYNAMIC_LAND,
259 	TILES_DYNAMIC_OBJECTS,
260 	TILES_DYNAMIC_SHADOWS,
261 	TILES_DYNAMIC_STRUCT_MERCS,
262 	TILES_DYNAMIC_MERCS,
263 	TILES_DYNAMIC_STRUCTURES,
264 	TILES_DYNAMIC_ROOF,
265 	TILES_DYNAMIC_HIGHMERCS,
266 	TILES_DYNAMIC_ONROOF,
267 	TILES_DYNAMIC_TOPMOST
268 };
269 
270 
271 #ifdef _DEBUG
272 
273 extern UINT8 gubFOVDebugInfoInfo[WORLD_MAX];
274 extern UINT8 gubGridNoMarkers[WORLD_MAX];
275 extern UINT8 gubGridNoValue;
276 
277 extern BOOLEAN gfDisplayCoverValues;
278 static BOOLEAN gfDisplayGridNoVisibleValues = 0;
279 extern INT16   gsCoverValue[WORLD_MAX];
280 extern INT16   gsBestCover;
281 
282 static void RenderFOVDebugInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS);
283 static void RenderCoverDebugInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS);
284 static void RenderGridNoVisibleDebugInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS);
285 
286 #endif
287 
288 
ResetLayerOptimizing(void)289 static void ResetLayerOptimizing(void)
290 {
291 	uiLayerUsedFlags         = TILES_LAYER_ALL;
292 	uiAdditiveLayerUsedFlags = TILES_LAYER_NONE;
293 }
294 
295 
ResetSpecificLayerOptimizing(RenderLayerFlags const uiRowFlag)296 void ResetSpecificLayerOptimizing(RenderLayerFlags const uiRowFlag)
297 {
298 	uiLayerUsedFlags |= uiRowFlag;
299 }
300 
301 
SumAdditiveLayerOptimization()302 static void SumAdditiveLayerOptimization()
303 {
304 	uiLayerUsedFlags = uiAdditiveLayerUsedFlags;
305 }
306 
307 
SetRenderFlags(RenderFlags const uiFlags)308 void SetRenderFlags(RenderFlags const uiFlags)
309 {
310 	gRenderFlags |= uiFlags;
311 }
312 
313 
ClearRenderFlags(RenderFlags const uiFlags)314 void ClearRenderFlags(RenderFlags const uiFlags)
315 {
316 	gRenderFlags &= ~uiFlags;
317 }
318 
319 
RenderSetShadows(BOOLEAN fShadows)320 void RenderSetShadows(BOOLEAN fShadows)
321 {
322 	if (fShadows)
323 	{
324 		gRenderFlags |= RENDER_FLAG_SHADOWS;
325 	}
326 	else
327 	{
328 		gRenderFlags &= ~RENDER_FLAG_SHADOWS;
329 	}
330 }
331 
332 
GetMapXYWorldY(INT32 WorldCellX,INT32 WorldCellY)333 static inline INT16 GetMapXYWorldY(INT32 WorldCellX, INT32 WorldCellY)
334 {
335 	INT16 RDistToCenterX = WorldCellX * CELL_X_SIZE - gCenterWorldX;
336 	INT16 RDistToCenterY = WorldCellY * CELL_Y_SIZE - gCenterWorldY;
337 	INT16 RScreenCenterY = RDistToCenterX + RDistToCenterY;
338 	return RScreenCenterY + gsCY - gsTopY;
339 }
340 
341 
342 static void Blt8BPPDataTo16BPPBufferTransZIncClip(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion);
343 static void Blt8BPPDataTo16BPPBufferTransZIncClipZSameZBurnsThrough(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion);
344 static void Blt8BPPDataTo16BPPBufferTransZIncObscureClip(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion);
345 static void Blt8BPPDataTo16BPPBufferTransZTransShadowIncClip(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion, INT16 sZIndex, const UINT16* p16BPPPalette);
346 static void Blt8BPPDataTo16BPPBufferTransZTransShadowIncObscureClip(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion, INT16 sZIndex, const UINT16* p16BPPPalette);
347 
348 
RenderTiles(RenderTilesFlags const uiFlags,INT32 const iStartPointX_M,INT32 const iStartPointY_M,INT32 const iStartPointX_S,INT32 const iStartPointY_S,INT32 const iEndXS,INT32 const iEndYS,UINT8 const ubNumLevels,RenderLayerID const * const psLevelIDs)349 static void RenderTiles(RenderTilesFlags const uiFlags, INT32 const iStartPointX_M, INT32 const iStartPointY_M, INT32 const iStartPointX_S, INT32 const iStartPointY_S, INT32 const iEndXS, INT32 const iEndYS, UINT8 const ubNumLevels, RenderLayerID const* const psLevelIDs)
350 {
351 	static UINT8        ubLevelNodeStartIndex[NUM_RENDER_FX_TYPES];
352 	static RenderFXType RenderFXList[NUM_RENDER_FX_TYPES];
353 
354 	HVOBJECT hVObject = NULL; // XXX HACK000E
355 	BOOLEAN fPixelate = FALSE;
356 	INT16 sMultiTransShadowZBlitterIndex = -1;
357 
358 	INT16 sZOffsetX = -1;
359 	INT16 sZOffsetY = -1;
360 	const ROTTING_CORPSE* pCorpse = NULL;
361 	UINT32 uiTileElemFlags = 0;
362 
363 	UINT16          usImageIndex = 0;
364 	INT16           sZLevel      = 0;
365 	BackgroundFlags uiDirtyFlags = BGND_FLAG_NONE;
366 	UINT16 const*   pShadeTable  = 0;
367 
368 	INT32 iAnchorPosX_M = iStartPointX_M;
369 	INT32 iAnchorPosY_M = iStartPointY_M;
370 	INT32 iAnchorPosX_S = iStartPointX_S;
371 	INT32 iAnchorPosY_S = iStartPointY_S;
372 
373 	UINT32                uiDestPitchBYTES = 0;
374 	UINT16*               pDestBuf         = 0;
375 	SGPVSurface::Lockable lock;
376 	if  (!(uiFlags & TILES_DIRTY))
377 	{
378 		lock.Lock(FRAME_BUFFER);
379 		pDestBuf         = lock.Buffer<UINT16>();
380 		uiDestPitchBYTES = lock.Pitch();
381 	}
382 
383 	bool check_for_mouse_detections = false;
384 	if (uiFlags & TILES_DYNAMIC_CHECKFOR_INT_TILE &&
385 			ShouldCheckForMouseDetections())
386 	{
387 		BeginCurInteractiveTileCheck();
388 		// If we are in edit mode, don't do this
389 		check_for_mouse_detections = !gfEditMode;
390 	}
391 
392 	for (UINT32 i = 0; i < ubNumLevels; i++)
393 	{
394 		ubLevelNodeStartIndex[i] = RenderFXStartIndex[psLevelIDs[i]];
395 		RenderFXList[i]          = RenderFX[psLevelIDs[i]];
396 	}
397 
398 	INT8 bXOddFlag = 0;
399 	do
400 	{
401 		static INT32 iTileMapPos[500];
402 
403 		{
404 			INT32 iTempPosX_M = iAnchorPosX_M;
405 			INT32 iTempPosY_M = iAnchorPosY_M;
406 			INT32 iTempPosX_S = iAnchorPosX_S;
407 			UINT32 uiMapPosIndex = 0;
408 
409 			// Build tile index list
410 			do
411 			{
412 				iTileMapPos[uiMapPosIndex] = FASTMAPROWCOLTOPOS(iTempPosY_M, iTempPosX_M);
413 
414 				iTempPosX_S += 40;
415 				iTempPosX_M++;
416 				iTempPosY_M--;
417 
418 				uiMapPosIndex++;
419 			}
420 			while (iTempPosX_S < iEndXS);
421 		}
422 
423 		for (UINT32 cnt = 0; cnt < ubNumLevels; cnt++)
424 		{
425 			RenderLayerFlags const uiRowFlags = g_render_fx_layer_flags[psLevelIDs[cnt]];
426 
427 			if (uiRowFlags & TILES_ALL_DYNAMICS && !(uiLayerUsedFlags & uiRowFlags) && !(uiFlags & TILES_DYNAMIC_CHECKFOR_INT_TILE)) continue;
428 
429 			INT32 iTempPosX_M = iAnchorPosX_M;
430 			INT32 iTempPosY_M = iAnchorPosY_M;
431 			INT32 iTempPosX_S = iAnchorPosX_S;
432 			INT32 iTempPosY_S = iAnchorPosY_S;
433 			UINT32 uiMapPosIndex = 0;
434 
435 			if (bXOddFlag) iTempPosX_S += 20;
436 
437 			do
438 			{
439 				const UINT32 uiTileIndex = iTileMapPos[uiMapPosIndex];
440 				uiMapPosIndex++;
441 
442 				if (uiTileIndex < GRIDSIZE)
443 				{
444 					MAP_ELEMENT const& me = gpWorldLevelData[uiTileIndex];
445 
446 					/* OK, we're searching through this loop anyway, might as well check
447 					 * for mouse position over objects. Experimental! */
448 					if (check_for_mouse_detections && me.pStructHead)
449 					{
450 						LogMouseOverInteractiveTile(uiTileIndex);
451 					}
452 
453 					if (uiFlags & TILES_MARKED && !(me.uiFlags & MAPELEMENT_REDRAW)) goto next_tile;
454 
455 					INT8             n_visible_items = 0;
456 					ITEM_POOL const* item_pool       = 0;
457 					for (LEVELNODE* pNode = me.pLevelNodes[ubLevelNodeStartIndex[cnt]]; pNode;)
458 					{
459 						const RenderFXType RenderingFX = RenderFXList[cnt];
460 						const BOOLEAN fObscured            = RenderingFX.fObscured;
461 						const BOOLEAN fDynamic             = RenderingFX.fDynamic;
462 						BOOLEAN       fMerc                = RenderingFX.fMerc;
463 						BOOLEAN       fZWrite              = RenderingFX.fZWrite;
464 						BOOLEAN       fZBlitter            = RenderingFX.fZBlitter;
465 						BOOLEAN       fShadowBlitter       = RenderingFX.fShadowBlitter;
466 						const BOOLEAN fLinkedListDirection = RenderingFX.fLinkedListDirection;
467 						const BOOLEAN fCheckForRedundency  = RenderingFX.fCheckForRedundency;
468 
469 						BOOLEAN fMultiZBlitter            = FALSE;
470 						BOOLEAN fIntensityBlitter         = FALSE;
471 						BOOLEAN fSaveZ                    = FALSE;
472 						BOOLEAN fWallTile                 = FALSE;
473 						BOOLEAN fMultiTransShadowZBlitter = FALSE;
474 						BOOLEAN fObscuredBlitter          = FALSE;
475 						UINT32 uiAniTileFlags = 0;
476 						INT16 gsForceSoldierZLevel = 0;
477 
478 						const UINT32 uiLevelNodeFlags = pNode->uiFlags;
479 
480 						if (fCheckForRedundency                              &&
481 								me.uiFlags & MAPELEMENT_REDUNDENT                &&
482 								!(me.uiFlags & MAPELEMENT_REEVALUATE_REDUNDENCY) && // If we donot want to re-evaluate first
483 								!(gTacticalStatus.uiFlags & NOHIDE_REDUNDENCY))
484 						{
485 							break;
486 						}
487 
488 						// Force z-buffer blitting for marked tiles (even ground!)
489 						if (uiFlags & TILES_MARKED) fZBlitter = TRUE;
490 
491 						//Looking up height every time here is alot better than doing it above!
492 						INT16 const sTileHeight = me.sHeight;
493 
494 						INT16 sModifiedTileHeight = (sTileHeight / 80 - 1) * 80;
495 						if (sModifiedTileHeight < 0) sModifiedTileHeight = 0;
496 
497 						BOOLEAN fRenderTile = TRUE;
498 						if (!(uiLevelNodeFlags & LEVELNODE_REVEAL))
499 						{
500 							fPixelate = FALSE;
501 						}
502 						else if (fDynamic)
503 						{
504 							fPixelate = TRUE;
505 						}
506 						else
507 						{
508 							fRenderTile = FALSE;
509 						}
510 
511 						// non-type specific setup
512 						INT16 sXPos = iTempPosX_S;
513 						INT16 sYPos = iTempPosY_S;
514 
515 						TILE_ELEMENT const* TileElem  = 0;
516 						// setup for any tile type except mercs
517 						if (!fMerc)
518 						{
519 							if (uiLevelNodeFlags & (LEVELNODE_ROTTINGCORPSE | LEVELNODE_CACHEDANITILE))
520 							{
521 								if (fDynamic)
522 								{
523 									if (!(uiLevelNodeFlags & LEVELNODE_DYNAMIC) && !(uiLevelNodeFlags & LEVELNODE_LASTDYNAMIC))
524 									{
525 										fRenderTile = FALSE;
526 									}
527 								}
528 								else if (uiLevelNodeFlags & LEVELNODE_DYNAMIC)
529 								{
530 									fRenderTile = FALSE;
531 								}
532 							}
533 							else
534 							{
535 								TileElem =
536 									uiLevelNodeFlags & LEVELNODE_REVEALTREES ? &gTileDatabase[pNode->usIndex + 2] :
537 									&gTileDatabase[pNode->usIndex];
538 
539 								// Handle independent-per-tile animations (i.e.: doors, exploding things, etc.)
540 								if (fDynamic && uiLevelNodeFlags & LEVELNODE_ANIMATION && pNode->sCurrentFrame != -1)
541 								{
542 									Assert(TileElem->pAnimData);
543 									TileElem = &gTileDatabase[TileElem->pAnimData->pusFrames[pNode->sCurrentFrame]];
544 								}
545 
546 								// Set Tile elem flags here!
547 								uiTileElemFlags = TileElem->uiFlags;
548 
549 								if (!fPixelate)
550 								{
551 									if (fDynamic)
552 									{
553 										if (!(uiLevelNodeFlags & LEVELNODE_DYNAMIC) && !(uiLevelNodeFlags & LEVELNODE_LASTDYNAMIC) && !(uiTileElemFlags & DYNAMIC_TILE))
554 										{
555 											if (uiTileElemFlags & ANIMATED_TILE)
556 											{
557 												Assert(TileElem->pAnimData);
558 												TileElem        = &gTileDatabase[TileElem->pAnimData->pusFrames[TileElem->pAnimData->bCurrentFrame]];
559 												uiTileElemFlags = TileElem->uiFlags;
560 											}
561 											else
562 											{
563 												fRenderTile = FALSE;
564 											}
565 										}
566 									}
567 									else
568 									{
569 										if (uiTileElemFlags & ANIMATED_TILE ||
570 												((uiTileElemFlags & DYNAMIC_TILE || uiLevelNodeFlags & LEVELNODE_DYNAMIC) && !(uiFlags & TILES_OBSCURED)))
571 										{
572 											fRenderTile = FALSE;
573 										}
574 									}
575 								}
576 							}
577 
578 							// OK, ATE, CHECK FOR AN OBSCURED TILE AND MAKE SURE IF LEVELNODE IS SET
579 							// WE DON'T RENDER UNLESS WE HAVE THE RENDER FLAG SET!
580 							if (fObscured)
581 							{
582 								if (uiFlags & TILES_OBSCURED)
583 								{
584 									if (uiLevelNodeFlags & LEVELNODE_SHOW_THROUGH)
585 									{
586 										fObscuredBlitter = TRUE;
587 									}
588 									else
589 									{
590 										// Do not render if we are not on this render loop!
591 										fRenderTile = FALSE;
592 									}
593 								}
594 								else
595 								{
596 									if (uiLevelNodeFlags & LEVELNODE_SHOW_THROUGH)
597 									{
598 										fRenderTile = FALSE;
599 									}
600 								}
601 							}
602 
603 							if (fRenderTile)
604 							{
605 								// Set flag to set layer as used
606 								if (fDynamic || fPixelate)
607 								{
608 									uiAdditiveLayerUsedFlags |= uiRowFlags;
609 								}
610 
611 								if (uiLevelNodeFlags & LEVELNODE_DYNAMICZ)
612 								{
613 									fSaveZ  = TRUE;
614 									fZWrite = TRUE;
615 								}
616 
617 								if (uiLevelNodeFlags & LEVELNODE_CACHEDANITILE)
618 								{
619 									ANITILE const& a = *pNode->pAniTile;
620 									hVObject         = gpTileCache[a.sCachedTileID].pImagery->vo;
621 									usImageIndex     = a.sCurrentFrame;
622 									uiAniTileFlags   = a.uiFlags;
623 
624 									float dOffsetX;
625 									float dOffsetY;
626 									// Position corpse based on it's float position
627 									if (uiLevelNodeFlags & LEVELNODE_ROTTINGCORPSE)
628 									{
629 										pCorpse     = ID2CORPSE(a.v.user.uiData);
630 										pShadeTable = pCorpse->pShades[pNode->ubShadeLevel];
631 
632 										// OK, if this is a corpse.... stop if not visible
633 										if (pCorpse->def.bVisible != 1 && !(gTacticalStatus.uiFlags & SHOW_ALL_MERCS)) goto next_prev_node;
634 
635 										INT16 x;
636 										INT16 y;
637 										ConvertGridNoToCenterCellXY(pCorpse->def.sGridNo, &x, &y);
638 										dOffsetX = x - gsRenderCenterX;
639 										dOffsetY = y - gsRenderCenterY;
640 									}
641 									else
642 									{
643 										dOffsetX = a.sRelativeX - gsRenderCenterX;
644 										dOffsetY = a.sRelativeY - gsRenderCenterY;
645 									}
646 
647 									// Calculate guy's position
648 									float dTempX_S;
649 									float dTempY_S;
650 									FloatFromCellToScreenCoordinates(dOffsetX, dOffsetY, &dTempX_S, &dTempY_S);
651 
652 									sXPos = g_ui.m_tacticalMapCenterX + (INT16)dTempX_S;
653 									sYPos = g_ui.m_tacticalMapCenterY + (INT16)dTempY_S - sTileHeight;
654 
655 									// Adjust for offset position on screen
656 									sXPos -= gsRenderWorldOffsetX;
657 									sYPos -= gsRenderWorldOffsetY;
658 								}
659 								else
660 								{
661 									hVObject     = TileElem->hTileSurface;
662 									usImageIndex = TileElem->usRegionIndex;
663 
664 									if (TileElem->uiFlags & IGNORE_WORLD_HEIGHT)
665 									{
666 										sYPos -= sModifiedTileHeight;
667 									}
668 									else if (!(uiLevelNodeFlags & LEVELNODE_IGNOREHEIGHT))
669 									{
670 										sYPos -= sTileHeight;
671 									}
672 
673 									if (!(uiFlags & TILES_DIRTY))
674 									{
675 										hVObject->CurrentShade(pNode->ubShadeLevel);
676 									}
677 								}
678 
679 
680 								//ADJUST FOR RELATIVE OFFSETS
681 								if (uiLevelNodeFlags & LEVELNODE_USERELPOS)
682 								{
683 									sXPos += pNode->sRelativeX;
684 									sYPos += pNode->sRelativeY;
685 								}
686 
687 								if (uiLevelNodeFlags & LEVELNODE_USEZ)
688 								{
689 									sYPos -= pNode->sRelativeZ;
690 								}
691 
692 								//ADJUST FOR ABSOLUTE POSITIONING
693 								if (uiLevelNodeFlags & LEVELNODE_USEABSOLUTEPOS)
694 								{
695 									float dOffsetX = pNode->sRelativeX - gsRenderCenterX;
696 									float dOffsetY = pNode->sRelativeY - gsRenderCenterY;
697 
698 									// OK, DONT'T ASK... CONVERSION TO PROPER Y NEEDS THIS...
699 									dOffsetX -= CELL_Y_SIZE;
700 
701 									float dTempX_S;
702 									float dTempY_S;
703 									FloatFromCellToScreenCoordinates(dOffsetX, dOffsetY, &dTempX_S, &dTempY_S);
704 
705 									sXPos = g_ui.m_tacticalMapCenterX + (INT16)dTempX_S;
706 									sYPos = g_ui.m_tacticalMapCenterY + (INT16)dTempY_S;
707 
708 									// Adjust for offset position on screen
709 									sXPos -= gsRenderWorldOffsetX;
710 									sYPos -= gsRenderWorldOffsetY;
711 
712 									sYPos -= pNode->sRelativeZ;
713 								}
714 							}
715 
716 							// COUNT # OF ITEMS AT THIS LOCATION
717 							if (uiLevelNodeFlags & LEVELNODE_ITEM)
718 							{
719 								// Set item pool for this location.
720 								item_pool = item_pool ? item_pool->pNext : pNode->pItemPool;
721 								WORLDITEM const& wi = GetWorldItem(item_pool->iItemIndex);
722 
723 								/* Limit rendering of items to MAX_RENDERED_ITEMS. Do not render
724 								 * hidden items either. */
725 								if (wi.bVisible != VISIBLE             ||
726 										wi.usFlags & WORLD_ITEM_DONTRENDER ||
727 										n_visible_items == MAX_RENDERED_ITEMS)
728 								{
729 									if (!(gTacticalStatus.uiFlags & SHOW_ALL_ITEMS)) goto next_prev_node;
730 								}
731 								++n_visible_items;
732 
733 								if (wi.bRenderZHeightAboveLevel > 0)
734 								{
735 									sYPos -= wi.bRenderZHeightAboveLevel;
736 								}
737 							}
738 
739 							// If render tile is false...
740 							if (!fRenderTile) goto next_prev_node;
741 						}
742 
743 						// specific code for node types on a per-tile basis
744 						switch (uiRowFlags)
745 						{
746 							case TILES_STATIC_LAND:
747 								goto zlevel_land;
748 
749 							case TILES_STATIC_OBJECTS:
750 								// ATE: Modified to use constant z level, as these are same level as land items
751 								goto zlevel_objects;
752 
753 							case TILES_STATIC_SHADOWS:
754 								if (uiLevelNodeFlags & LEVELNODE_EXITGRID)
755 								{
756 									fIntensityBlitter = TRUE;
757 									fShadowBlitter    = FALSE;
758 								}
759 								goto zlevel_shadows;
760 
761 							case TILES_STATIC_STRUCTURES:
762 								if (TileElem)
763 								{
764 									if (TileElem->uiFlags & MULTI_Z_TILE) fMultiZBlitter = TRUE;
765 									if (TileElem->uiFlags & WALL_TILE)    fWallTile      = TRUE;
766 								}
767 								goto zlevel_structures;
768 
769 							case TILES_STATIC_ROOF:
770 								// ATE: Added for shadows on roofs
771 								if (TileElem && TileElem->uiFlags & ROOFSHADOW_TILE)
772 								{
773 									fShadowBlitter = TRUE;
774 								}
775 								goto zlevel_roof;
776 
777 							case TILES_STATIC_ONROOF:
778 								goto zlevel_onroof;
779 
780 							case TILES_STATIC_TOPMOST:
781 								goto zlevel_topmost;
782 
783 							case TILES_DYNAMIC_LAND:
784 								uiDirtyFlags = BGND_FLAG_SINGLE | BGND_FLAG_ANIMATED;
785 zlevel_land:
786 								sZLevel = LAND_Z_LEVEL;
787 								break;
788 
789 							case TILES_DYNAMIC_OBJECTS:
790 								uiDirtyFlags = BGND_FLAG_SINGLE | BGND_FLAG_ANIMATED;
791 zlevel_objects:
792 								if (uiTileElemFlags & CLIFFHANG_TILE)
793 								{
794 									sZLevel = LAND_Z_LEVEL;
795 								}
796 								else if (uiTileElemFlags & OBJECTLAYER_USEZHEIGHT)
797 								{
798 									INT16 const world_y = GetMapXYWorldY(iTempPosX_M, iTempPosY_M);
799 									sZLevel = (world_y * Z_SUBLAYERS) + LAND_Z_LEVEL;
800 								}
801 								else
802 								{
803 									sZLevel = OBJECT_Z_LEVEL;
804 								}
805 								break;
806 
807 							case TILES_DYNAMIC_SHADOWS:
808 							{
809 								uiDirtyFlags = BGND_FLAG_SINGLE | BGND_FLAG_ANIMATED;
810 zlevel_shadows:
811 								INT16 const world_y = GetMapXYWorldY(iTempPosX_M, iTempPosY_M);
812 								sZLevel = __max(((world_y - 80) * Z_SUBLAYERS) + SHADOW_Z_LEVEL, 0);
813 								break;
814 							}
815 
816 							case TILES_DYNAMIC_STRUCTURES:
817 							{
818 								uiDirtyFlags = BGND_FLAG_SINGLE | BGND_FLAG_ANIMATED;
819 zlevel_structures:
820 								INT16 world_y = GetMapXYWorldY(iTempPosX_M, iTempPosY_M);
821 								if (uiLevelNodeFlags & LEVELNODE_ROTTINGCORPSE)
822 								{
823 									if (pCorpse->def.usFlags & ROTTING_CORPSE_VEHICLE)
824 									{
825 										if (pNode->pStructureData)
826 										{
827 											DB_STRUCTURE const& dbs = *pNode->pStructureData->pDBStructureRef->pDBStructure;
828 											sZOffsetX = dbs.bZTileOffsetX;
829 											sZOffsetY = dbs.bZTileOffsetY;
830 										}
831 										world_y = GetMapXYWorldY(iTempPosX_M + sZOffsetX, iTempPosY_M + sZOffsetY);
832 										sZLevel = STRUCT_Z_LEVEL;
833 									}
834 									else
835 									{
836 										sZOffsetX = -1;
837 										sZOffsetY = -1;
838 										world_y   = GetMapXYWorldY(iTempPosX_M + sZOffsetX, iTempPosY_M + sZOffsetY);
839 										world_y  += 20;
840 										sZLevel   = LAND_Z_LEVEL;
841 									}
842 								}
843 								else if (uiLevelNodeFlags & LEVELNODE_PHYSICSOBJECT)
844 								{
845 									world_y += pNode->sRelativeZ;
846 									sZLevel  = ONROOF_Z_LEVEL;
847 								}
848 								else if (uiLevelNodeFlags & LEVELNODE_ITEM)
849 								{
850 									WORLDITEM const& wi = GetWorldItem(pNode->pItemPool->iItemIndex);
851 									if (wi.bRenderZHeightAboveLevel > 0)
852 									{
853 										sZLevel  = STRUCT_Z_LEVEL + wi.bRenderZHeightAboveLevel;
854 									}
855 									else
856 									{
857 										sZLevel = OBJECT_Z_LEVEL;
858 									}
859 								}
860 								else if (uiAniTileFlags & ANITILE_SMOKE_EFFECT)
861 								{
862 									sZLevel = OBJECT_Z_LEVEL;
863 								}
864 								else if (uiLevelNodeFlags & LEVELNODE_USEZ)
865 								{
866 									if (uiLevelNodeFlags & LEVELNODE_NOZBLITTER)
867 									{
868 										world_y += 40;
869 									}
870 									else
871 									{
872 										world_y += pNode->sRelativeZ;
873 									}
874 									sZLevel = ONROOF_Z_LEVEL;
875 								}
876 								else
877 								{
878 									sZLevel = STRUCT_Z_LEVEL;
879 								}
880 								sZLevel += world_y * Z_SUBLAYERS;
881 								break;
882 							}
883 
884 							case TILES_DYNAMIC_ROOF:
885 							{
886 								uiDirtyFlags = BGND_FLAG_SINGLE | BGND_FLAG_ANIMATED;
887 zlevel_roof:
888 								// Automatically adjust height.
889 								sYPos -= WALL_HEIGHT;
890 
891 								INT16 const world_y = WALL_HEIGHT + GetMapXYWorldY(iTempPosX_M, iTempPosY_M);
892 								sZLevel = (world_y * Z_SUBLAYERS) + ROOF_Z_LEVEL;
893 								break;
894 							}
895 
896 							case TILES_DYNAMIC_ONROOF:
897 							{
898 								uiDirtyFlags = BGND_FLAG_SINGLE | BGND_FLAG_ANIMATED;
899 zlevel_onroof:
900 								// Automatically adjust height.
901 								sYPos -= WALL_HEIGHT;
902 
903 								INT16 world_y = GetMapXYWorldY(iTempPosX_M, iTempPosY_M);
904 								if (uiLevelNodeFlags & LEVELNODE_ROTTINGCORPSE)
905 								{
906 									world_y += WALL_HEIGHT + 40;
907 								}
908 								if (uiLevelNodeFlags & LEVELNODE_ROTTINGCORPSE)
909 								{ // XXX duplicate?
910 									world_y += WALL_HEIGHT + 40;
911 								}
912 								else
913 								{
914 									world_y += WALL_HEIGHT;
915 								}
916 								sZLevel = (world_y * Z_SUBLAYERS) + ONROOF_Z_LEVEL;
917 								break;
918 							}
919 
920 							case TILES_DYNAMIC_TOPMOST:
921 								uiDirtyFlags = BGND_FLAG_SINGLE | BGND_FLAG_ANIMATED;
922 zlevel_topmost:
923 								sZLevel = TOPMOST_Z_LEVEL;
924 								break;
925 
926 							case TILES_DYNAMIC_MERCS:
927 							case TILES_DYNAMIC_HIGHMERCS:
928 							case TILES_DYNAMIC_STRUCT_MERCS:
929 							{
930 								// Set flag to set layer as used
931 								uiAdditiveLayerUsedFlags |= uiRowFlags;
932 
933 								SOLDIERTYPE const& s = *pNode->pSoldier;
934 								switch (uiRowFlags)
935 								{
936 									case TILES_DYNAMIC_MERCS:
937 										// If we are multi-tiled, ignore here
938 										if (s.uiStatusFlags & SOLDIER_MULTITILE) goto next_node;
939 										// If we are at a higher level, no not do anything unless we are at the highmerc stage
940 										if (s.bLevel > 0) goto next_node;
941 										break;
942 
943 									case TILES_DYNAMIC_HIGHMERCS:
944 										// If we are multi-tiled, ignore here
945 										if (s.uiStatusFlags & SOLDIER_MULTITILE) goto next_node;
946 										// If we are at a lower level, no not do anything unless we are at the highmerc stage
947 										if (s.bLevel == 0) goto next_node;
948 										break;
949 
950 									case TILES_DYNAMIC_STRUCT_MERCS:
951 										// If we are not multi-tiled, ignore here
952 										if (!(s.uiStatusFlags & SOLDIER_MULTITILE))
953 										{
954 											// If we are at a low level, no not do anything unless we are at the merc stage
955 											if (s.bLevel == 0) goto next_node;
956 										}
957 										else
958 										{
959 											fSaveZ                    = TRUE;
960 											fMultiTransShadowZBlitter = TRUE;
961 											fZBlitter                 = TRUE;
962 
963 											// ATE: Use one direction for queen!
964 											sMultiTransShadowZBlitterIndex =
965 												s.ubBodyType == QUEENMONSTER ? 0 :
966 												OneCDirection(s.bDirection);
967 										}
968 										break;
969 									default:
970 										break;
971 								}
972 
973 								// IF we are not active, or are a placeholder for multi-tile animations do nothing
974 								if (!s.bActive || uiLevelNodeFlags & LEVELNODE_MERCPLACEHOLDER) goto next_node;
975 
976 								// Skip if we cannot see the guy!
977 								if (s.bLastRenderVisibleValue == -1 && !(gTacticalStatus.uiFlags & SHOW_ALL_MERCS)) goto next_node;
978 
979 								// Get animation surface....
980 								UINT16 const usAnimSurface = GetSoldierAnimationSurface(&s);
981 								if (usAnimSurface == INVALID_ANIMATION_SURFACE) goto next_node;
982 
983 								// Shade guy always lighter than sceane default!
984 								UINT8 ubShadeLevel;
985 								if (s.fBeginFade)
986 								{
987 									ubShadeLevel = s.ubFadeLevel;
988 								}
989 								else
990 								{
991 									ubShadeLevel  = pNode->ubShadeLevel & 0x0f;
992 									ubShadeLevel  = __max(ubShadeLevel - 2, DEFAULT_SHADE_LEVEL);
993 									ubShadeLevel |= pNode->ubShadeLevel & 0x30;
994 								}
995 								pShadeTable = s.pShades[ubShadeLevel];
996 
997 								// Position guy based on guy's position
998 								float const dOffsetX = s.dXPos - gsRenderCenterX;
999 								float const dOffsetY = s.dYPos - gsRenderCenterY;
1000 
1001 								// Calculate guy's position
1002 								float dTempX_S;
1003 								float dTempY_S;
1004 								FloatFromCellToScreenCoordinates(dOffsetX, dOffsetY, &dTempX_S, &dTempY_S);
1005 
1006 								sXPos = g_ui.m_tacticalMapCenterX + (INT16)dTempX_S;
1007 								sYPos = g_ui.m_tacticalMapCenterY + (INT16)dTempY_S - sTileHeight;
1008 
1009 								// Adjust for offset position on screen
1010 								sXPos -= gsRenderWorldOffsetX;
1011 								sYPos -= gsRenderWorldOffsetY;
1012 
1013 								// Adjust for soldier height
1014 								sYPos -= s.sHeightAdjustment;
1015 
1016 								// Handle shade stuff....
1017 								if (!s.fBeginFade)
1018 								{
1019 									// Special effect - draw ghost if is seen by a guy in player's team but not current guy
1020 									// ATE: Todo: setup flag for 'bad-guy' - can releive some checks in renderer
1021 									if (!s.bNeutral && s.bSide != OUR_TEAM)
1022 									{
1023 										INT8 bGlowShadeOffset = 0;
1024 
1025 										if (gTacticalStatus.ubCurrentTeam == OUR_TEAM)
1026 										{
1027 											// Shade differently depending on visiblity
1028 											if (s.bLastRenderVisibleValue == 0)
1029 											{
1030 												bGlowShadeOffset = 10;
1031 											}
1032 
1033 											const SOLDIERTYPE* const sel = GetSelectedMan();
1034 											if (sel                                       &&
1035 													sel->bOppList[s.ubID] != SEEN_CURRENTLY   &&
1036 													s.usAnimState         != CHARIOTS_OF_FIRE &&
1037 													s.usAnimState         != BODYEXPLODING)
1038 											{
1039 												bGlowShadeOffset = 10;
1040 											}
1041 										}
1042 
1043 										UINT16* const* pShadeStart =
1044 											s.bLevel == 0 ? &s.pGlowShades[0] : &s.pShades[20];
1045 
1046 										// Set shade
1047 										// If a bad guy is highlighted
1048 										if (gSelectedGuy != NULL && gSelectedGuy->bSide != OUR_TEAM)
1049 										{
1050 											if (gSelectedGuy == &s)
1051 											{
1052 												pShadeTable = pShadeStart[gsGlowFrames[gsCurrentGlowFrame] + bGlowShadeOffset];
1053 												gsForceSoldierZLevel = TOPMOST_Z_LEVEL;
1054 											}
1055 											else
1056 											{
1057 												// Are we dealing with a not-so visible merc?
1058 												if (bGlowShadeOffset == 10)
1059 												{
1060 													pShadeTable = s.effect_shade;
1061 												}
1062 											}
1063 										}
1064 										else
1065 										{
1066 											// Not highlighted, but maybe we are in enemy's turn and they have the baton
1067 											if (gTacticalStatus.ubCurrentTeam == OUR_TEAM ||
1068 													s.uiStatusFlags & SOLDIER_UNDERAICONTROL) // Does he have baton?
1069 											{
1070 												pShadeTable = pShadeStart[gsGlowFrames[gsCurrentGlowFrame] + bGlowShadeOffset];
1071 												if (gsGlowFrames[gsCurrentGlowFrame] >= 7)
1072 												{
1073 													gsForceSoldierZLevel = TOPMOST_Z_LEVEL;
1074 												}
1075 											}
1076 										}
1077 									}
1078 								}
1079 
1080 								{ // Calculate Z level
1081 									INT16 world_y;
1082 									if (s.uiStatusFlags & SOLDIER_MULTITILE)
1083 									{
1084 										if (pNode->pStructureData)
1085 										{
1086 											DB_STRUCTURE const& dbs = *pNode->pStructureData->pDBStructureRef->pDBStructure;
1087 											sZOffsetX = dbs.bZTileOffsetX;
1088 											sZOffsetY = dbs.bZTileOffsetY;
1089 										}
1090 										world_y = GetMapXYWorldY(iTempPosX_M + sZOffsetX, iTempPosY_M + sZOffsetY);
1091 									}
1092 									else
1093 									{
1094 										world_y = GetMapXYWorldY(iTempPosX_M, iTempPosY_M);
1095 									}
1096 
1097 									if (s.uiStatusFlags & SOLDIER_VEHICLE)
1098 									{
1099 										sZLevel = (world_y * Z_SUBLAYERS) + STRUCT_Z_LEVEL;
1100 									}
1101 									else if (gsForceSoldierZLevel != 0)
1102 									{
1103 										sZLevel = gsForceSoldierZLevel;
1104 									}
1105 									else if (s.sZLevelOverride != -1)
1106 									{
1107 										sZLevel = s.sZLevelOverride;
1108 									}
1109 									else if (s.dHeightAdjustment > 0)
1110 									{
1111 										world_y += WALL_HEIGHT + 20;
1112 										sZLevel = (world_y * Z_SUBLAYERS) + ONROOF_Z_LEVEL;
1113 									}
1114 									else
1115 									{
1116 										sZLevel = (world_y * Z_SUBLAYERS) + MERC_Z_LEVEL;
1117 									}
1118 								}
1119 
1120 								if (!(uiFlags & TILES_DIRTY) && s.fForceShade)
1121 								{
1122 									pShadeTable = s.pForcedShade;
1123 								}
1124 
1125 								hVObject = gAnimSurfaceDatabase[usAnimSurface].hVideoObject;
1126 								if (!hVObject) goto next_node;
1127 
1128 								// ATE: If we are in a gridno that we should not use obscure blitter, set!
1129 								if (!(me.ubExtFlags[0] & MAPELEMENT_EXT_NOBURN_STRUCT))
1130 								{
1131 									fObscuredBlitter = TRUE;
1132 								}
1133 								else
1134 								{
1135 									// ATE: Artificially increase z-level...
1136 									sZLevel += 2;
1137 								}
1138 
1139 								usImageIndex = s.usAniFrame;
1140 
1141 								uiDirtyFlags = BGND_FLAG_SINGLE | BGND_FLAG_ANIMATED;
1142 								break;
1143 							}
1144 							default:
1145 								break;
1146 						}
1147 
1148 						// Adjust for interface level
1149 						sYPos += gsRenderHeight;
1150 
1151 						if (!fRenderTile) goto next_prev_node;
1152 
1153 						if (uiLevelNodeFlags & LEVELNODE_HIDDEN &&
1154 								/* If it is a roof and SHOW_ALL_ROOFS is on, turn off hidden tile check */
1155 								(!TileElem || !(TileElem->uiFlags & ROOF_TILE) || !(gTacticalStatus.uiFlags & SHOW_ALL_ROOFS)))
1156 							goto next_prev_node;
1157 
1158 						if (uiLevelNodeFlags & LEVELNODE_ROTTINGCORPSE)
1159 						{
1160 							// Set fmerc flag!
1161 							fMerc = TRUE;
1162 							fZWrite = TRUE;
1163 
1164 							sMultiTransShadowZBlitterIndex = GetCorpseStructIndex(&pCorpse->def, TRUE);
1165 							fMultiTransShadowZBlitter      = TRUE;
1166 						}
1167 
1168 						if (uiLevelNodeFlags & LEVELNODE_LASTDYNAMIC && !(uiFlags & TILES_DIRTY))
1169 						{
1170 							// Remove flags!
1171 							pNode->uiFlags &= ~LEVELNODE_LASTDYNAMIC;
1172 							fZWrite = TRUE;
1173 						}
1174 
1175 						// RENDER
1176 						if (uiLevelNodeFlags & LEVELNODE_WIREFRAME &&
1177 								!gGameSettings.fOptions[TOPTION_TOGGLE_WIREFRAME])
1178 						{
1179 						}
1180 						else if (uiFlags & TILES_DIRTY)
1181 						{
1182 							if (!(uiLevelNodeFlags & LEVELNODE_LASTDYNAMIC))
1183 							{
1184 								ETRLEObject const& pTrav = hVObject->SubregionProperties(usImageIndex);
1185 								UINT32 const uiBrushHeight = pTrav.usHeight;
1186 								UINT32 const uiBrushWidth  = pTrav.usWidth;
1187 								sXPos += pTrav.sOffsetX;
1188 								sYPos += pTrav.sOffsetY;
1189 
1190 								INT16 const h = MIN((INT16)uiBrushHeight, gsVIEWPORT_WINDOW_END_Y - sYPos);
1191 								RegisterBackgroundRect(uiDirtyFlags, sXPos, sYPos, uiBrushWidth, h);
1192 								if (fSaveZ)
1193 								{
1194 									RegisterBackgroundRect(uiDirtyFlags | BGND_FLAG_SAVE_Z, sXPos, sYPos, uiBrushWidth, h);
1195 								}
1196 							}
1197 						}
1198 						else if (uiLevelNodeFlags & LEVELNODE_DISPLAY_AP)
1199 						{
1200 							ETRLEObject const& pTrav = hVObject->SubregionProperties(usImageIndex);
1201 							sXPos += pTrav.sOffsetX;
1202 							sYPos += pTrav.sOffsetY;
1203 
1204 							UINT8 const foreground = gfUIDisplayActionPointsBlack ? FONT_MCOLOR_BLACK : FONT_MCOLOR_WHITE;
1205 							SetFontAttributes(TINYFONT1, foreground);
1206 							SetFontDestBuffer(guiSAVEBUFFER, 0, gsVIEWPORT_WINDOW_START_Y, SCREEN_WIDTH, gsVIEWPORT_WINDOW_END_Y);
1207 							ST::string buf = ST::format("{}", pNode->uiAPCost);
1208 							INT16 sX;
1209 							INT16 sY;
1210 							FindFontCenterCoordinates(sXPos, sYPos, 1, 1, buf, TINYFONT1, &sX, &sY);
1211 							MPrintBuffer(pDestBuf, uiDestPitchBYTES, sX, sY, buf);
1212 							SetFontDestBuffer(FRAME_BUFFER);
1213 						}
1214 						else if (uiLevelNodeFlags & LEVELNODE_ITEM)
1215 						{
1216 							UINT16     outline_colour;
1217 							bool const on_roof = uiRowFlags == TILES_STATIC_ONROOF || uiRowFlags == TILES_DYNAMIC_ONROOF;
1218 							if (gGameSettings.fOptions[TOPTION_GLOW_ITEMS])
1219 							{
1220 								UINT16 const *palette =
1221 									on_roof                                    ? us16BPPItemCycleYellowColors :
1222 									gTacticalStatus.uiFlags & RED_ITEM_GLOW_ON ? us16BPPItemCycleRedColors    :
1223 									us16BPPItemCycleWhiteColors;
1224 								outline_colour = palette[gsCurrentItemGlowFrame];
1225 							}
1226 							else
1227 							{
1228 								outline_colour =
1229 									on_roof ? gusYellowItemOutlineColor :
1230 									gusNormalItemOutlineColor;
1231 							}
1232 
1233 							const BOOLEAN bBlitClipVal = BltIsClippedOrOffScreen(hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1234 							if (bBlitClipVal == FALSE)
1235 							{
1236 								if (fObscuredBlitter)
1237 								{
1238 									Blt8BPPDataTo16BPPBufferOutlineZPixelateObscured(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, outline_colour);
1239 								}
1240 								else
1241 								{
1242 									Blt8BPPDataTo16BPPBufferOutlineZ(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, outline_colour);
1243 								}
1244 							}
1245 							else if (bBlitClipVal == TRUE)
1246 							{
1247 								if (fObscuredBlitter)
1248 								{
1249 									Blt8BPPDataTo16BPPBufferOutlineZPixelateObscuredClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, outline_colour, &gClippingRect);
1250 								}
1251 								else
1252 								{
1253 									Blt8BPPDataTo16BPPBufferOutlineZClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, outline_colour, &gClippingRect);
1254 								}
1255 							}
1256 						}
1257 						// ATE: Check here for a lot of conditions!
1258 						else if (uiLevelNodeFlags & LEVELNODE_PHYSICSOBJECT)
1259 						{
1260 							const BOOLEAN bBlitClipVal = BltIsClippedOrOffScreen(hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1261 
1262 							if (fShadowBlitter)
1263 							{
1264 								if (bBlitClipVal == FALSE)
1265 								{
1266 									Blt8BPPDataTo16BPPBufferShadowZNB(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1267 								}
1268 								else
1269 								{
1270 									Blt8BPPDataTo16BPPBufferShadowZNBClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1271 								}
1272 							}
1273 							else
1274 							{
1275 								if (bBlitClipVal == FALSE)
1276 								{
1277 									Blt8BPPDataTo16BPPBufferOutlineZNB(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1278 								}
1279 								else if (bBlitClipVal == TRUE)
1280 								{
1281 									Blt8BPPDataTo16BPPBufferOutlineClip(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex, SGP_TRANSPARENT, &gClippingRect);
1282 								}
1283 							}
1284 						}
1285 						else
1286 						{
1287 							if (fMultiTransShadowZBlitter)
1288 							{
1289 								if (fZBlitter)
1290 								{
1291 									if (fObscuredBlitter)
1292 									{
1293 										Blt8BPPDataTo16BPPBufferTransZTransShadowIncObscureClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect, sMultiTransShadowZBlitterIndex, pShadeTable);
1294 									}
1295 									else
1296 									{
1297 										Blt8BPPDataTo16BPPBufferTransZTransShadowIncClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect, sMultiTransShadowZBlitterIndex, pShadeTable);
1298 									}
1299 								}
1300 							}
1301 							else if (fMultiZBlitter)
1302 							{
1303 								if (fZBlitter)
1304 								{
1305 									if (fObscuredBlitter)
1306 									{
1307 										Blt8BPPDataTo16BPPBufferTransZIncObscureClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1308 									}
1309 									else
1310 									{
1311 										if (fWallTile)
1312 										{
1313 											Blt8BPPDataTo16BPPBufferTransZIncClipZSameZBurnsThrough(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1314 										}
1315 										else
1316 										{
1317 											Blt8BPPDataTo16BPPBufferTransZIncClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1318 										}
1319 									}
1320 								}
1321 								else
1322 								{
1323 									Blt8BPPDataTo16BPPBufferTransparentClip(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1324 								}
1325 							}
1326 							else
1327 							{
1328 								const BOOLEAN bBlitClipVal = BltIsClippedOrOffScreen(hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1329 								if (bBlitClipVal == TRUE)
1330 								{
1331 									if (fPixelate)
1332 									{
1333 										Blt8BPPDataTo16BPPBufferTransZNBClipTranslucent(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1334 									}
1335 									else if (fMerc)
1336 									{
1337 										if (fZBlitter)
1338 										{
1339 											if (fZWrite)
1340 											{
1341 												Blt8BPPDataTo16BPPBufferTransShadowZClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect, pShadeTable);
1342 											}
1343 											else
1344 											{
1345 												if (fObscuredBlitter)
1346 												{
1347 													Blt8BPPDataTo16BPPBufferTransShadowZNBObscuredClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect, pShadeTable);
1348 												}
1349 												else
1350 												{
1351 													Blt8BPPDataTo16BPPBufferTransShadowZNBClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect, pShadeTable);
1352 												}
1353 											}
1354 
1355 											if (uiLevelNodeFlags & LEVELNODE_UPDATESAVEBUFFERONCE)
1356 											{
1357 												SGPVSurface::Lock l(guiSAVEBUFFER);
1358 
1359 												// BLIT HERE
1360 												Blt8BPPDataTo16BPPBufferTransShadowClip(l.Buffer<UINT16>(), l.Pitch(), hVObject, sXPos, sYPos, usImageIndex, &gClippingRect, pShadeTable);
1361 
1362 												// Turn it off!
1363 												pNode->uiFlags &= ~LEVELNODE_UPDATESAVEBUFFERONCE;
1364 											}
1365 										}
1366 										else
1367 										{
1368 											Blt8BPPDataTo16BPPBufferTransShadowClip(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect, pShadeTable);
1369 										}
1370 									}
1371 									else if (fShadowBlitter)
1372 									{
1373 										if (fZBlitter)
1374 										{
1375 											if (fZWrite)
1376 											{
1377 												Blt8BPPDataTo16BPPBufferShadowZClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1378 											}
1379 											else
1380 											{
1381 												Blt8BPPDataTo16BPPBufferShadowZClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1382 											}
1383 										}
1384 										else
1385 										{
1386 											Blt8BPPDataTo16BPPBufferShadowClip(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1387 										}
1388 									}
1389 									else if (fIntensityBlitter)
1390 									{
1391 										if (fZBlitter)
1392 										{
1393 											if (fZWrite)
1394 											{
1395 												Blt8BPPDataTo16BPPBufferIntensityZClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1396 											}
1397 											else
1398 											{
1399 												Blt8BPPDataTo16BPPBufferIntensityZClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1400 											}
1401 										}
1402 										else
1403 										{
1404 											Blt8BPPDataTo16BPPBufferIntensityClip(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1405 										}
1406 									}
1407 									else if (fZBlitter)
1408 									{
1409 										if (fZWrite)
1410 										{
1411 											if (fObscuredBlitter)
1412 											{
1413 												Blt8BPPDataTo16BPPBufferTransZClipPixelateObscured(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1414 											}
1415 											else
1416 											{
1417 												Blt8BPPDataTo16BPPBufferTransZClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1418 											}
1419 										}
1420 										else
1421 										{
1422 											Blt8BPPDataTo16BPPBufferTransZNBClip(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1423 										}
1424 
1425 										if (uiLevelNodeFlags & LEVELNODE_UPDATESAVEBUFFERONCE)
1426 										{
1427 											SGPVSurface::Lock l(guiSAVEBUFFER);
1428 
1429 											// BLIT HERE
1430 											Blt8BPPDataTo16BPPBufferTransZClip(l.Buffer<UINT16>(), l.Pitch(), gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1431 
1432 											// Turn it off!
1433 											pNode->uiFlags &= ~LEVELNODE_UPDATESAVEBUFFERONCE;
1434 										}
1435 									}
1436 									else
1437 									{
1438 										Blt8BPPDataTo16BPPBufferTransparentClip(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex, &gClippingRect);
1439 									}
1440 								}
1441 								else if (bBlitClipVal == FALSE)
1442 								{
1443 									if (fPixelate)
1444 									{
1445 										if (fZWrite)
1446 										{
1447 											Blt8BPPDataTo16BPPBufferTransZTranslucent(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1448 										}
1449 										else
1450 										{
1451 											Blt8BPPDataTo16BPPBufferTransZNBTranslucent(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1452 										}
1453 									}
1454 									else if (fMerc)
1455 									{
1456 										if (fZBlitter)
1457 										{
1458 											if (fZWrite)
1459 											{
1460 												Blt8BPPDataTo16BPPBufferTransShadowZ(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, pShadeTable);
1461 											}
1462 											else
1463 											{
1464 												if (fObscuredBlitter)
1465 												{
1466 													Blt8BPPDataTo16BPPBufferTransShadowZNBObscured(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, pShadeTable);
1467 												}
1468 												else
1469 												{
1470 													Blt8BPPDataTo16BPPBufferTransShadowZNB(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex, pShadeTable);
1471 												}
1472 											}
1473 
1474 											if (uiLevelNodeFlags & LEVELNODE_UPDATESAVEBUFFERONCE)
1475 											{
1476 												SGPVSurface::Lock l(guiSAVEBUFFER);
1477 
1478 												// BLIT HERE
1479 												Blt8BPPDataTo16BPPBufferTransShadow(l.Buffer<UINT16>(), l.Pitch(), hVObject, sXPos, sYPos, usImageIndex, pShadeTable);
1480 
1481 												// Turn it off!
1482 												pNode->uiFlags &= ~LEVELNODE_UPDATESAVEBUFFERONCE;
1483 											}
1484 										}
1485 										else
1486 										{
1487 											Blt8BPPDataTo16BPPBufferTransShadow(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex, pShadeTable);
1488 										}
1489 									}
1490 									else if (fShadowBlitter)
1491 									{
1492 										if (fZBlitter)
1493 										{
1494 											if (fZWrite)
1495 											{
1496 												Blt8BPPDataTo16BPPBufferShadowZ(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1497 											}
1498 											else
1499 											{
1500 												Blt8BPPDataTo16BPPBufferShadowZNB(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1501 											}
1502 										}
1503 										else
1504 										{
1505 											Blt8BPPDataTo16BPPBufferShadow(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex);
1506 										}
1507 									}
1508 									else if (fIntensityBlitter)
1509 									{
1510 										if (fZBlitter)
1511 										{
1512 											if (fZWrite)
1513 											{
1514 												Blt8BPPDataTo16BPPBufferIntensityZ(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1515 											}
1516 											else
1517 											{
1518 												Blt8BPPDataTo16BPPBufferIntensityZNB(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1519 											}
1520 										}
1521 										else
1522 										{
1523 											Blt8BPPDataTo16BPPBufferIntensity(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex);
1524 										}
1525 									}
1526 									else if (fZBlitter)
1527 									{
1528 										if (fZWrite)
1529 										{
1530 											if (fObscuredBlitter)
1531 											{
1532 												Blt8BPPDataTo16BPPBufferTransZPixelateObscured(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1533 											}
1534 											else
1535 											{
1536 												Blt8BPPDataTo16BPPBufferTransZ(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1537 											}
1538 										}
1539 										else
1540 										{
1541 											Blt8BPPDataTo16BPPBufferTransZNB(pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1542 										}
1543 
1544 										if (uiLevelNodeFlags & LEVELNODE_UPDATESAVEBUFFERONCE)
1545 										{
1546 											SGPVSurface::Lock l(guiSAVEBUFFER);
1547 
1548 											// BLIT HERE
1549 											Blt8BPPDataTo16BPPBufferTransZ(l.Buffer<UINT16>(), l.Pitch(), gpZBuffer, sZLevel, hVObject, sXPos, sYPos, usImageIndex);
1550 
1551 											// Turn it off!
1552 											pNode->uiFlags &= ~LEVELNODE_UPDATESAVEBUFFERONCE;
1553 										}
1554 
1555 									}
1556 									else
1557 									{
1558 										Blt8BPPDataTo16BPPBufferTransparent(pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex);
1559 									}
1560 								}
1561 							}
1562 						}
1563 
1564 next_prev_node:
1565 						if (fLinkedListDirection)
1566 						{
1567 next_node:
1568 							pNode = pNode->pNext;
1569 						}
1570 						else
1571 						{
1572 							pNode = pNode->pPrevNode;
1573 						}
1574 					}
1575 				}
1576 				else
1577 				{
1578 					if (gfEditMode)
1579 					{
1580 						// ATE: Used here in the editor to denote when an area is not in the world
1581 						/* Kris:  Fixed a couple things here...
1582 						 * It seems that scrolling to the bottom right hand corner of the
1583 						 * map, would cause the end of the world to be drawn.  Now, this
1584 						 * would only crash on my computer and not Emmons, so this should
1585 						 * work.  Also, I changed the color from fluorescent green to
1586 						 * black, which is easier on the eyes, and prevent the drawing of
1587 						 * the end of the world if it would be drawn on the editor's
1588 						 * taskbar. */
1589 						if (iTempPosY_S < 360)
1590 						{
1591 							ColorFillVideoSurfaceArea(FRAME_BUFFER, iTempPosX_S, iTempPosY_S, iTempPosX_S + 40, MIN(iTempPosY_S + 20, 360), Get16BPPColor(FROMRGB(0, 0, 0)));
1592 						}
1593 					}
1594 				}
1595 
1596 next_tile:
1597 				iTempPosX_S += 40;
1598 				iTempPosX_M++;
1599 				iTempPosY_M--;
1600 			} while (iTempPosX_S < iEndXS);
1601 		}
1602 
1603 		if (bXOddFlag)
1604 		{
1605 			iAnchorPosY_M++;
1606 		}
1607 		else
1608 		{
1609 			iAnchorPosX_M++;
1610 		}
1611 
1612 		bXOddFlag = !bXOddFlag;
1613 		iAnchorPosY_S += 10;
1614 	}
1615 	while (iAnchorPosY_S < iEndYS);
1616 
1617 	if (uiFlags & TILES_DYNAMIC_CHECKFOR_INT_TILE) EndCurInteractiveTileCheck();
1618 }
1619 
1620 
1621 // memcpy's the background to the new scroll position, and renders the missing strip
1622 // via the RenderStaticWorldRect. Dynamic stuff will be updated on the next frame
1623 // by the normal render cycle
ScrollBackground(INT16 sScrollXIncrement,INT16 sScrollYIncrement)1624 static void ScrollBackground(INT16 sScrollXIncrement, INT16 sScrollYIncrement)
1625 {
1626 	if (!gfDoVideoScroll)
1627 	{
1628 		// Clear z-buffer
1629 		std::fill_n(gpZBuffer, gsVIEWPORT_END_Y * SCREEN_WIDTH, LAND_Z_LEVEL);
1630 
1631 		RenderStaticWorldRect(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_END_Y, FALSE);
1632 
1633 		FreeBackgroundRectType(BGND_FLAG_ANIMATED);
1634 	}
1635 	else
1636 	{
1637 		gsScrollXIncrement += sScrollXIncrement;
1638 		gsScrollYIncrement += sScrollYIncrement;
1639 	}
1640 }
1641 
1642 
1643 enum ScrollType {
1644 	ScrollType_Undefined,
1645 	ScrollType_Horizontal,
1646 	ScrollType_Vertical
1647 };
1648 
1649 static BOOLEAN ApplyScrolling(INT16 sTempRenderCenterX, INT16 sTempRenderCenterY, BOOLEAN fForceAdjust, BOOLEAN fCheckOnly,
1650 				ScrollType scrollType=ScrollType_Undefined);
1651 static void ClearMarkedTiles(void);
1652 static void ExamineZBufferRect(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom);
1653 static void RenderDynamicWorld(void);
1654 static void RenderMarkedWorld(void);
1655 static void RenderRoomInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS);
1656 static void RenderStaticWorld(void);
1657 
1658 
1659 // Render routine takes center X, Y and Z coordinate and gets world
1660 // Coordinates for the window from that using the following functions
1661 // For coordinate transformations
RenderWorld(void)1662 void RenderWorld(void)
1663 {
1664 	gfRenderFullThisFrame = FALSE;
1665 
1666 	// If we are testing renderer, set background to pink!
1667 	if (gTacticalStatus.uiFlags & DEBUGCLIFFS)
1668 	{
1669 		ColorFillVideoSurfaceArea(FRAME_BUFFER, 0, gsVIEWPORT_WINDOW_START_Y, SCREEN_WIDTH, gsVIEWPORT_WINDOW_END_Y, Get16BPPColor(FROMRGB(0, 255, 0)));
1670 		SetRenderFlags(RENDER_FLAG_FULL);
1671 	}
1672 
1673 	if (gTacticalStatus.uiFlags & SHOW_Z_BUFFER)
1674 	{
1675 		SetRenderFlags(RENDER_FLAG_FULL);
1676 	}
1677 
1678 	// For now here, update animated tiles
1679 	if (COUNTERDONE(ANIMATETILES))
1680 	{
1681 		RESETCOUNTER(ANIMATETILES);
1682 		for (UINT32 i = 0; i != gusNumAnimatedTiles; ++i)
1683 		{
1684 			TILE_ANIMATION_DATA& a = *gTileDatabase[gusAnimatedTiles[i]].pAnimData;
1685 			if (++a.bCurrentFrame >= a.ubNumFrames) a.bCurrentFrame = 0;
1686 		}
1687 	}
1688 
1689 	// HERE, UPDATE GLOW INDEX
1690 	if (COUNTERDONE(GLOW_ENEMYS))
1691 	{
1692 		RESETCOUNTER(GLOW_ENEMYS);
1693 		gsCurrentGlowFrame     = (gsCurrentGlowFrame     + 1) % lengthof(gsGlowFrames);
1694 		gsCurrentItemGlowFrame = (gsCurrentItemGlowFrame + 1) % NUM_ITEM_CYCLE_COLORS;
1695 	}
1696 
1697 	if (gRenderFlags & RENDER_FLAG_FULL)
1698 	{
1699 		gfRenderFullThisFrame = TRUE;
1700 		gfTopMessageDirty     = TRUE;
1701 
1702 		// Dirty the interface...
1703 		fInterfacePanelDirty = DIRTYLEVEL2;
1704 
1705 		// Apply scrolling sets some world variables
1706 		ApplyScrolling(gsRenderCenterX, gsRenderCenterY, TRUE, FALSE);
1707 		ResetLayerOptimizing();
1708 
1709 		if (gRenderFlags & RENDER_FLAG_NOZ)
1710 		{
1711 			RenderStaticWorldRect(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_END_Y, FALSE);
1712 		}
1713 		else
1714 		{
1715 			RenderStaticWorld();
1716 		}
1717 
1718 		if (!(gRenderFlags & RENDER_FLAG_SAVEOFF)) UpdateSaveBuffer();
1719 	}
1720 	else if (gRenderFlags & RENDER_FLAG_MARKED)
1721 	{
1722 		ResetLayerOptimizing();
1723 		RenderMarkedWorld();
1724 		if (!(gRenderFlags & RENDER_FLAG_SAVEOFF)) UpdateSaveBuffer();
1725 	}
1726 
1727 	if (!g_scroll_inertia               ||
1728 			gRenderFlags & RENDER_FLAG_NOZ  ||
1729 			gRenderFlags & RENDER_FLAG_FULL ||
1730 			gRenderFlags & RENDER_FLAG_MARKED)
1731 	{
1732 		RenderDynamicWorld();
1733 	}
1734 
1735 	if (g_scroll_inertia) EmptyBackgroundRects();
1736 
1737 	if (gRenderFlags & RENDER_FLAG_ROOMIDS)
1738 	{
1739 		RenderRoomInfo(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
1740 	}
1741 
1742 #ifdef _DEBUG
1743 	if (gRenderFlags & RENDER_FLAG_FOVDEBUG)
1744 	{
1745 		RenderFOVDebugInfo(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
1746 	}
1747 	else if (gfDisplayCoverValues)
1748 	{
1749 		RenderCoverDebugInfo(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
1750 	}
1751 	else if (gfDisplayGridNoVisibleValues)
1752 	{
1753 		RenderGridNoVisibleDebugInfo(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
1754 	}
1755 #endif
1756 
1757 
1758 	if (gRenderFlags & RENDER_FLAG_MARKED) ClearMarkedTiles();
1759 
1760 	if (gRenderFlags & RENDER_FLAG_CHECKZ && !(gTacticalStatus.uiFlags & NOHIDE_REDUNDENCY))
1761 	{
1762 		ExamineZBufferRect(gsVIEWPORT_START_X, gsVIEWPORT_WINDOW_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_WINDOW_END_Y);
1763 	}
1764 
1765 	gRenderFlags &= ~(RENDER_FLAG_FULL | RENDER_FLAG_MARKED | RENDER_FLAG_ROOMIDS | RENDER_FLAG_CHECKZ);
1766 
1767 	if (gTacticalStatus.uiFlags & SHOW_Z_BUFFER)
1768 	{
1769 		// COPY Z BUFFER TO FRAME BUFFER
1770 		SGPVSurface::Lock l(FRAME_BUFFER);
1771 		UINT16* const pDestBuf = l.Buffer<UINT16>();
1772 
1773 		for (UINT32 i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; ++i)
1774 		{
1775 			pDestBuf[i] = gpZBuffer[i];
1776 		}
1777 	}
1778 }
1779 
1780 
1781 static void CalcRenderParameters(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom);
1782 static void ResetRenderParameters(void);
1783 
1784 
1785 // Start with a center X,Y,Z world coordinate and render direction
1786 // Determine WorldIntersectionPoint and the starting block from these
1787 // Then render away!
RenderStaticWorldRect(INT16 sLeft,INT16 sTop,INT16 sRight,INT16 sBottom,BOOLEAN fDynamicsToo)1788 void RenderStaticWorldRect(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom, BOOLEAN fDynamicsToo)
1789 {
1790 	RenderLayerID sLevelIDs[10];
1791 
1792 	// Calculate render starting parameters
1793 	CalcRenderParameters(sLeft, sTop, sRight, sBottom);
1794 
1795 	// Reset layer optimizations
1796 	ResetLayerOptimizing();
1797 
1798 	// STATICS
1799 	sLevelIDs[0] = RENDER_STATIC_LAND;
1800 	RenderTiles(TILES_NONE, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 1, sLevelIDs);
1801 
1802 	sLevelIDs[0] = RENDER_STATIC_OBJECTS;
1803 	RenderTiles(TILES_NONE, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 1, sLevelIDs);
1804 
1805 	if (gRenderFlags & RENDER_FLAG_SHADOWS)
1806 	{
1807 		sLevelIDs[0] = RENDER_STATIC_SHADOWS;
1808 		RenderTiles(TILES_NONE, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 1, sLevelIDs);
1809 	}
1810 
1811 	sLevelIDs[0] = RENDER_STATIC_STRUCTS;
1812 	sLevelIDs[1] = RENDER_STATIC_ROOF;
1813 	sLevelIDs[2] = RENDER_STATIC_ONROOF;
1814 	sLevelIDs[3] = RENDER_STATIC_TOPMOST;
1815 	RenderTiles(TILES_NONE, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 4, sLevelIDs);
1816 
1817 	//ATE: Do obsucred layer!
1818 	sLevelIDs[0] = RENDER_STATIC_STRUCTS;
1819 	sLevelIDs[1] = RENDER_STATIC_ONROOF;
1820 	RenderTiles(TILES_OBSCURED, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 2, sLevelIDs);
1821 
1822 	if (fDynamicsToo)
1823 	{
1824 		// DYNAMICS
1825 		sLevelIDs[0] = RENDER_DYNAMIC_LAND;
1826 		sLevelIDs[1] = RENDER_DYNAMIC_OBJECTS;
1827 		sLevelIDs[2] = RENDER_DYNAMIC_SHADOWS;
1828 		sLevelIDs[3] = RENDER_DYNAMIC_STRUCT_MERCS;
1829 		sLevelIDs[4] = RENDER_DYNAMIC_MERCS;
1830 		sLevelIDs[5] = RENDER_DYNAMIC_STRUCTS;
1831 		sLevelIDs[6] = RENDER_DYNAMIC_ROOF;
1832 		sLevelIDs[7] = RENDER_DYNAMIC_HIGHMERCS;
1833 		sLevelIDs[8] = RENDER_DYNAMIC_ONROOF;
1834 		RenderTiles(TILES_NONE, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 9, sLevelIDs);
1835 
1836 		SumAdditiveLayerOptimization();
1837 	}
1838 
1839 	ResetRenderParameters();
1840 
1841 	if (!gfDoVideoScroll) AddBaseDirtyRect(sLeft, sTop, sRight, sBottom);
1842 }
1843 
1844 
RenderStaticWorld(void)1845 static void RenderStaticWorld(void)
1846 {
1847 	RenderLayerID sLevelIDs[9];
1848 
1849 	// Calculate render starting parameters
1850 	CalcRenderParameters(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_END_Y);
1851 
1852 	// Clear z-buffer
1853 	std::fill_n(gpZBuffer, gsVIEWPORT_END_Y * SCREEN_WIDTH, LAND_Z_LEVEL);
1854 
1855 	FreeBackgroundRectType(BGND_FLAG_ANIMATED);
1856 	InvalidateBackgroundRects();
1857 
1858 	sLevelIDs[0] = RENDER_STATIC_LAND;
1859 	RenderTiles(TILES_NONE, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 1, sLevelIDs);
1860 
1861 	sLevelIDs[0] = RENDER_STATIC_OBJECTS;
1862 	RenderTiles(TILES_NONE, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 1, sLevelIDs);
1863 
1864 	if (gRenderFlags & RENDER_FLAG_SHADOWS)
1865 	{
1866 		sLevelIDs[0] = RENDER_STATIC_SHADOWS;
1867 		RenderTiles(TILES_NONE, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 1, sLevelIDs);
1868 	}
1869 
1870 	sLevelIDs[0] = RENDER_STATIC_STRUCTS;
1871 	sLevelIDs[1] = RENDER_STATIC_ROOF;
1872 	sLevelIDs[2] = RENDER_STATIC_ONROOF;
1873 	sLevelIDs[3] = RENDER_STATIC_TOPMOST;
1874 	RenderTiles(TILES_NONE, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 4, sLevelIDs);
1875 
1876 	//ATE: Do obsucred layer!
1877 	sLevelIDs[0] = RENDER_STATIC_STRUCTS;
1878 	sLevelIDs[1] = RENDER_STATIC_ONROOF;
1879 	RenderTiles(TILES_OBSCURED, gsLStartPointX_M, gsLStartPointY_M, gsLStartPointX_S, gsLStartPointY_S, gsLEndXS, gsLEndYS, 2, sLevelIDs);
1880 
1881 	AddBaseDirtyRect(gsVIEWPORT_START_X, gsVIEWPORT_WINDOW_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_WINDOW_END_Y);
1882 	ResetRenderParameters();
1883 }
1884 
1885 
RenderMarkedWorld(void)1886 static void RenderMarkedWorld(void)
1887 {
1888 	RenderLayerID sLevelIDs[4];
1889 
1890 	CalcRenderParameters(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_END_Y);
1891 
1892 	RestoreBackgroundRects();
1893 	FreeBackgroundRectType(BGND_FLAG_ANIMATED);
1894 	InvalidateBackgroundRects();
1895 
1896 	ResetLayerOptimizing();
1897 
1898 	sLevelIDs[0] = RENDER_STATIC_LAND;
1899 	sLevelIDs[1] = RENDER_STATIC_OBJECTS;
1900 	RenderTiles(TILES_MARKED, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 2, sLevelIDs);
1901 
1902 	if (gRenderFlags & RENDER_FLAG_SHADOWS)
1903 	{
1904 		sLevelIDs[0] = RENDER_STATIC_SHADOWS;
1905 		RenderTiles(TILES_MARKED, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 1, sLevelIDs);
1906 	}
1907 
1908 	sLevelIDs[0] = RENDER_STATIC_STRUCTS;
1909 	RenderTiles(TILES_MARKED, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 1, sLevelIDs);
1910 
1911 	sLevelIDs[0] = RENDER_STATIC_ROOF;
1912 	RenderTiles(TILES_MARKED, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 1, sLevelIDs);
1913 
1914 	sLevelIDs[0] = RENDER_STATIC_ONROOF;
1915 	RenderTiles(TILES_MARKED, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 1, sLevelIDs);
1916 
1917 	sLevelIDs[0] = RENDER_STATIC_TOPMOST;
1918 	RenderTiles(TILES_MARKED, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 1, sLevelIDs);
1919 
1920 	AddBaseDirtyRect(gsVIEWPORT_START_X, gsVIEWPORT_WINDOW_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_WINDOW_END_Y);
1921 
1922 	ResetRenderParameters();
1923 }
1924 
1925 
RenderDynamicWorld(void)1926 static void RenderDynamicWorld(void)
1927 {
1928 	RenderLayerID sLevelIDs[10];
1929 
1930 	CalcRenderParameters(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_END_Y);
1931 
1932 	RestoreBackgroundRects();
1933 
1934 	sLevelIDs[0] = RENDER_DYNAMIC_OBJECTS;
1935 	sLevelIDs[1] = RENDER_DYNAMIC_SHADOWS;
1936 	sLevelIDs[2] = RENDER_DYNAMIC_STRUCT_MERCS;
1937 	sLevelIDs[3] = RENDER_DYNAMIC_MERCS;
1938 	sLevelIDs[4] = RENDER_DYNAMIC_STRUCTS;
1939 	sLevelIDs[5] = RENDER_DYNAMIC_HIGHMERCS;
1940 	sLevelIDs[6] = RENDER_DYNAMIC_ROOF;
1941 	sLevelIDs[7] = RENDER_DYNAMIC_ONROOF;
1942 	sLevelIDs[8] = RENDER_DYNAMIC_TOPMOST;
1943 	RenderTiles(TILES_DIRTY, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 9, sLevelIDs);
1944 
1945 	if (!GameState::getInstance()->isEditorMode() || !gfEditMode)
1946 	{
1947 		RenderTacticalInterface();
1948 	}
1949 
1950 	SaveBackgroundRects();
1951 
1952 	sLevelIDs[0] = RENDER_DYNAMIC_OBJECTS;
1953 	sLevelIDs[1] = RENDER_DYNAMIC_SHADOWS;
1954 	sLevelIDs[2] = RENDER_DYNAMIC_STRUCT_MERCS;
1955 	sLevelIDs[3] = RENDER_DYNAMIC_MERCS;
1956 	sLevelIDs[4] = RENDER_DYNAMIC_STRUCTS;
1957 	RenderTiles(TILES_NONE, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 5, sLevelIDs);
1958 
1959 	sLevelIDs[0] = RENDER_DYNAMIC_ROOF;
1960 	sLevelIDs[1] = RENDER_DYNAMIC_HIGHMERCS;
1961 	sLevelIDs[2] = RENDER_DYNAMIC_ONROOF;
1962 	RenderTiles(TILES_NONE, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 3, sLevelIDs);
1963 
1964 	sLevelIDs[0] = RENDER_DYNAMIC_TOPMOST;
1965 	// ATE: check here for mouse over structs.....
1966 	RenderTiles(TILES_DYNAMIC_CHECKFOR_INT_TILE, gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS, 1, sLevelIDs);
1967 
1968 	SumAdditiveLayerOptimization();
1969 	ResetRenderParameters();
1970 }
1971 
1972 
HandleScrollDirections(UINT32 ScrollFlags,INT16 sScrollXStep,INT16 sScrollYStep,BOOLEAN fCheckOnly)1973 static BOOLEAN HandleScrollDirections(UINT32 ScrollFlags, INT16 sScrollXStep, INT16 sScrollYStep, BOOLEAN fCheckOnly)
1974 {
1975 	// printf("HandleScrollDirections: %d, (%4d, %4d), %d\n", ScrollFlags, sScrollXStep, sScrollYStep, fCheckOnly);
1976 	INT16 scroll_x = 0;
1977 	if (ScrollFlags & SCROLL_LEFT)  scroll_x -= sScrollXStep;
1978 	if (ScrollFlags & SCROLL_RIGHT) scroll_x += sScrollXStep;
1979 
1980 	INT16 scroll_y = 0;
1981 	if (ScrollFlags & SCROLL_UP)    scroll_y -= sScrollYStep;
1982 	if (ScrollFlags & SCROLL_DOWN)  scroll_y += sScrollYStep;
1983 
1984 	if (scroll_x != 0)
1985 	{
1986 		// Check horizontal
1987 		INT16 sTempX_W;
1988 		INT16 sTempY_W;
1989 		FromScreenToCellCoordinates(scroll_x, 0, &sTempX_W, &sTempY_W);
1990 		const INT16 sTempRenderCenterX = gsRenderCenterX + sTempX_W;
1991 		const INT16 sTempRenderCenterY = gsRenderCenterY + sTempY_W;
1992 		if (!ApplyScrolling(sTempRenderCenterX, sTempRenderCenterY, FALSE, fCheckOnly, ScrollType_Horizontal))
1993 		{
1994 			scroll_x = 0;
1995 		}
1996 	}
1997 
1998 	if (scroll_y != 0)
1999 	{
2000 		// Check vertical
2001 		INT16 sTempX_W;
2002 		INT16 sTempY_W;
2003 		FromScreenToCellCoordinates(0, scroll_y, &sTempX_W, &sTempY_W);
2004 		const INT16 sTempRenderCenterX = gsRenderCenterX + sTempX_W;
2005 		const INT16 sTempRenderCenterY = gsRenderCenterY + sTempY_W;
2006 		if (!ApplyScrolling(sTempRenderCenterX, sTempRenderCenterY, FALSE, fCheckOnly, ScrollType_Vertical))
2007 		{
2008 			scroll_y = 0;
2009 		}
2010 	}
2011 
2012 	const BOOLEAN fAGoodMove = (scroll_x != 0 || scroll_y != 0);
2013 	if (fAGoodMove && !fCheckOnly) ScrollBackground(scroll_x, scroll_y);
2014 
2015 	return fAGoodMove;
2016 }
2017 
2018 
ScrollSpeed(void)2019 static UINT ScrollSpeed(void)
2020 {
2021 	UINT speed = 20 << (_KeyDown(SHIFT) ? 2 : gubCurScrollSpeedID);
2022 	if (!gfDoVideoScroll) speed *= 2;
2023 	return speed;
2024 }
2025 
2026 
ScrollWorld(void)2027 void ScrollWorld(void)
2028 {
2029 	static UINT8   ubOldScrollSpeed        = 0;
2030 	static BOOLEAN fFirstTimeInSlideToMode = TRUE;
2031 
2032 	if (gfIgnoreScrollDueToCenterAdjust)
2033 	{
2034 		//	gfIgnoreScrollDueToCenterAdjust = FALSE;
2035 		return;
2036 	}
2037 
2038 	BOOLEAN fIgnoreInput = FALSE;
2039 
2040 	if (gfIgnoreScrolling) return;
2041 	if (gCurrentUIMode == LOCKUI_MODE) fIgnoreInput = TRUE;
2042 
2043 	// If in editor, ignore scrolling if any of the shift keys pressed with arrow keys
2044 	if (gfEditMode && _KeyDown(CTRL)) return;
2045 
2046 	if (_KeyDown(ALT)) return;
2047 
2048 	UINT32 ScrollFlags = 0;
2049 
2050 	do
2051 	{
2052 		// Check for sliding
2053 		if (gTacticalStatus.sSlideTarget != NOWHERE)
2054 		{
2055 			// Ignore all input...
2056 			// Check if we have reached out dest!
2057 			if (fFirstTimeInSlideToMode)
2058 			{
2059 				ubOldScrollSpeed = gubCurScrollSpeedID;
2060 				fFirstTimeInSlideToMode = FALSE;
2061 			}
2062 
2063 			ScrollFlags = 0;
2064 			INT8 bDirection;
2065 			if (SoldierLocationRelativeToScreen(gTacticalStatus.sSlideTarget, &bDirection, &ScrollFlags) &&
2066 					GridNoOnVisibleWorldTile(gTacticalStatus.sSlideTarget))
2067 			{
2068 				static const UINT32 gScrollDirectionFlags[] =
2069 				{
2070 					SCROLL_UP | SCROLL_RIGHT,
2071 					SCROLL_RIGHT,
2072 					SCROLL_DOWN | SCROLL_RIGHT,
2073 					SCROLL_DOWN,
2074 					SCROLL_DOWN | SCROLL_LEFT,
2075 					SCROLL_LEFT,
2076 					SCROLL_UP | SCROLL_LEFT,
2077 					SCROLL_UP,
2078 				};
2079 
2080 				ScrollFlags  = gScrollDirectionFlags[bDirection];
2081 				fIgnoreInput = TRUE;
2082 			}
2083 			else
2084 			{
2085 				// We've stopped!
2086 				gTacticalStatus.sSlideTarget = NOWHERE;
2087 			}
2088 		}
2089 		else
2090 		{
2091 			// Restore old scroll speed
2092 			if (!fFirstTimeInSlideToMode)
2093 			{
2094 				gubCurScrollSpeedID = ubOldScrollSpeed;
2095 			}
2096 			fFirstTimeInSlideToMode = TRUE;
2097 		}
2098 
2099 		if (!fIgnoreInput)
2100 		{
2101 			// Check keys
2102 			if (_KeyDown(SDLK_UP))    ScrollFlags |= SCROLL_UP;
2103 			if (_KeyDown(SDLK_DOWN))  ScrollFlags |= SCROLL_DOWN;
2104 			if (_KeyDown(SDLK_RIGHT)) ScrollFlags |= SCROLL_RIGHT;
2105 			if (_KeyDown(SDLK_LEFT))  ScrollFlags |= SCROLL_LEFT;
2106 
2107 			// Do mouse - PUT INTO A TIMER!
2108 			// Put a counter on starting from mouse, if we have not started already!
2109 			if (!g_scroll_inertia && !gfScrollPending)
2110 			{
2111 				if (!COUNTERDONE(STARTSCROLL)) break;
2112 				RESETCOUNTER(STARTSCROLL);
2113 			}
2114 
2115 			if (gusMouseYPos <  NO_PX_SHOW_EXIT_CURS)                 ScrollFlags |= SCROLL_UP;
2116 			if (gusMouseYPos >= SCREEN_HEIGHT - NO_PX_SHOW_EXIT_CURS) ScrollFlags |= SCROLL_DOWN;
2117 			if (gusMouseXPos >= SCREEN_WIDTH  - NO_PX_SHOW_EXIT_CURS) ScrollFlags |= SCROLL_RIGHT;
2118 			if (gusMouseXPos <  NO_PX_SHOW_EXIT_CURS)                 ScrollFlags |= SCROLL_LEFT;
2119 		}
2120 	}
2121 	while (FALSE);
2122 
2123 
2124 	BOOLEAN fAGoodMove   = FALSE;
2125 	INT16   sScrollXStep = -1;
2126 	INT16   sScrollYStep = -1;
2127 	if (ScrollFlags != 0)
2128 	{
2129 		// Adjust speed based on whether shift is down
2130 		const UINT speed = ScrollSpeed();
2131 		sScrollXStep = speed;
2132 		sScrollYStep = speed / 2;
2133 
2134 		fAGoodMove = HandleScrollDirections(ScrollFlags, sScrollXStep, sScrollYStep, TRUE);
2135 	}
2136 
2137 	// Has this been an OK scroll?
2138 	if (fAGoodMove)
2139 	{
2140 		if (COUNTERDONE(NEXTSCROLL))
2141 		{
2142 			RESETCOUNTER(NEXTSCROLL);
2143 
2144 			// Are we starting a new scroll?
2145 			if (!g_scroll_inertia && !gfScrollPending)
2146 			{
2147 				// We are starting to scroll - setup scroll pending
2148 				gfScrollPending = TRUE;
2149 
2150 				// Remove any interface stuff
2151 				ClearInterface();
2152 
2153 				// Return so that next frame things will be erased!
2154 				return;
2155 			}
2156 
2157 			// If here, set scroll pending to false
2158 			gfScrollPending = FALSE;
2159 
2160 			g_scroll_inertia = true;
2161 
2162 			// Now we actually begin our scrolling
2163 			HandleScrollDirections(ScrollFlags, sScrollXStep, sScrollYStep, FALSE);
2164 		}
2165 	}
2166 	else
2167 	{
2168 		// ATE: Also if scroll pending never got to scroll....
2169 		if (gfScrollPending)
2170 		{
2171 			// Do a complete rebuild!
2172 			gfScrollPending = FALSE;
2173 
2174 			// Restore Interface!
2175 			RestoreInterface();
2176 
2177 			DeleteVideoOverlaysArea();
2178 		}
2179 
2180 		// Check if we have just stopped scrolling!
2181 		if (g_scroll_inertia)
2182 		{
2183 			SetRenderFlags(RENDER_FLAG_FULL | RENDER_FLAG_CHECKZ);
2184 
2185 			// Restore Interface!
2186 			RestoreInterface();
2187 
2188 			DeleteVideoOverlaysArea();
2189 		}
2190 
2191 		g_scroll_inertia = false;
2192 		gfScrollPending  = FALSE;
2193 	}
2194 }
2195 
2196 
InitRenderParams(UINT8 ubRestrictionID)2197 void InitRenderParams(UINT8 ubRestrictionID)
2198 {
2199 	// FIXME incorrect use of CELL_X_SIZE/CELL_Y_SIZE and WORLD_ROWS/WORLD_COLS
2200 	//       it only works as intended because they have the same value as the counterpart
2201 	INT16 gTopLeftWorldLimitX;     // XXX HACK000E
2202 	INT16 gTopLeftWorldLimitY;     // XXX HACK000E
2203 	INT16 gBottomRightWorldLimitX; // XXX HACK000E
2204 	INT16 gBottomRightWorldLimitY; // XXX HACK000E
2205 	switch (ubRestrictionID)
2206 	{
2207 		case 0: // Default!
2208 			gTopLeftWorldLimitX = CELL_X_SIZE;
2209 			gTopLeftWorldLimitY = CELL_X_SIZE * WORLD_ROWS / 2;
2210 
2211 			gBottomRightWorldLimitX = CELL_Y_SIZE * WORLD_COLS;
2212 			gBottomRightWorldLimitY = CELL_X_SIZE * WORLD_ROWS / 2;
2213 			break;
2214 
2215 		case 1: // BAEMENT LEVEL 1
2216 			gTopLeftWorldLimitX = CELL_X_SIZE * WORLD_ROWS * 3 / 10;
2217 			gTopLeftWorldLimitY = CELL_X_SIZE * WORLD_ROWS     /  2;
2218 
2219 			gBottomRightWorldLimitX = CELL_X_SIZE * WORLD_ROWS * 7 / 10;
2220 			gBottomRightWorldLimitY = CELL_X_SIZE * WORLD_ROWS     /  2;
2221 			break;
2222 
2223 		default: abort(); // HACK000E
2224 	}
2225 
2226 	gCenterWorldX = CELL_X_SIZE * WORLD_ROWS / 2;
2227 	gCenterWorldY = CELL_X_SIZE * WORLD_COLS / 2;
2228 
2229 	// Convert Bounding box into screen coords
2230 	FromCellToScreenCoordinates(gTopLeftWorldLimitX,     gTopLeftWorldLimitY,     &gsLeftX, &gsTopY);
2231 	FromCellToScreenCoordinates(gBottomRightWorldLimitX, gBottomRightWorldLimitY, &gsRightX, &gsBottomY);
2232 	FromCellToScreenCoordinates(gCenterWorldX,           gCenterWorldY,           &gsCX,  &gsCY);
2233 
2234 	// Adjust for interface height tabbing!
2235 	gsTopY += ROOF_LEVEL_HEIGHT;
2236 	gsCY  += ROOF_LEVEL_HEIGHT / 2;
2237 
2238 	SLOGD("World Screen Width %d Height %d", gsRightX - gsLeftX, gsBottomY - gsTopY);
2239 
2240 	// Determine scale factors
2241 	// First scale world screen coords for VIEWPORT ratio
2242 	const double dWorldX = gsRightX - gsLeftX;
2243 	const double dWorldY = gsBottomY - gsTopY;
2244 
2245 	gdScaleX = (double)RADAR_WINDOW_WIDTH  / dWorldX;
2246 	gdScaleY = (double)RADAR_WINDOW_HEIGHT / dWorldY;
2247 
2248 	const UINT32 n = NUM_ITEM_CYCLE_COLORS;
2249 	for (UINT32 i = 0; i < n; ++i)
2250 	{
2251 		const UINT32 l = (i < n / 2 ? i + 1 : n - i) * (250 / (n / 2));
2252 		us16BPPItemCycleWhiteColors[i]  = Get16BPPColor(FROMRGB(l, l, l));
2253 		us16BPPItemCycleRedColors[i]    = Get16BPPColor(FROMRGB(l, 0, 0));
2254 		us16BPPItemCycleYellowColors[i] = Get16BPPColor(FROMRGB(l, l, 0));
2255 	}
2256 
2257 	gusNormalItemOutlineColor = Get16BPPColor(FROMRGB(255, 255, 255));
2258 	gusYellowItemOutlineColor = Get16BPPColor(FROMRGB(255, 255,   0));
2259 }
2260 
2261 /** This function checks whether the render screen can be moved to new position. */
ApplyScrolling(INT16 sTempRenderCenterX,INT16 sTempRenderCenterY,BOOLEAN fForceAdjust,BOOLEAN fCheckOnly,ScrollType scrollType)2262 static BOOLEAN ApplyScrolling(INT16 sTempRenderCenterX, INT16 sTempRenderCenterY, BOOLEAN fForceAdjust, BOOLEAN fCheckOnly,
2263 				ScrollType scrollType)
2264 {
2265 	// Make sure it's a multiple of 5
2266 	sTempRenderCenterX = sTempRenderCenterX / CELL_X_SIZE * CELL_X_SIZE + CELL_X_SIZE / 2;
2267 	sTempRenderCenterY = sTempRenderCenterY / CELL_X_SIZE * CELL_Y_SIZE + CELL_Y_SIZE / 2;
2268 
2269 	// From render center in world coords, convert to render center in "screen" coords
2270 	INT16 sScreenCenterX;
2271 	INT16 sScreenCenterY;
2272 	FromCellToScreenCoordinates(sTempRenderCenterX, sTempRenderCenterY, &sScreenCenterX, &sScreenCenterY);
2273 
2274 	// Adjust for offset position on screen
2275 	sScreenCenterX -=  0;
2276 	sScreenCenterY -= 10;
2277 
2278 	const INT16 sX_S = g_ui.m_tacticalMapCenterX;
2279 	const INT16 sY_S = g_ui.m_tacticalMapCenterY;
2280 
2281 	// Get corners in screen coords
2282 	const INT16 sTopLeftWorldX = sScreenCenterX - sX_S;
2283 	const INT16 sTopLeftWorldY = sScreenCenterY - sY_S;
2284 
2285 	const INT16 sBottomRightWorldX = sScreenCenterX + sX_S;
2286 	const INT16 sBottomRightWorldY = sScreenCenterY + sY_S;
2287 
2288 	// Checking if screen shows areas outside of the map
2289 	const BOOLEAN fOutLeft   = (gsLeftX + SCROLL_LEFT_PADDING > sTopLeftWorldX);
2290 	const BOOLEAN fOutRight  = (gsRightX + SCROLL_RIGHT_PADDING < sBottomRightWorldX);
2291 	const BOOLEAN fOutTop    = (gsTopY + SCROLL_TOP_PADDING >= sTopLeftWorldY);            /* top of the screen is above top of the map */
2292 	const BOOLEAN fOutBottom = (gsBottomY + SCROLL_BOTTOM_PADDING < sBottomRightWorldY);          /* bottom of the screen is below bottom if the map */
2293 
2294 	const int mapHeight = (gsBottomY + SCROLL_BOTTOM_PADDING) - (gsTopY + SCROLL_TOP_PADDING);
2295 	const int screenHeight = gsVIEWPORT_END_Y - gsVIEWPORT_START_Y;
2296 
2297 	const int mapWidth = (gsRightX + SCROLL_RIGHT_PADDING) - (gsLeftX + SCROLL_LEFT_PADDING);
2298 	const int screenWidth = gsVIEWPORT_END_X - gsVIEWPORT_START_X;
2299 
2300 	BOOLEAN fScrollGood = FALSE;
2301 
2302 	if (!fOutRight && !fOutLeft && !fOutTop && !fOutBottom)
2303 	{
2304 		// Nothing goes outside the borders of the map.
2305 		// Can change render center.
2306 		fScrollGood = TRUE;
2307 	}
2308 	else
2309 	{
2310 		// Something is outside the border.
2311 		// Let's check if we can move horizontally or vertically.
2312 
2313 		if((scrollType == ScrollType_Horizontal)
2314 			&& (((sTempRenderCenterX < gsRenderCenterX) && !fOutLeft)                /** moving left */
2315 			|| ((sTempRenderCenterX > gsRenderCenterX) && !fOutRight)))            /** moving right */
2316 		{
2317 			// can move
2318 			fScrollGood = TRUE;
2319 		}
2320 
2321 		if((scrollType == ScrollType_Vertical)
2322 			&& (((sTempRenderCenterY < gsRenderCenterY) && !fOutTop)
2323 			|| ((sTempRenderCenterY > gsRenderCenterY) && !fOutBottom)))
2324 		{
2325 			// can move
2326 			fScrollGood = TRUE;
2327 		}
2328 	}
2329 
2330 	// If in editor, anything goes
2331 	if (gfEditMode && _KeyDown(SHIFT)) fScrollGood = TRUE;
2332 
2333 	// Reset some UI flags
2334 	gfUIShowExitEast  = FALSE;
2335 	gfUIShowExitWest  = FALSE;
2336 	gfUIShowExitNorth = FALSE;
2337 	gfUIShowExitSouth = FALSE;
2338 
2339 	if (!fScrollGood)
2340 	{
2341 		if (fForceAdjust)
2342 		{
2343 			INT16 newScreenCenterX = sScreenCenterX;
2344 			INT16 newScreenCenterY = sScreenCenterY;
2345 
2346 			if (screenHeight > mapHeight)
2347 			{
2348 				// printf("screen height is bigger than map height\n");
2349 				newScreenCenterY = gsCY + (SCROLL_TOP_PADDING + SCROLL_BOTTOM_PADDING) / 2;
2350 			}
2351 			else if (fOutTop)
2352 			{
2353 				newScreenCenterY = gsTopY + SCROLL_TOP_PADDING + sY_S;
2354 			}
2355 			else if (fOutBottom)
2356 			{
2357 				newScreenCenterY = gsBottomY + SCROLL_BOTTOM_PADDING - sY_S;
2358 			}
2359 
2360 			if (screenWidth > mapWidth)
2361 			{
2362 				// printf("screen width is bigger than map width\n");
2363 				newScreenCenterX = gsCX + (SCROLL_LEFT_PADDING + SCROLL_RIGHT_PADDING) / 2;
2364 			}
2365 			else if (fOutLeft)
2366 			{
2367 				newScreenCenterX = gsLeftX + SCROLL_LEFT_PADDING + sX_S;
2368 			}
2369 			else if (fOutRight)
2370 			{
2371 				newScreenCenterX = gsRightX + SCROLL_RIGHT_PADDING - sX_S;
2372 			}
2373 
2374 			INT16 sTempPosX_W;
2375 			INT16 sTempPosY_W;
2376 			FromScreenToCellCoordinates(newScreenCenterX, newScreenCenterY, &sTempPosX_W, &sTempPosY_W);
2377 			sTempRenderCenterX = sTempPosX_W;
2378 			sTempRenderCenterY = sTempPosY_W;
2379 			fScrollGood = TRUE;
2380 		}
2381 		else
2382 		{
2383 			if (fOutRight  && gusMouseXPos >= SCREEN_WIDTH - NO_PX_SHOW_EXIT_CURS)  gfUIShowExitEast  = TRUE;
2384 			if (fOutLeft   && gusMouseXPos <  NO_PX_SHOW_EXIT_CURS)                 gfUIShowExitWest  = TRUE;
2385 			if (fOutTop    && gusMouseYPos <  NO_PX_SHOW_EXIT_CURS)                 gfUIShowExitNorth = TRUE;
2386 			if (fOutBottom && gusMouseYPos >= SCREEN_HEIGHT - NO_PX_SHOW_EXIT_CURS) gfUIShowExitSouth = TRUE;
2387 		}
2388 	}
2389 
2390 	if (fScrollGood && !fCheckOnly)
2391 	{
2392 		// Make sure it's a multiple of 5
2393 		gsRenderCenterX = sTempRenderCenterX / CELL_X_SIZE * CELL_X_SIZE + CELL_X_SIZE / 2;
2394 		gsRenderCenterY = sTempRenderCenterY / CELL_X_SIZE * CELL_Y_SIZE + CELL_Y_SIZE / 2;
2395 
2396 		gsTopLeftWorldX = sTopLeftWorldX - gsLeftX;
2397 		gsTopLeftWorldY = sTopLeftWorldY - gsTopY;
2398 
2399 		gsBottomRightWorldX = sBottomRightWorldX - gsLeftX;
2400 		gsBottomRightWorldY = sBottomRightWorldY - gsTopY;
2401 
2402 		SetPositionSndsVolumeAndPanning();
2403 	}
2404 
2405 	return fScrollGood;
2406 }
2407 
2408 
ClearMarkedTiles(void)2409 static void ClearMarkedTiles(void)
2410 {
2411 	FOR_EACH_WORLD_TILE(i)
2412 	{
2413 		i->uiFlags &= ~MAPELEMENT_REDRAW;
2414 	}
2415 }
2416 
2417 
InvalidateWorldRedundency(void)2418 void InvalidateWorldRedundency(void)
2419 {
2420 	SetRenderFlags(RENDER_FLAG_CHECKZ);
2421 	FOR_EACH_WORLD_TILE(i)
2422 	{
2423 		i->uiFlags |= MAPELEMENT_REEVALUATE_REDUNDENCY;
2424 	}
2425 }
2426 
2427 
2428 #define Z_STRIP_DELTA_Y  (Z_SUBLAYERS * 10)
2429 
2430 /**********************************************************************************************
2431 Blt8BPPDataTo16BPPBufferTransZIncClip
2432 
2433 	Blits an image into the destination buffer, using an ETRLE brush as a source, and a 16-bit
2434 	buffer as a destination. As it is blitting, it checks the Z value of the ZBuffer, and if the
2435 	pixel's Z level is below that of the current pixel, it is written on, and the Z value is
2436 	updated to the current value, for any non-transparent pixels. The Z-buffer is 16 bit, and
2437 	must be the same dimensions (including Pitch) as the destination.
2438 
2439 **********************************************************************************************/
Blt8BPPDataTo16BPPBufferTransZIncClip(UINT16 * pBuffer,UINT32 uiDestPitchBYTES,UINT16 * pZBuffer,UINT16 usZValue,HVOBJECT hSrcVObject,INT32 iX,INT32 iY,UINT16 usIndex,SGPRect * clipregion)2440 static void Blt8BPPDataTo16BPPBufferTransZIncClip(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion)
2441 {
2442 	UINT32 Unblitted;
2443 	INT32  LSCount;
2444 	UINT16 usZLevel, usZColsToGo, usZIndex;
2445 
2446 	Assert(hSrcVObject != NULL);
2447 	Assert(pBuffer     != NULL);
2448 
2449 	// Get Offsets from Index into structure
2450 	ETRLEObject const& pTrav    = hSrcVObject->SubregionProperties(usIndex);
2451 	INT32       const  usHeight = pTrav.usHeight;
2452 	INT32       const  usWidth  = pTrav.usWidth;
2453 
2454 	// Add to start position of dest buffer
2455 	INT32 const iTempX = iX + pTrav.sOffsetX;
2456 	INT32 const iTempY = iY + pTrav.sOffsetY;
2457 
2458 	INT32 ClipX1;
2459 	INT32 ClipY1;
2460 	INT32 ClipX2;
2461 	INT32 ClipY2;
2462 	if (clipregion == NULL)
2463 	{
2464 		ClipX1 = ClippingRect.iLeft;
2465 		ClipY1 = ClippingRect.iTop;
2466 		ClipX2 = ClippingRect.iRight;
2467 		ClipY2 = ClippingRect.iBottom;
2468 	}
2469 	else
2470 	{
2471 		ClipX1 = clipregion->iLeft;
2472 		ClipY1 = clipregion->iTop;
2473 		ClipX2 = clipregion->iRight;
2474 		ClipY2 = clipregion->iBottom;
2475 	}
2476 
2477 	// Calculate rows hanging off each side of the screen
2478 	const INT32 LeftSkip   = __min(ClipX1 -   MIN(ClipX1, iTempX), usWidth);
2479 	INT32       TopSkip    = __min(ClipY1 - __min(ClipY1, iTempY), usHeight);
2480 	const INT32 RightSkip  = __min(  MAX(ClipX2, iTempX + usWidth)  - ClipX2, usWidth);
2481 	const INT32 BottomSkip = __min(__max(ClipY2, iTempY + usHeight) - ClipY2, usHeight);
2482 
2483 	// calculate the remaining rows and columns to blit
2484 	const INT32 BlitLength = usWidth  - LeftSkip - RightSkip;
2485 	INT32       BlitHeight = usHeight - TopSkip  - BottomSkip;
2486 
2487 	// check if whole thing is clipped
2488 	if (LeftSkip >= usWidth  || RightSkip  >= usWidth)  return;
2489 	if (TopSkip  >= usHeight || BottomSkip >= usHeight) return;
2490 
2491 	UINT8 const* SrcPtr   = hSrcVObject->PixData(pTrav);
2492 	UINT8*       DestPtr  = (UINT8*)pBuffer  + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
2493 	UINT8*       ZPtr     = (UINT8*)pZBuffer + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
2494 	const UINT32 LineSkip = uiDestPitchBYTES - BlitLength * 2;
2495 	UINT16 const* const p16BPPPalette = hSrcVObject->CurrentShade();
2496 
2497 	if (hSrcVObject->ppZStripInfo == NULL)
2498 	{
2499 		SLOGW("Missing Z-Strip info on multi-Z object");
2500 		return;
2501 	}
2502 	// setup for the z-column blitting stuff
2503 	const ZStripInfo* const pZInfo = hSrcVObject->ppZStripInfo[usIndex];
2504 	if (pZInfo == NULL)
2505 	{
2506 		SLOGW("Missing Z-Strip info on multi-Z object");
2507 		return;
2508 	}
2509 
2510 	UINT16 usZStartLevel = (INT16)usZValue + pZInfo->bInitialZChange * Z_STRIP_DELTA_Y;
2511 	// set to odd number of pixels for first column
2512 
2513 	UINT16 usZStartCols;
2514 	if  (LeftSkip > pZInfo->ubFirstZStripWidth)
2515 	{
2516 		usZStartCols = LeftSkip - pZInfo->ubFirstZStripWidth;
2517 		usZStartCols = 20 - usZStartCols % 20;
2518 	}
2519 	else if (LeftSkip < pZInfo->ubFirstZStripWidth)
2520 	{
2521 		usZStartCols = pZInfo->ubFirstZStripWidth - LeftSkip;
2522 	}
2523 	else
2524 	{
2525 		usZStartCols = 20;
2526 	}
2527 
2528 	usZColsToGo = usZStartCols;
2529 
2530 	const INT8* const pZArray = pZInfo->pbZChange;
2531 
2532 	UINT16 usZStartIndex;
2533 	if (LeftSkip >= pZInfo->ubFirstZStripWidth)
2534 	{
2535 		// Index into array after doing left clipping
2536 		usZStartIndex = 1 + (LeftSkip - pZInfo->ubFirstZStripWidth) / 20;
2537 
2538 		//calculates the Z-value after left-side clipping
2539 		if (usZStartIndex)
2540 		{
2541 			for (UINT16 i = 0; i < usZStartIndex; i++)
2542 			{
2543 				switch (pZArray[i])
2544 				{
2545 					case -1: usZStartLevel -= Z_STRIP_DELTA_Y; break;
2546 					case  0: /* no change */                   break;
2547 					case  1: usZStartLevel += Z_STRIP_DELTA_Y; break;
2548 				}
2549 			}
2550 		}
2551 	}
2552 	else
2553 	{
2554 		usZStartIndex = 0;
2555 	}
2556 
2557 	usZLevel = usZStartLevel;
2558 	usZIndex = usZStartIndex;
2559 
2560 	UINT32 PxCount;
2561 
2562 	while (TopSkip > 0)
2563 	{
2564 		for (;;)
2565 		{
2566 			PxCount = *SrcPtr++;
2567 			if (PxCount & 0x80) continue;
2568 			if (PxCount == 0) break;
2569 			SrcPtr += PxCount;
2570 		}
2571 		TopSkip--;
2572 	}
2573 
2574 	do
2575 	{
2576 		usZLevel = usZStartLevel;
2577 		usZIndex = usZStartIndex;
2578 		usZColsToGo = usZStartCols;
2579 		for (LSCount = LeftSkip; LSCount > 0; LSCount -= PxCount)
2580 		{
2581 			PxCount = *SrcPtr++;
2582 			if (PxCount & 0x80)
2583 			{
2584 				PxCount &= 0x7F;
2585 				if (PxCount > static_cast<UINT32>(LSCount))
2586 				{
2587 					PxCount -= LSCount;
2588 					LSCount = BlitLength;
2589 					goto BlitTransparent;
2590 				}
2591 			}
2592 			else
2593 			{
2594 				if (PxCount > static_cast<UINT32>(LSCount))
2595 				{
2596 					SrcPtr += LSCount;
2597 					PxCount -= LSCount;
2598 					LSCount = BlitLength;
2599 					goto BlitNonTransLoop;
2600 				}
2601 				SrcPtr += PxCount;
2602 			}
2603 		}
2604 
2605 		LSCount = BlitLength;
2606 		while (LSCount > 0)
2607 		{
2608 			PxCount = *SrcPtr++;
2609 			if (PxCount & 0x80)
2610 			{
2611 BlitTransparent: // skip transparent pixels
2612 				PxCount &= 0x7F;
2613 				if (PxCount > static_cast<UINT32>(LSCount)) PxCount = LSCount;
2614 				LSCount -= PxCount;
2615 				DestPtr += 2 * PxCount;
2616 				ZPtr    += 2 * PxCount;
2617 				for (;;)
2618 				{
2619 					if (PxCount >= usZColsToGo)
2620 					{
2621 						PxCount -= usZColsToGo;
2622 						usZColsToGo = 20;
2623 
2624 						INT8 delta = pZArray[usZIndex++];
2625 						if (delta < 0)
2626 						{
2627 							usZLevel -= Z_STRIP_DELTA_Y;
2628 						}
2629 						else if (delta > 0)
2630 						{
2631 							usZLevel += Z_STRIP_DELTA_Y;
2632 						}
2633 					}
2634 					else
2635 					{
2636 						usZColsToGo -= PxCount;
2637 						break;
2638 					}
2639 				}
2640 			}
2641 			else
2642 			{
2643 BlitNonTransLoop: // blit non-transparent pixels
2644 				if (PxCount > static_cast<UINT32>(LSCount))
2645 				{
2646 					Unblitted = PxCount - LSCount;
2647 					PxCount = LSCount;
2648 				}
2649 				else
2650 				{
2651 					Unblitted = 0;
2652 				}
2653 				LSCount -= PxCount;
2654 
2655 				do
2656 				{
2657 					if (*(UINT16*)ZPtr < usZLevel)
2658 					{
2659 						*(UINT16*)ZPtr = usZLevel;
2660 						*(UINT16*)DestPtr = p16BPPPalette[*SrcPtr];
2661 					}
2662 					SrcPtr++;
2663 					DestPtr += 2;
2664 					ZPtr += 2;
2665 					if (--usZColsToGo == 0)
2666 					{
2667 						usZColsToGo = 20;
2668 
2669 						INT8 delta = pZArray[usZIndex++];
2670 						if (delta < 0)
2671 						{
2672 							usZLevel -= Z_STRIP_DELTA_Y;
2673 						}
2674 						else if (delta > 0)
2675 						{
2676 							usZLevel += Z_STRIP_DELTA_Y;
2677 						}
2678 					}
2679 				}
2680 				while (--PxCount > 0);
2681 				SrcPtr += Unblitted;
2682 			}
2683 		}
2684 
2685 		while (*SrcPtr++ != 0) {} // skip along until we hit and end-of-line marker
2686 		DestPtr += LineSkip;
2687 		ZPtr += LineSkip;
2688 	}
2689 	while (--BlitHeight > 0);
2690 }
2691 
2692 
2693 /**********************************************************************************************
2694 Blt8BPPDataTo16BPPBufferTransZIncClipSaveZBurnsThrough
2695 
2696 	Blits an image into the destination buffer, using an ETRLE brush as a source, and a 16-bit
2697 	buffer as a destination. As it is blitting, it checks the Z value of the ZBuffer, and if the
2698 	pixel's Z level is below that of the current pixel, it is written on, and the Z value is
2699 	updated to the current value, for any non-transparent pixels. The Z-buffer is 16 bit, and
2700 	must be the same dimensions (including Pitch) as the destination.
2701 
2702 **********************************************************************************************/
Blt8BPPDataTo16BPPBufferTransZIncClipZSameZBurnsThrough(UINT16 * pBuffer,UINT32 uiDestPitchBYTES,UINT16 * pZBuffer,UINT16 usZValue,HVOBJECT hSrcVObject,INT32 iX,INT32 iY,UINT16 usIndex,SGPRect * clipregion)2703 static void Blt8BPPDataTo16BPPBufferTransZIncClipZSameZBurnsThrough(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion)
2704 {
2705 	UINT32 Unblitted;
2706 	INT32  LSCount;
2707 	UINT16 usZLevel, usZColsToGo, usZStartIndex, usZIndex;
2708 
2709 	Assert(hSrcVObject != NULL);
2710 	Assert(pBuffer     != NULL);
2711 
2712 	// Get Offsets from Index into structure
2713 	ETRLEObject const& pTrav    = hSrcVObject->SubregionProperties(usIndex);
2714 	INT32       const  usHeight = pTrav.usHeight;
2715 	INT32       const  usWidth  = pTrav.usWidth;
2716 
2717 	// Add to start position of dest buffer
2718 	INT32 const iTempX = iX + pTrav.sOffsetX;
2719 	INT32 const iTempY = iY + pTrav.sOffsetY;
2720 
2721 	INT32 ClipX1;
2722 	INT32 ClipY1;
2723 	INT32 ClipX2;
2724 	INT32 ClipY2;
2725 	if (clipregion == NULL)
2726 	{
2727 		ClipX1 = ClippingRect.iLeft;
2728 		ClipY1 = ClippingRect.iTop;
2729 		ClipX2 = ClippingRect.iRight;
2730 		ClipY2 = ClippingRect.iBottom;
2731 	}
2732 	else
2733 	{
2734 		ClipX1 = clipregion->iLeft;
2735 		ClipY1 = clipregion->iTop;
2736 		ClipX2 = clipregion->iRight;
2737 		ClipY2 = clipregion->iBottom;
2738 	}
2739 
2740 	// Calculate rows hanging off each side of the screen
2741 	const INT32 LeftSkip   = __min(ClipX1 -   MIN(ClipX1, iTempX), usWidth);
2742 	INT32       TopSkip    = __min(ClipY1 - __min(ClipY1, iTempY), usHeight);
2743 	const INT32 RightSkip  = __min(  MAX(ClipX2, iTempX + usWidth)  - ClipX2, usWidth);
2744 	const INT32 BottomSkip = __min(__max(ClipY2, iTempY + usHeight) - ClipY2, usHeight);
2745 
2746 	// calculate the remaining rows and columns to blit
2747 	const INT32 BlitLength = usWidth  - LeftSkip - RightSkip;
2748 	INT32       BlitHeight = usHeight - TopSkip  - BottomSkip;
2749 
2750 	// check if whole thing is clipped
2751 	if (LeftSkip >= usWidth  || RightSkip  >= usWidth)  return;
2752 	if (TopSkip  >= usHeight || BottomSkip >= usHeight) return;
2753 
2754 	UINT8 const* SrcPtr   = hSrcVObject->PixData(pTrav);
2755 	UINT8*       DestPtr  = (UINT8*)pBuffer  + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
2756 	UINT8*       ZPtr     = (UINT8*)pZBuffer + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
2757 	const UINT32 LineSkip = uiDestPitchBYTES - BlitLength * 2;
2758 	UINT16 const* const p16BPPPalette = hSrcVObject->CurrentShade();
2759 
2760 	if (hSrcVObject->ppZStripInfo == NULL)
2761 	{
2762 		SLOGW("Missing Z-Strip info on multi-Z object");
2763 		return;
2764 	}
2765 	// setup for the z-column blitting stuff
2766 	const ZStripInfo* const pZInfo = hSrcVObject->ppZStripInfo[usIndex];
2767 	if (pZInfo == NULL)
2768 	{
2769 		SLOGW("Missing Z-Strip info on multi-Z object");
2770 		return;
2771 	}
2772 
2773 	UINT16 usZStartLevel = (INT16)usZValue + pZInfo->bInitialZChange * Z_STRIP_DELTA_Y;
2774 	// set to odd number of pixels for first column
2775 
2776 	UINT16 usZStartCols;
2777 	if (LeftSkip > pZInfo->ubFirstZStripWidth)
2778 	{
2779 		usZStartCols = LeftSkip - pZInfo->ubFirstZStripWidth;
2780 		usZStartCols = 20 - usZStartCols % 20;
2781 	}
2782 	else if (LeftSkip < pZInfo->ubFirstZStripWidth)
2783 	{
2784 		usZStartCols  = pZInfo->ubFirstZStripWidth - LeftSkip;
2785 	}
2786 	else
2787 	{
2788 		usZStartCols = 20;
2789 	}
2790 
2791 	usZColsToGo = usZStartCols;
2792 
2793 	const INT8* const pZArray = pZInfo->pbZChange;
2794 
2795 	if (LeftSkip >= pZInfo->ubFirstZStripWidth)
2796 	{
2797 		// Index into array after doing left clipping
2798 		usZStartIndex = 1 + (LeftSkip - pZInfo->ubFirstZStripWidth) / 20;
2799 
2800 		//calculates the Z-value after left-side clipping
2801 		if (usZStartIndex)
2802 		{
2803 			for (UINT16 i = 0; i < usZStartIndex; i++)
2804 			{
2805 				switch (pZArray[i])
2806 				{
2807 					case -1: usZStartLevel -= Z_STRIP_DELTA_Y; break;
2808 					case  0: /* no change */                   break;
2809 					case  1: usZStartLevel += Z_STRIP_DELTA_Y; break;
2810 				}
2811 			}
2812 		}
2813 	}
2814 	else
2815 	{
2816 		usZStartIndex = 0;
2817 	}
2818 
2819 	usZLevel = usZStartLevel;
2820 	usZIndex = usZStartIndex;
2821 
2822 	UINT32 PxCount;
2823 
2824 	while (TopSkip > 0)
2825 	{
2826 		for (;;)
2827 		{
2828 			PxCount = *SrcPtr++;
2829 			if (PxCount & 0x80) continue;
2830 			if (PxCount == 0) break;
2831 			SrcPtr += PxCount;
2832 		}
2833 		TopSkip--;
2834 	}
2835 
2836 	do
2837 	{
2838 		usZLevel = usZStartLevel;
2839 		usZIndex = usZStartIndex;
2840 		usZColsToGo = usZStartCols;
2841 		for (LSCount = LeftSkip; LSCount > 0; LSCount -= PxCount)
2842 		{
2843 			PxCount = *SrcPtr++;
2844 			if (PxCount & 0x80)
2845 			{
2846 				PxCount &= 0x7F;
2847 				if (PxCount > static_cast<UINT32>(LSCount))
2848 				{
2849 					PxCount -= LSCount;
2850 					LSCount = BlitLength;
2851 					goto BlitTransparent;
2852 				}
2853 			}
2854 			else
2855 			{
2856 				if (PxCount > static_cast<UINT32>(LSCount))
2857 				{
2858 					SrcPtr += LSCount;
2859 					PxCount -= LSCount;
2860 					LSCount = BlitLength;
2861 					goto BlitNonTransLoop;
2862 				}
2863 				SrcPtr += PxCount;
2864 			}
2865 		}
2866 
2867 		LSCount = BlitLength;
2868 		while (LSCount > 0)
2869 		{
2870 			PxCount = *SrcPtr++;
2871 			if (PxCount & 0x80)
2872 			{
2873 BlitTransparent: // skip transparent pixels
2874 				PxCount &= 0x7F;
2875 				if (PxCount > static_cast<UINT32>(LSCount)) PxCount = LSCount;
2876 				LSCount -= PxCount;
2877 				DestPtr += 2 * PxCount;
2878 				ZPtr    += 2 * PxCount;
2879 				for (;;)
2880 				{
2881 					if (PxCount >= usZColsToGo)
2882 					{
2883 						PxCount -= usZColsToGo;
2884 						usZColsToGo = 20;
2885 
2886 						INT8 delta = pZArray[usZIndex++];
2887 						if (delta < 0)
2888 						{
2889 							usZLevel -= Z_STRIP_DELTA_Y;
2890 						}
2891 						else if (delta > 0)
2892 						{
2893 							usZLevel += Z_STRIP_DELTA_Y;
2894 						}
2895 					}
2896 					else
2897 					{
2898 						usZColsToGo -= PxCount;
2899 						break;
2900 					}
2901 				}
2902 			}
2903 			else
2904 			{
2905 BlitNonTransLoop: // blit non-transparent pixels
2906 				if (PxCount > static_cast<UINT32>(LSCount))
2907 				{
2908 					Unblitted = PxCount - LSCount;
2909 					PxCount = LSCount;
2910 				}
2911 				else
2912 				{
2913 					Unblitted = 0;
2914 				}
2915 				LSCount -= PxCount;
2916 
2917 				do
2918 				{
2919 					if (*(UINT16*)ZPtr <= usZLevel)
2920 					{
2921 						*(UINT16*)ZPtr = usZLevel;
2922 						*(UINT16*)DestPtr = p16BPPPalette[*SrcPtr];
2923 					}
2924 					SrcPtr++;
2925 					DestPtr += 2;
2926 					ZPtr += 2;
2927 					if (--usZColsToGo == 0)
2928 					{
2929 						usZColsToGo = 20;
2930 
2931 						INT8 delta = pZArray[usZIndex++];
2932 						if (delta < 0)
2933 						{
2934 							usZLevel -= Z_STRIP_DELTA_Y;
2935 						}
2936 						else if (delta > 0)
2937 						{
2938 							usZLevel += Z_STRIP_DELTA_Y;
2939 						}
2940 					}
2941 				}
2942 				while (--PxCount > 0);
2943 				SrcPtr += Unblitted;
2944 			}
2945 		}
2946 
2947 		while (*SrcPtr++ != 0) {} // skip along until we hit and end-of-line marker
2948 		DestPtr += LineSkip;
2949 		ZPtr += LineSkip;
2950 	}
2951 	while (--BlitHeight > 0);
2952 }
2953 
2954 
2955 /**********************************************************************************************
2956 Blt8BPPDataTo16BPPBufferTransZIncObscureClip
2957 
2958 	Blits an image into the destination buffer, using an ETRLE brush as a source, and a 16-bit
2959 	buffer as a destination. As it is blitting, it checks the Z value of the ZBuffer, and if the
2960 	pixel's Z level is below that of the current pixel, it is written on, and the Z value is
2961 	updated to the current value, for any non-transparent pixels. The Z-buffer is 16 bit, and
2962 	must be the same dimensions (including Pitch) as the destination.
2963 
2964 	//ATE: This blitter makes the values that are =< z value pixellate rather than not
2965 	// render at all
2966 
2967 **********************************************************************************************/
Blt8BPPDataTo16BPPBufferTransZIncObscureClip(UINT16 * pBuffer,UINT32 uiDestPitchBYTES,UINT16 * pZBuffer,UINT16 usZValue,HVOBJECT hSrcVObject,INT32 iX,INT32 iY,UINT16 usIndex,SGPRect * clipregion)2968 static void Blt8BPPDataTo16BPPBufferTransZIncObscureClip(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion)
2969 {
2970 	UINT32 Unblitted;
2971 	INT32  LSCount;
2972 	UINT16 usZLevel, usZColsToGo, usZIndex;
2973 
2974 	Assert(hSrcVObject != NULL);
2975 	Assert(pBuffer     != NULL);
2976 
2977 	// Get Offsets from Index into structure
2978 	ETRLEObject const& pTrav    = hSrcVObject->SubregionProperties(usIndex);
2979 	INT32       const  usHeight = pTrav.usHeight;
2980 	INT32       const  usWidth  = pTrav.usWidth;
2981 
2982 	// Add to start position of dest buffer
2983 	INT32 const iTempX = iX + pTrav.sOffsetX;
2984 	INT32 const iTempY = iY + pTrav.sOffsetY;
2985 
2986 	INT32 ClipX1;
2987 	INT32 ClipY1;
2988 	INT32 ClipX2;
2989 	INT32 ClipY2;
2990 	if (clipregion == NULL)
2991 	{
2992 		ClipX1 = ClippingRect.iLeft;
2993 		ClipY1 = ClippingRect.iTop;
2994 		ClipX2 = ClippingRect.iRight;
2995 		ClipY2 = ClippingRect.iBottom;
2996 	}
2997 	else
2998 	{
2999 		ClipX1 = clipregion->iLeft;
3000 		ClipY1 = clipregion->iTop;
3001 		ClipX2 = clipregion->iRight;
3002 		ClipY2 = clipregion->iBottom;
3003 	}
3004 
3005 	// Calculate rows hanging off each side of the screen
3006 	const INT32 LeftSkip   = __min(ClipX1 -   MIN(ClipX1, iTempX), usWidth);
3007 	INT32       TopSkip    = __min(ClipY1 - __min(ClipY1, iTempY), usHeight);
3008 	const INT32 RightSkip  = __min(  MAX(ClipX2, iTempX + usWidth)  - ClipX2, usWidth);
3009 	const INT32 BottomSkip = __min(__max(ClipY2, iTempY + usHeight) - ClipY2, usHeight);
3010 
3011 	UINT32 uiLineFlag = iTempY & 1;
3012 
3013 	// calculate the remaining rows and columns to blit
3014 	const INT32 BlitLength = usWidth  - LeftSkip - RightSkip;
3015 	INT32       BlitHeight = usHeight - TopSkip  - BottomSkip;
3016 
3017 	// check if whole thing is clipped
3018 	if (LeftSkip >= usWidth  || RightSkip  >= usWidth)  return;
3019 	if (TopSkip  >= usHeight || BottomSkip >= usHeight) return;
3020 
3021 	UINT8 const* SrcPtr   = hSrcVObject->PixData(pTrav);
3022 	UINT8*       DestPtr  = (UINT8*)pBuffer  + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
3023 	UINT8*       ZPtr     = (UINT8*)pZBuffer + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
3024 	const UINT32 LineSkip = uiDestPitchBYTES - BlitLength * 2;
3025 	UINT16 const* const p16BPPPalette = hSrcVObject->CurrentShade();
3026 
3027 	if (hSrcVObject->ppZStripInfo == NULL)
3028 	{
3029 		SLOGW("Missing Z-Strip info on multi-Z object");
3030 		return;
3031 	}
3032 	// setup for the z-column blitting stuff
3033 	const ZStripInfo* const pZInfo = hSrcVObject->ppZStripInfo[usIndex];
3034 	if (pZInfo == NULL)
3035 	{
3036 		SLOGW("Missing Z-Strip info on multi-Z object");
3037 		return;
3038 	}
3039 
3040 	UINT16 usZStartLevel = (INT16)usZValue + pZInfo->bInitialZChange * Z_STRIP_DELTA_Y;
3041 	// set to odd number of pixels for first column
3042 
3043 	UINT16 usZStartCols;
3044 	if (LeftSkip > pZInfo->ubFirstZStripWidth)
3045 	{
3046 		usZStartCols = LeftSkip - pZInfo->ubFirstZStripWidth;
3047 		usZStartCols = 20 - usZStartCols % 20;
3048 	}
3049 	else if (LeftSkip < pZInfo->ubFirstZStripWidth)
3050 	{
3051 		usZStartCols = pZInfo->ubFirstZStripWidth - LeftSkip;
3052 	}
3053 	else
3054 	{
3055 		usZStartCols = 20;
3056 	}
3057 
3058 	usZColsToGo = usZStartCols;
3059 
3060 	const INT8* const pZArray  = pZInfo->pbZChange;
3061 
3062 	UINT16 usZStartIndex;
3063 	if (LeftSkip >= pZInfo->ubFirstZStripWidth)
3064 	{
3065 		// Index into array after doing left clipping
3066 		usZStartIndex = 1 + (LeftSkip - pZInfo->ubFirstZStripWidth) / 20;
3067 
3068 		//calculates the Z-value after left-side clipping
3069 		if (usZStartIndex)
3070 		{
3071 			for (UINT16 i = 0; i < usZStartIndex; i++)
3072 			{
3073 				switch (pZArray[i])
3074 				{
3075 					case -1: usZStartLevel -= Z_STRIP_DELTA_Y; break;
3076 					case  0: /* no change */                   break;
3077 					case  1: usZStartLevel += Z_STRIP_DELTA_Y; break;
3078 				}
3079 			}
3080 		}
3081 	}
3082 	else
3083 	{
3084 		usZStartIndex = 0;
3085 	}
3086 
3087 	usZLevel = usZStartLevel;
3088 	usZIndex = usZStartIndex;
3089 
3090 	UINT32 PxCount;
3091 
3092 	while (TopSkip > 0)
3093 	{
3094 		for (;;)
3095 		{
3096 			PxCount = *SrcPtr++;
3097 			if (PxCount & 0x80) continue;
3098 			if (PxCount == 0) break;
3099 			SrcPtr += PxCount;
3100 		}
3101 		uiLineFlag ^= 1; // XXX evaluate before loop
3102 		TopSkip--;
3103 	}
3104 
3105 	do
3106 	{
3107 		usZLevel = usZStartLevel;
3108 		usZIndex = usZStartIndex;
3109 		usZColsToGo = usZStartCols;
3110 		for (LSCount = LeftSkip; LSCount > 0; LSCount -= PxCount)
3111 		{
3112 			PxCount = *SrcPtr++;
3113 			if (PxCount & 0x80)
3114 			{
3115 				PxCount &= 0x7F;
3116 				if (PxCount > static_cast<UINT32>(LSCount))
3117 				{
3118 					PxCount -= LSCount;
3119 					LSCount = BlitLength;
3120 					goto BlitTransparent;
3121 				}
3122 			}
3123 			else
3124 			{
3125 				if (PxCount > static_cast<UINT32>(LSCount))
3126 				{
3127 					SrcPtr += LSCount;
3128 					PxCount -= LSCount;
3129 					LSCount = BlitLength;
3130 					goto BlitNonTransLoop;
3131 				}
3132 				SrcPtr += PxCount;
3133 			}
3134 		}
3135 
3136 		LSCount = BlitLength;
3137 		while (LSCount > 0)
3138 		{
3139 			PxCount = *SrcPtr++;
3140 			if (PxCount & 0x80)
3141 			{
3142 BlitTransparent: // skip transparent pixels
3143 				PxCount &= 0x7F;
3144 				if (PxCount > static_cast<UINT32>(LSCount)) PxCount = LSCount;
3145 				LSCount -= PxCount;
3146 				DestPtr += 2 * PxCount;
3147 				ZPtr    += 2 * PxCount;
3148 				for (;;)
3149 				{
3150 					if (PxCount >= usZColsToGo)
3151 					{
3152 						PxCount -= usZColsToGo;
3153 						usZColsToGo = 20;
3154 
3155 						INT8 delta = pZArray[usZIndex++];
3156 						if (delta < 0)
3157 						{
3158 							usZLevel -= Z_STRIP_DELTA_Y;
3159 						}
3160 						else if (delta > 0)
3161 						{
3162 							usZLevel += Z_STRIP_DELTA_Y;
3163 						}
3164 					}
3165 					else
3166 					{
3167 						usZColsToGo -= PxCount;
3168 						break;
3169 					}
3170 				}
3171 			}
3172 			else
3173 			{
3174 BlitNonTransLoop: // blit non-transparent pixels
3175 				if (PxCount > static_cast<UINT32>(LSCount))
3176 				{
3177 					Unblitted = PxCount - LSCount;
3178 					PxCount = LSCount;
3179 				}
3180 				else
3181 				{
3182 					Unblitted = 0;
3183 				}
3184 				LSCount -= PxCount;
3185 
3186 				do
3187 				{
3188 					if (*(UINT16*)ZPtr < usZLevel ||
3189 							uiLineFlag == (((uintptr_t)DestPtr & 2) != 0)) // XXX update Z when pixelating?
3190 					{
3191 						*(UINT16*)ZPtr = usZLevel;
3192 						*(UINT16*)DestPtr = p16BPPPalette[*SrcPtr];
3193 					}
3194 					SrcPtr++;
3195 					DestPtr += 2;
3196 					ZPtr += 2;
3197 					if (--usZColsToGo == 0)
3198 					{
3199 						usZColsToGo = 20;
3200 
3201 						INT8 delta = pZArray[usZIndex++];
3202 						if (delta < 0)
3203 						{
3204 							usZLevel -= Z_STRIP_DELTA_Y;
3205 						}
3206 						else if (delta > 0)
3207 						{
3208 							usZLevel += Z_STRIP_DELTA_Y;
3209 						}
3210 					}
3211 				}
3212 				while (--PxCount > 0);
3213 				SrcPtr += Unblitted;
3214 			}
3215 		}
3216 
3217 		while (*SrcPtr++ != 0) {} // skip along until we hit and end-of-line marker
3218 		uiLineFlag ^= 1;
3219 		DestPtr += LineSkip;
3220 		ZPtr += LineSkip;
3221 	}
3222 	while (--BlitHeight > 0);
3223 }
3224 
3225 
3226 /* Blitter Specs
3227 	* 1) 8 to 16 bpp
3228 	* 2) strip z-blitter
3229 	* 3) clipped
3230 	* 4) trans shadow - if value is 254, makes a shadow */
Blt8BPPDataTo16BPPBufferTransZTransShadowIncObscureClip(UINT16 * pBuffer,UINT32 uiDestPitchBYTES,UINT16 * pZBuffer,UINT16 usZValue,HVOBJECT hSrcVObject,INT32 iX,INT32 iY,UINT16 usIndex,SGPRect * clipregion,INT16 sZIndex,const UINT16 * p16BPPPalette)3231 static void Blt8BPPDataTo16BPPBufferTransZTransShadowIncObscureClip(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion, INT16 sZIndex, const UINT16* p16BPPPalette)
3232 {
3233 	UINT32 Unblitted;
3234 	INT32  LSCount;
3235 	UINT16 usZLevel, usZColsToGo, usZIndex;
3236 
3237 	Assert(hSrcVObject != NULL);
3238 	Assert(pBuffer     != NULL);
3239 
3240 	// Get Offsets from Index into structure
3241 	ETRLEObject const& pTrav    = hSrcVObject->SubregionProperties(usIndex);
3242 	INT32       const  usHeight = pTrav.usHeight;
3243 	INT32       const  usWidth  = pTrav.usWidth;
3244 
3245 	// Add to start position of dest buffer
3246 	INT32 const iTempX = iX + pTrav.sOffsetX;
3247 	INT32 const iTempY = iY + pTrav.sOffsetY;
3248 
3249 	INT32 ClipX1;
3250 	INT32 ClipY1;
3251 	INT32 ClipX2;
3252 	INT32 ClipY2;
3253 	if (clipregion == NULL)
3254 	{
3255 		ClipX1 = ClippingRect.iLeft;
3256 		ClipY1 = ClippingRect.iTop;
3257 		ClipX2 = ClippingRect.iRight;
3258 		ClipY2 = ClippingRect.iBottom;
3259 	}
3260 	else
3261 	{
3262 		ClipX1 = clipregion->iLeft;
3263 		ClipY1 = clipregion->iTop;
3264 		ClipX2 = clipregion->iRight;
3265 		ClipY2 = clipregion->iBottom;
3266 	}
3267 
3268 	// Calculate rows hanging off each side of the screen
3269 	const INT32 LeftSkip   = __min(ClipX1 -   MIN(ClipX1, iTempX), usWidth);
3270 	INT32       TopSkip    = __min(ClipY1 - __min(ClipY1, iTempY), usHeight);
3271 	const INT32 RightSkip  = __min(  MAX(ClipX2, iTempX + usWidth)  - ClipX2, usWidth);
3272 	const INT32 BottomSkip = __min(__max(ClipY2, iTempY + usHeight) - ClipY2, usHeight);
3273 
3274 	UINT32 uiLineFlag = iTempY & 1;
3275 
3276 	// calculate the remaining rows and columns to blit
3277 	const INT32 BlitLength = usWidth - LeftSkip - RightSkip;
3278 	INT32       BlitHeight = usHeight - TopSkip - BottomSkip;
3279 
3280 	// check if whole thing is clipped
3281 	if (LeftSkip >= usWidth  || RightSkip  >= usWidth)  return;
3282 	if (TopSkip  >= usHeight || BottomSkip >= usHeight) return;
3283 
3284 	UINT8 const* SrcPtr   = hSrcVObject->PixData(pTrav);
3285 	UINT8*       DestPtr = (UINT8*)pBuffer  + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
3286 	UINT8*       ZPtr    = (UINT8*)pZBuffer + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
3287 	const UINT32 LineSkip = uiDestPitchBYTES - BlitLength * 2;
3288 
3289 	if (hSrcVObject->ppZStripInfo == NULL)
3290 	{
3291 		SLOGW("Missing Z-Strip info on multi-Z object");
3292 		return;
3293 	}
3294 	// setup for the z-column blitting stuff
3295 	const ZStripInfo* const pZInfo = hSrcVObject->ppZStripInfo[sZIndex];
3296 	if (pZInfo == NULL)
3297 	{
3298 		SLOGW("Missing Z-Strip info on multi-Z object");
3299 		return;
3300 	}
3301 
3302 	UINT16 usZStartLevel = (INT16)usZValue + pZInfo->bInitialZChange * Z_SUBLAYERS * 10;
3303 
3304 	UINT16 usZStartCols;
3305 	if (LeftSkip > pZInfo->ubFirstZStripWidth)
3306 	{
3307 		usZStartCols = LeftSkip - pZInfo->ubFirstZStripWidth;
3308 		usZStartCols = 20 - usZStartCols % 20;
3309 	}
3310 	else if (LeftSkip < pZInfo->ubFirstZStripWidth)
3311 	{
3312 		usZStartCols = pZInfo->ubFirstZStripWidth - LeftSkip;
3313 	}
3314 	else
3315 	{
3316 		usZStartCols = 20;
3317 	}
3318 
3319 	// set to odd number of pixels for first column
3320 	usZColsToGo = usZStartCols;
3321 
3322 	const INT8* const pZArray = pZInfo->pbZChange;
3323 
3324 	UINT16 usZStartIndex;
3325 	if (LeftSkip >= usZColsToGo)
3326 	{
3327 		// Index into array after doing left clipping
3328 		usZStartIndex = 1 + (LeftSkip - pZInfo->ubFirstZStripWidth) / 20;
3329 
3330 		//calculates the Z-value after left-side clipping
3331 		if (usZStartIndex)
3332 		{
3333 			for (UINT16 i = 0; i < usZStartIndex; i++)
3334 			{
3335 				switch (pZArray[i])
3336 				{
3337 					case -1: usZStartLevel -= Z_SUBLAYERS; break;
3338 					case  0: /* no change */               break;
3339 					case  1: usZStartLevel += Z_SUBLAYERS; break;
3340 				}
3341 			}
3342 		}
3343 	}
3344 	else
3345 	{
3346 		usZStartIndex = 0;
3347 	}
3348 
3349 	usZLevel = usZStartLevel;
3350 	usZIndex = usZStartIndex;
3351 
3352 	UINT32 PxCount;
3353 
3354 	while (TopSkip > 0)
3355 	{
3356 		for (;;)
3357 		{
3358 			PxCount = *SrcPtr++;
3359 			if (PxCount & 0x80) continue;
3360 			if (PxCount == 0) break;
3361 			SrcPtr += PxCount;
3362 		}
3363 		TopSkip--;
3364 	}
3365 
3366 	do
3367 	{
3368 		usZLevel = usZStartLevel;
3369 		usZIndex = usZStartIndex;
3370 		usZColsToGo = usZStartCols;
3371 		for (LSCount = LeftSkip; LSCount > 0; LSCount -= PxCount)
3372 		{
3373 			PxCount = *SrcPtr++;
3374 			if (PxCount & 0x80)
3375 			{
3376 				PxCount &= 0x7F;
3377 				if (PxCount > static_cast<UINT32>(LSCount))
3378 				{
3379 					PxCount -= LSCount;
3380 					LSCount = BlitLength;
3381 					goto BlitTransparent;
3382 				}
3383 			}
3384 			else
3385 			{
3386 				if (PxCount > static_cast<UINT32>(LSCount))
3387 				{
3388 					SrcPtr += LSCount;
3389 					PxCount -= LSCount;
3390 					LSCount = BlitLength;
3391 					goto BlitNonTransLoop;
3392 				}
3393 				SrcPtr += PxCount;
3394 			}
3395 		}
3396 
3397 		LSCount = BlitLength;
3398 		while (LSCount > 0)
3399 		{
3400 			PxCount = *SrcPtr++;
3401 			if (PxCount & 0x80)
3402 			{
3403 BlitTransparent: // skip transparent pixels
3404 				PxCount &= 0x7F;
3405 				if (PxCount > static_cast<UINT32>(LSCount)) PxCount = LSCount;
3406 				LSCount -= PxCount;
3407 				DestPtr += 2 * PxCount;
3408 				ZPtr    += 2 * PxCount;
3409 				for (;;)
3410 				{
3411 					if (PxCount >= usZColsToGo)
3412 					{
3413 						PxCount -= usZColsToGo;
3414 						usZColsToGo = 20;
3415 
3416 						INT8 delta = pZArray[usZIndex++];
3417 						if (delta < 0)
3418 						{
3419 							usZLevel -= Z_STRIP_DELTA_Y;
3420 						}
3421 						else if (delta > 0)
3422 						{
3423 							usZLevel += Z_STRIP_DELTA_Y;
3424 						}
3425 					}
3426 					else
3427 					{
3428 						usZColsToGo -= PxCount;
3429 						break;
3430 					}
3431 				}
3432 			}
3433 			else
3434 			{
3435 BlitNonTransLoop: // blit non-transparent pixels
3436 				if (PxCount > static_cast<UINT32>(LSCount))
3437 				{
3438 					Unblitted = PxCount - LSCount;
3439 					PxCount = LSCount;
3440 				}
3441 				else
3442 				{
3443 					Unblitted = 0;
3444 				}
3445 				LSCount -= PxCount;
3446 
3447 				do
3448 				{
3449 					if (*(UINT16*)ZPtr < usZLevel ||
3450 							uiLineFlag == (((uintptr_t)DestPtr & 2) != 0)) // XXX update Z when pixelating?
3451 					{
3452 						*(UINT16*)ZPtr = usZLevel;
3453 						UINT8 Px = *SrcPtr;
3454 						if (Px == 254)
3455 						{
3456 							*(UINT16*)DestPtr = ShadeTable[*(UINT16*)DestPtr];
3457 						}
3458 						else
3459 						{
3460 							*(UINT16*)DestPtr = p16BPPPalette[Px];
3461 						}
3462 					}
3463 					SrcPtr++;
3464 					DestPtr += 2;
3465 					ZPtr += 2;
3466 					if (--usZColsToGo == 0)
3467 					{
3468 						usZColsToGo = 20;
3469 
3470 						INT8 delta = pZArray[usZIndex++];
3471 						if (delta < 0)
3472 						{
3473 							usZLevel -= Z_STRIP_DELTA_Y;
3474 						}
3475 						else if (delta > 0)
3476 						{
3477 							usZLevel += Z_STRIP_DELTA_Y;
3478 						}
3479 					}
3480 				}
3481 				while (--PxCount > 0);
3482 				SrcPtr += Unblitted;
3483 			}
3484 		}
3485 
3486 		while (*SrcPtr++ != 0) {} // skip along until we hit and end-of-line marker
3487 		uiLineFlag ^= 1;
3488 		DestPtr += LineSkip;
3489 		ZPtr += LineSkip;
3490 	}
3491 	while (--BlitHeight > 0);
3492 }
3493 
3494 /* Blitter Specs
3495 	* 1) 8 to 16 bpp
3496 	* 2) strip z-blitter
3497 	* 3) clipped
3498 	* 4) trans shadow - if value is 254, makes a shadow */
Blt8BPPDataTo16BPPBufferTransZTransShadowIncClip(UINT16 * pBuffer,UINT32 uiDestPitchBYTES,UINT16 * pZBuffer,UINT16 usZValue,HVOBJECT hSrcVObject,INT32 iX,INT32 iY,UINT16 usIndex,SGPRect * clipregion,INT16 sZIndex,const UINT16 * p16BPPPalette)3499 static void Blt8BPPDataTo16BPPBufferTransZTransShadowIncClip(UINT16* pBuffer, UINT32 uiDestPitchBYTES, UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect* clipregion, INT16 sZIndex, const UINT16* p16BPPPalette)
3500 {
3501 	UINT32 Unblitted;
3502 	INT32  LSCount;
3503 	UINT16 usZLevel, usZColsToGo, usZIndex;
3504 
3505 	Assert(hSrcVObject != NULL);
3506 	Assert(pBuffer     != NULL);
3507 
3508 	// Get Offsets from Index into structure
3509 	ETRLEObject const& pTrav    = hSrcVObject->SubregionProperties(usIndex);
3510 	INT32       const  usHeight = pTrav.usHeight;
3511 	INT32       const  usWidth  = pTrav.usWidth;
3512 
3513 	// Add to start position of dest buffer
3514 	INT32 const iTempX = iX + pTrav.sOffsetX;
3515 	INT32 const iTempY = iY + pTrav.sOffsetY;
3516 
3517 	INT32 ClipX1;
3518 	INT32 ClipY1;
3519 	INT32 ClipX2;
3520 	INT32 ClipY2;
3521 	if (clipregion == NULL)
3522 	{
3523 		ClipX1 = ClippingRect.iLeft;
3524 		ClipY1 = ClippingRect.iTop;
3525 		ClipX2 = ClippingRect.iRight;
3526 		ClipY2 = ClippingRect.iBottom;
3527 	}
3528 	else
3529 	{
3530 		ClipX1 = clipregion->iLeft;
3531 		ClipY1 = clipregion->iTop;
3532 		ClipX2 = clipregion->iRight;
3533 		ClipY2 = clipregion->iBottom;
3534 	}
3535 
3536 	// Calculate rows hanging off each side of the screen
3537 	const INT32 LeftSkip   = __min(ClipX1 -   MIN(ClipX1, iTempX), usWidth);
3538 	INT32       TopSkip    = __min(ClipY1 - __min(ClipY1, iTempY), usHeight);
3539 	const INT32 RightSkip  = __min(  MAX(ClipX2, iTempX + usWidth)  - ClipX2, usWidth);
3540 	const INT32 BottomSkip = __min(__max(ClipY2, iTempY + usHeight) - ClipY2, usHeight);
3541 
3542 	// calculate the remaining rows and columns to blit
3543 	const INT32 BlitLength = usWidth  - LeftSkip - RightSkip;
3544 	INT32       BlitHeight = usHeight - TopSkip  - BottomSkip;
3545 
3546 	// check if whole thing is clipped
3547 	if (LeftSkip >= usWidth  || RightSkip  >= usWidth)  return;
3548 	if (TopSkip  >= usHeight || BottomSkip >= usHeight) return;
3549 
3550 	UINT8 const* SrcPtr   = hSrcVObject->PixData(pTrav);
3551 	UINT8*       DestPtr  = (UINT8*)pBuffer  + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
3552 	UINT8*       ZPtr     = (UINT8*)pZBuffer + uiDestPitchBYTES * (iTempY + TopSkip) + (iTempX + LeftSkip) * 2;
3553 	const UINT32 LineSkip = uiDestPitchBYTES - BlitLength * 2;
3554 
3555 	if (hSrcVObject->ppZStripInfo == NULL)
3556 	{
3557 		SLOGW("Missing Z-Strip info on multi-Z object");
3558 		return;
3559 	}
3560 	// setup for the z-column blitting stuff
3561 	const ZStripInfo* const pZInfo = hSrcVObject->ppZStripInfo[sZIndex];
3562 	if (pZInfo == NULL)
3563 	{
3564 		SLOGW("Missing Z-Strip info on multi-Z object");
3565 		return;
3566 	}
3567 
3568 	UINT16 usZStartLevel = (INT16)usZValue + pZInfo->bInitialZChange * Z_SUBLAYERS * 10;
3569 
3570 	UINT16 usZStartCols;
3571 	if (LeftSkip > pZInfo->ubFirstZStripWidth)
3572 	{
3573 		usZStartCols = LeftSkip - pZInfo->ubFirstZStripWidth;
3574 		usZStartCols = 20 - usZStartCols % 20;
3575 	}
3576 	else if (LeftSkip < pZInfo->ubFirstZStripWidth)
3577 	{
3578 		usZStartCols = pZInfo->ubFirstZStripWidth - LeftSkip;
3579 	}
3580 	else
3581 	{
3582 		usZStartCols = 20;
3583 	}
3584 
3585 	// set to odd number of pixels for first column
3586 	usZColsToGo = usZStartCols;
3587 
3588 	const INT8* const pZArray = pZInfo->pbZChange;
3589 
3590 	UINT16 usZStartIndex;
3591 	if (LeftSkip >= usZColsToGo)
3592 	{
3593 		// Index into array after doing left clipping
3594 		usZStartIndex = 1 + (LeftSkip - pZInfo->ubFirstZStripWidth) / 20;
3595 
3596 		// calculates the Z-value after left-side clipping
3597 		if (usZStartIndex)
3598 		{
3599 			for (UINT16 i = 0; i < usZStartIndex; i++)
3600 			{
3601 				switch (pZArray[i])
3602 				{
3603 					case -1: usZStartLevel -= Z_SUBLAYERS; break;
3604 					case  0: /* no change */               break;
3605 					case  1: usZStartLevel += Z_SUBLAYERS; break;
3606 				}
3607 			}
3608 		}
3609 	}
3610 	else
3611 	{
3612 		usZStartIndex = 0;
3613 	}
3614 
3615 	usZLevel = usZStartLevel;
3616 	usZIndex = usZStartIndex;
3617 
3618 	UINT32 PxCount;
3619 
3620 	while (TopSkip > 0)
3621 	{
3622 		for (;;)
3623 		{
3624 			PxCount = *SrcPtr++;
3625 			if (PxCount & 0x80) continue;
3626 			if (PxCount == 0) break;
3627 			SrcPtr += PxCount;
3628 		}
3629 		TopSkip--;
3630 	}
3631 
3632 	do
3633 	{
3634 		usZLevel = usZStartLevel;
3635 		usZIndex = usZStartIndex;
3636 		usZColsToGo = usZStartCols;
3637 		for (LSCount = LeftSkip; LSCount > 0; LSCount -= PxCount)
3638 		{
3639 			PxCount = *SrcPtr++;
3640 			if (PxCount & 0x80)
3641 			{
3642 				PxCount &= 0x7F;
3643 				if (PxCount > static_cast<UINT32>(LSCount))
3644 				{
3645 					PxCount -= LSCount;
3646 					LSCount = BlitLength;
3647 					goto BlitTransparent;
3648 				}
3649 			}
3650 			else
3651 			{
3652 				if (PxCount > static_cast<UINT32>(LSCount))
3653 				{
3654 					SrcPtr += LSCount;
3655 					PxCount -= LSCount;
3656 					LSCount = BlitLength;
3657 					goto BlitNonTransLoop;
3658 				}
3659 				SrcPtr += PxCount;
3660 			}
3661 		}
3662 
3663 		LSCount = BlitLength;
3664 		while (LSCount > 0)
3665 		{
3666 			PxCount = *SrcPtr++;
3667 			if (PxCount & 0x80)
3668 			{
3669 BlitTransparent: // skip transparent pixels
3670 				PxCount &= 0x7F;
3671 				if (PxCount > static_cast<UINT32>(LSCount)) PxCount = LSCount;
3672 				LSCount -= PxCount;
3673 				DestPtr += 2 * PxCount;
3674 				ZPtr    += 2 * PxCount;
3675 				for (;;)
3676 				{
3677 					if (PxCount >= usZColsToGo)
3678 					{
3679 						PxCount -= usZColsToGo;
3680 						usZColsToGo = 20;
3681 
3682 						INT8 delta = pZArray[usZIndex++];
3683 						if (delta < 0)
3684 						{
3685 							usZLevel -= Z_STRIP_DELTA_Y;
3686 						}
3687 						else if (delta > 0)
3688 						{
3689 							usZLevel += Z_STRIP_DELTA_Y;
3690 						}
3691 					}
3692 					else
3693 					{
3694 						usZColsToGo -= PxCount;
3695 						break;
3696 					}
3697 				}
3698 			}
3699 			else
3700 			{
3701 BlitNonTransLoop: // blit non-transparent pixels
3702 				if (PxCount > static_cast<UINT32>(LSCount))
3703 				{
3704 					Unblitted = PxCount - LSCount;
3705 					PxCount = LSCount;
3706 				}
3707 				else
3708 				{
3709 					Unblitted = 0;
3710 				}
3711 				LSCount -= PxCount;
3712 
3713 				do
3714 				{
3715 					if (*(UINT16*)ZPtr <= usZLevel)
3716 					{
3717 						*(UINT16*)ZPtr = usZLevel;
3718 
3719 						UINT32 Px = *SrcPtr;
3720 						if (Px == 254)
3721 						{
3722 							*(UINT16*)DestPtr = ShadeTable[*(UINT16*)DestPtr];
3723 						}
3724 						else
3725 						{
3726 							*(UINT16*)DestPtr = p16BPPPalette[*SrcPtr];
3727 						}
3728 					}
3729 					SrcPtr++;
3730 					DestPtr += 2;
3731 					ZPtr += 2;
3732 					if (--usZColsToGo == 0)
3733 					{
3734 						usZColsToGo = 20;
3735 
3736 						INT8 delta = pZArray[usZIndex++];
3737 						if (delta < 0)
3738 						{
3739 							usZLevel -= Z_SUBLAYERS;
3740 						}
3741 						else if (delta > 0)
3742 						{
3743 							usZLevel += Z_SUBLAYERS;
3744 						}
3745 					}
3746 				}
3747 				while (--PxCount > 0);
3748 				SrcPtr += Unblitted;
3749 			}
3750 		}
3751 
3752 		while (*SrcPtr++ != 0) {} // skip along until we hit and end-of-line marker
3753 		DestPtr += LineSkip;
3754 		ZPtr += LineSkip;
3755 	}
3756 	while (--BlitHeight > 0);
3757 }
3758 
3759 
RenderRoomInfo(INT16 sStartPointX_M,INT16 sStartPointY_M,INT16 sStartPointX_S,INT16 sStartPointY_S,INT16 sEndXS,INT16 sEndYS)3760 static void RenderRoomInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS)
3761 {
3762 	INT16 sAnchorPosX_M = sStartPointX_M;
3763 	INT16 sAnchorPosY_M = sStartPointY_M;
3764 	INT16 sAnchorPosX_S = sStartPointX_S;
3765 	INT16 sAnchorPosY_S = sStartPointY_S;
3766 
3767 	SGPVSurface::Lock l(FRAME_BUFFER);
3768 	UINT16* const pDestBuf         = l.Buffer<UINT16>();
3769 	UINT32  const uiDestPitchBYTES = l.Pitch();
3770 
3771 	BOOLEAN bXOddFlag = FALSE;
3772 	do
3773 	{
3774 		INT16 sTempPosX_M = sAnchorPosX_M;
3775 		INT16 sTempPosY_M = sAnchorPosY_M;
3776 		INT16 sTempPosX_S = sAnchorPosX_S;
3777 		INT16 sTempPosY_S = sAnchorPosY_S;
3778 
3779 		if (bXOddFlag) sTempPosX_S += 20;
3780 
3781 		do
3782 		{
3783 			const UINT16 usTileIndex = FASTMAPROWCOLTOPOS(sTempPosY_M, sTempPosX_M);
3784 			if (usTileIndex < GRIDSIZE)
3785 			{
3786 				const INT16 sX = sTempPosX_S + WORLD_TILE_X / 2 - 5;
3787 				INT16       sY = sTempPosY_S + WORLD_TILE_Y / 2 - 5;
3788 
3789 				// THIS ROOM STUFF IS ONLY DONE IN THE EDITOR...
3790 				// ADJUST BY SHEIGHT
3791 				sY -= gpWorldLevelData[usTileIndex].sHeight;
3792 
3793 				if (gubWorldRoomInfo[usTileIndex] != NO_ROOM)
3794 				{
3795 					SetFont(SMALLCOMPFONT);
3796 					SetFontDestBuffer(FRAME_BUFFER, 0, 0, SCREEN_WIDTH, gsVIEWPORT_END_Y);
3797 					switch (gubWorldRoomInfo[usTileIndex] % 5)
3798 					{
3799 						case 0: SetFontForeground(FONT_GRAY3);   break;
3800 						case 1: SetFontForeground(FONT_YELLOW);  break;
3801 						case 2: SetFontForeground(FONT_LTRED);   break;
3802 						case 3: SetFontForeground(FONT_LTBLUE);  break;
3803 						case 4: SetFontForeground(FONT_LTGREEN); break;
3804 					}
3805 					MPrintBuffer(pDestBuf, uiDestPitchBYTES, sX, sY, ST::format("{}", gubWorldRoomInfo[usTileIndex]));
3806 					SetFontDestBuffer(FRAME_BUFFER);
3807 				}
3808 			}
3809 
3810 			sTempPosX_S += 40;
3811 			sTempPosX_M++;
3812 			sTempPosY_M--;
3813 		}
3814 		while (sTempPosX_S < sEndXS);
3815 
3816 		if (bXOddFlag)
3817 		{
3818 			sAnchorPosY_M++;
3819 		}
3820 		else
3821 		{
3822 			sAnchorPosX_M++;
3823 		}
3824 
3825 		bXOddFlag = !bXOddFlag;
3826 		sAnchorPosY_S += 10;
3827 	}
3828 	while (sAnchorPosY_S < sEndYS);
3829 }
3830 
3831 
3832 #ifdef _DEBUG
3833 
RenderFOVDebugInfo(INT16 sStartPointX_M,INT16 sStartPointY_M,INT16 sStartPointX_S,INT16 sStartPointY_S,INT16 sEndXS,INT16 sEndYS)3834 static void RenderFOVDebugInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS)
3835 {
3836 	INT16 sAnchorPosX_M = sStartPointX_M;
3837 	INT16 sAnchorPosY_M = sStartPointY_M;
3838 	INT16 sAnchorPosX_S = sStartPointX_S;
3839 	INT16 sAnchorPosY_S = sStartPointY_S;
3840 
3841 	SGPVSurface::Lock l(FRAME_BUFFER);
3842 	UINT16* const pDestBuf         = l.Buffer<UINT16>();
3843 	UINT32  const uiDestPitchBYTES = l.Pitch();
3844 
3845 	BOOLEAN bXOddFlag = FALSE;
3846 	do
3847 	{
3848 		INT16 sTempPosX_M = sAnchorPosX_M;
3849 		INT16 sTempPosY_M = sAnchorPosY_M;
3850 		INT16 sTempPosX_S = sAnchorPosX_S;
3851 		INT16 sTempPosY_S = sAnchorPosY_S;
3852 
3853 		if (bXOddFlag) sTempPosX_S += 20;
3854 
3855 		do
3856 		{
3857 			const UINT16 usTileIndex = FASTMAPROWCOLTOPOS(sTempPosY_M, sTempPosX_M);
3858 			if (usTileIndex < GRIDSIZE)
3859 			{
3860 				const INT16 sX = sTempPosX_S + WORLD_TILE_X / 2 - 5;
3861 				INT16       sY = sTempPosY_S + WORLD_TILE_Y / 2 - 5;
3862 
3863 				// Adjust for interface level
3864 				sY -= gpWorldLevelData[usTileIndex].sHeight;
3865 				sY += gsRenderHeight;
3866 
3867 				if (gubFOVDebugInfoInfo[usTileIndex] != 0)
3868 				{
3869 					SetFont(SMALLCOMPFONT);
3870 					SetFontDestBuffer(FRAME_BUFFER, 0, 0, SCREEN_WIDTH, gsVIEWPORT_END_Y);
3871 					SetFontForeground(FONT_GRAY3);
3872 					MPrintBuffer(pDestBuf, uiDestPitchBYTES, sX, sY, ST::format("{}", gubFOVDebugInfoInfo[usTileIndex]));
3873 					SetFontDestBuffer(FRAME_BUFFER);
3874 
3875 					Blt8BPPDataTo16BPPBufferTransparentClip(pDestBuf, uiDestPitchBYTES, gTileDatabase[0].hTileSurface, sTempPosX_S, sTempPosY_S, 0, &gClippingRect);
3876 				}
3877 
3878 				if (gubGridNoMarkers[usTileIndex] == gubGridNoValue)
3879 				{
3880 					SetFont(SMALLCOMPFONT);
3881 					SetFontDestBuffer(FRAME_BUFFER, 0, 0, SCREEN_WIDTH, gsVIEWPORT_END_Y);
3882 					SetFontForeground(FONT_FCOLOR_YELLOW);
3883 					MPrintBuffer(pDestBuf, uiDestPitchBYTES, sX, sY + 4, "x");
3884 					SetFontDestBuffer(FRAME_BUFFER);
3885 				}
3886 			}
3887 
3888 			sTempPosX_S += 40;
3889 			sTempPosX_M++;
3890 			sTempPosY_M--;
3891 		}
3892 		while (sTempPosX_S < sEndXS);
3893 
3894 		if (bXOddFlag)
3895 		{
3896 			sAnchorPosY_M++;
3897 		}
3898 		else
3899 		{
3900 			sAnchorPosX_M++;
3901 		}
3902 
3903 		bXOddFlag = !bXOddFlag;
3904 		sAnchorPosY_S += 10;
3905 	}
3906 	while (sAnchorPosY_S < sEndYS);
3907 }
3908 
3909 
RenderCoverDebugInfo(INT16 sStartPointX_M,INT16 sStartPointY_M,INT16 sStartPointX_S,INT16 sStartPointY_S,INT16 sEndXS,INT16 sEndYS)3910 static void RenderCoverDebugInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS)
3911 {
3912 	INT16 sAnchorPosX_M = sStartPointX_M;
3913 	INT16 sAnchorPosY_M = sStartPointY_M;
3914 	INT16 sAnchorPosX_S = sStartPointX_S;
3915 	INT16 sAnchorPosY_S = sStartPointY_S;
3916 
3917 	SGPVSurface::Lock l(FRAME_BUFFER);
3918 	UINT16* const pDestBuf         = l.Buffer<UINT16>();
3919 	UINT32  const uiDestPitchBYTES = l.Pitch();
3920 
3921 	BOOLEAN bXOddFlag = FALSE;
3922 	do
3923 	{
3924 		INT16 sTempPosX_M = sAnchorPosX_M;
3925 		INT16 sTempPosY_M = sAnchorPosY_M;
3926 		INT16 sTempPosX_S = sAnchorPosX_S;
3927 		INT16 sTempPosY_S = sAnchorPosY_S;
3928 
3929 		if (bXOddFlag) sTempPosX_S += 20;
3930 
3931 		do
3932 		{
3933 			const UINT16 usTileIndex = FASTMAPROWCOLTOPOS(sTempPosY_M, sTempPosX_M);
3934 			if (usTileIndex < GRIDSIZE)
3935 			{
3936 				const INT16 sX = sTempPosX_S + WORLD_TILE_X / 2 - 5;
3937 				INT16       sY = sTempPosY_S + WORLD_TILE_Y / 2 - 5;
3938 
3939 				// Adjust for interface level
3940 				sY -= gpWorldLevelData[usTileIndex].sHeight;
3941 				sY += gsRenderHeight;
3942 
3943 				if (gsCoverValue[usTileIndex] != 0x7F7F)
3944 				{
3945 					SetFont(SMALLCOMPFONT);
3946 					SetFontDestBuffer(FRAME_BUFFER, 0, 0, SCREEN_WIDTH, gsVIEWPORT_END_Y);
3947 					if (usTileIndex == gsBestCover)
3948 					{
3949 						SetFontForeground(FONT_MCOLOR_RED);
3950 					}
3951 					else if (gsCoverValue[usTileIndex] < 0)
3952 					{
3953 						SetFontForeground(FONT_MCOLOR_WHITE);
3954 					}
3955 					else
3956 					{
3957 						SetFontForeground(FONT_GRAY3);
3958 					}
3959 					MPrintBuffer(pDestBuf, uiDestPitchBYTES, sX, sY, ST::format("{}", gsCoverValue[usTileIndex]));
3960 					SetFontDestBuffer(FRAME_BUFFER);
3961 				}
3962 			}
3963 
3964 			sTempPosX_S += 40;
3965 			sTempPosX_M++;
3966 			sTempPosY_M--;
3967 		}
3968 		while (sTempPosX_S < sEndXS);
3969 
3970 		if (bXOddFlag)
3971 		{
3972 			sAnchorPosY_M++;
3973 		}
3974 		else
3975 		{
3976 			sAnchorPosX_M++;
3977 		}
3978 
3979 		bXOddFlag = !bXOddFlag;
3980 		sAnchorPosY_S += 10;
3981 	}
3982 	while (sAnchorPosY_S < sEndYS);
3983 }
3984 
3985 
RenderGridNoVisibleDebugInfo(INT16 sStartPointX_M,INT16 sStartPointY_M,INT16 sStartPointX_S,INT16 sStartPointY_S,INT16 sEndXS,INT16 sEndYS)3986 static void RenderGridNoVisibleDebugInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS)
3987 {
3988 	INT16 sAnchorPosX_M = sStartPointX_M;
3989 	INT16 sAnchorPosY_M = sStartPointY_M;
3990 	INT16 sAnchorPosX_S = sStartPointX_S;
3991 	INT16 sAnchorPosY_S = sStartPointY_S;
3992 
3993 	SGPVSurface::Lock l(FRAME_BUFFER);
3994 	UINT16* const pDestBuf         = l.Buffer<UINT16>();
3995 	UINT32  const uiDestPitchBYTES = l.Pitch();
3996 
3997 	BOOLEAN bXOddFlag = FALSE;
3998 	do
3999 	{
4000 		INT16 sTempPosX_M = sAnchorPosX_M;
4001 		INT16 sTempPosY_M = sAnchorPosY_M;
4002 		INT16 sTempPosX_S = sAnchorPosX_S;
4003 		INT16 sTempPosY_S = sAnchorPosY_S;
4004 
4005 		if (bXOddFlag) sTempPosX_S += 20;
4006 
4007 		do
4008 		{
4009 			const UINT16 usTileIndex = FASTMAPROWCOLTOPOS(sTempPosY_M, sTempPosX_M);
4010 			if (usTileIndex < GRIDSIZE)
4011 			{
4012 				const INT16 sX = sTempPosX_S + WORLD_TILE_X / 2 - 5;
4013 				INT16       sY = sTempPosY_S + WORLD_TILE_Y / 2 - 5;
4014 
4015 				// Adjust for interface level
4016 				sY -= gpWorldLevelData[usTileIndex].sHeight;
4017 				sY += gsRenderHeight;
4018 
4019 				SetFont(SMALLCOMPFONT);
4020 				SetFontDestBuffer(FRAME_BUFFER, 0, 0, SCREEN_WIDTH, gsVIEWPORT_END_Y);
4021 
4022 				if (!GridNoOnVisibleWorldTile(usTileIndex))
4023 				{
4024 					SetFontForeground(FONT_MCOLOR_RED);
4025 				}
4026 				else
4027 				{
4028 					SetFontForeground(FONT_GRAY3);
4029 				}
4030 				MPrintBuffer(pDestBuf, uiDestPitchBYTES, sX, sY, ST::format("{}", usTileIndex));
4031 				SetFontDestBuffer(FRAME_BUFFER);
4032 			}
4033 
4034 			sTempPosX_S += 40;
4035 			sTempPosX_M++;
4036 			sTempPosY_M--;
4037 		}
4038 		while (sTempPosX_S < sEndXS);
4039 
4040 		if (bXOddFlag)
4041 		{
4042 			sAnchorPosY_M++;
4043 		}
4044 		else
4045 		{
4046 			sAnchorPosX_M++;
4047 		}
4048 
4049 		bXOddFlag = !bXOddFlag;
4050 		sAnchorPosY_S += 10;
4051 	}
4052 	while (sAnchorPosY_S < sEndYS);
4053 }
4054 
4055 #endif
4056 
4057 
4058 static void ExamineZBufferForHiddenTiles(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS);
4059 
4060 
ExamineZBufferRect(INT16 sLeft,INT16 sTop,INT16 sRight,INT16 sBottom)4061 static void ExamineZBufferRect(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom)
4062 {
4063 	CalcRenderParameters(sLeft, sTop, sRight, sBottom);
4064 	ExamineZBufferForHiddenTiles(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
4065 }
4066 
4067 
4068 static BOOLEAN IsTileRedundant(UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex);
4069 
4070 
ExamineZBufferForHiddenTiles(INT16 sStartPointX_M,INT16 sStartPointY_M,INT16 sStartPointX_S,INT16 sStartPointY_S,INT16 sEndXS,INT16 sEndYS)4071 static void ExamineZBufferForHiddenTiles(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS)
4072 {
4073 	// Begin Render Loop
4074 	INT16 sAnchorPosX_M = sStartPointX_M;
4075 	INT16 sAnchorPosY_M = sStartPointY_M;
4076 	INT16 sAnchorPosX_S = sStartPointX_S;
4077 	INT16 sAnchorPosY_S = sStartPointY_S;
4078 
4079 	// Get VObject for firt land peice!
4080 	const TILE_ELEMENT* const TileElem = &gTileDatabase[FIRSTTEXTURE1];
4081 
4082 	BOOLEAN bXOddFlag = FALSE;
4083 	do
4084 	{
4085 		INT16       sTempPosX_M = sAnchorPosX_M;
4086 		INT16       sTempPosY_M = sAnchorPosY_M;
4087 		INT16       sTempPosX_S = sAnchorPosX_S;
4088 		const INT16 sTempPosY_S = sAnchorPosY_S;
4089 
4090 		if (bXOddFlag) sTempPosX_S += 20;
4091 
4092 		do
4093 		{
4094 			const UINT16 usTileIndex = FASTMAPROWCOLTOPOS(sTempPosY_M, sTempPosX_M);
4095 			if (usTileIndex < GRIDSIZE)
4096 			{
4097 				// ATE: Don;t let any vehicle sit here....
4098 				if (FindStructure(usTileIndex, STRUCTURE_MOBILE))
4099 				{
4100 					// Continue...
4101 					goto ENDOFLOOP;
4102 				}
4103 
4104 				const INT16 sX = sTempPosX_S;
4105 				INT16       sY = sTempPosY_S - gpWorldLevelData[usTileIndex].sHeight;
4106 
4107 				// Adjust for interface level
4108 				sY += gsRenderHeight;
4109 
4110 				// Caluluate zvalue
4111 				// Look for anything less than struct layer!
4112 				INT16 sWorldX;
4113 				INT16 sZLevel;
4114 				GetAbsoluteScreenXYFromMapPos(usTileIndex, &sWorldX, &sZLevel);
4115 
4116 				sZLevel += gsRenderHeight;
4117 				sZLevel  = sZLevel * Z_SUBLAYERS + STRUCT_Z_LEVEL;
4118 
4119 				if (gpWorldLevelData[usTileIndex].uiFlags & MAPELEMENT_REEVALUATE_REDUNDENCY)
4120 				{
4121 					const INT8 bBlitClipVal = BltIsClippedOrOffScreen(TileElem->hTileSurface, sX, sY, TileElem->usRegionIndex, &gClippingRect);
4122 					if (bBlitClipVal == FALSE)
4123 					{
4124 						// Set flag to not evaluate again!
4125 						gpWorldLevelData[usTileIndex].uiFlags &= ~MAPELEMENT_REEVALUATE_REDUNDENCY;
4126 
4127 						if (IsTileRedundant(gpZBuffer, sZLevel, TileElem->hTileSurface, sX, sY, TileElem->usRegionIndex))
4128 						{
4129 							// Mark in the world!
4130 							gpWorldLevelData[usTileIndex].uiFlags |= MAPELEMENT_REDUNDENT;
4131 						}
4132 						else
4133 						{
4134 							// Un Mark in the world!
4135 							gpWorldLevelData[usTileIndex].uiFlags &= ~MAPELEMENT_REDUNDENT;
4136 						}
4137 					}
4138 				}
4139 			}
4140 
4141 ENDOFLOOP:
4142 			sTempPosX_S += 40;
4143 			sTempPosX_M++;
4144 			sTempPosY_M--;
4145 		} while (sTempPosX_S < sEndXS);
4146 
4147 		if (bXOddFlag)
4148 		{
4149 			++sAnchorPosY_M;
4150 		}
4151 		else
4152 		{
4153 			++sAnchorPosX_M;
4154 		}
4155 
4156 		bXOddFlag = !bXOddFlag;
4157 		sAnchorPosY_S += 10;
4158 	}
4159 	while (sAnchorPosY_S < sEndYS);
4160 }
4161 
4162 
CalcRenderParameters(INT16 sLeft,INT16 sTop,INT16 sRight,INT16 sBottom)4163 static void CalcRenderParameters(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom)
4164 {
4165 	INT16 sTempPosX_W, sTempPosY_W;
4166 
4167 	gOldClipRect = gClippingRect;
4168 
4169 	// Set new clipped rect
4170 	gClippingRect.iLeft   = __max(gsVIEWPORT_START_X,        sLeft);
4171 	gClippingRect.iRight  = __min(gsVIEWPORT_END_X,          sRight);
4172 	gClippingRect.iTop    = __max(gsVIEWPORT_WINDOW_START_Y, sTop);
4173 	gClippingRect.iBottom = __min(gsVIEWPORT_WINDOW_END_Y,   sBottom);
4174 
4175 	gsEndXS = sRight  + VIEWPORT_XOFFSET_S;
4176 	gsEndYS = sBottom + VIEWPORT_YOFFSET_S;
4177 
4178 	const INT16 sRenderCenterX_W = gsRenderCenterX;
4179 	const INT16 sRenderCenterY_W = gsRenderCenterY;
4180 
4181 	// STEP THREE - determine starting point in world coords
4182 	// a) Determine where in screen coords to start rendering
4183 	gsStartPointX_S = g_ui.m_tacticalMapCenterX - (sLeft - VIEWPORT_XOFFSET_S);
4184 	gsStartPointY_S = g_ui.m_tacticalMapCenterY - (sTop  - VIEWPORT_YOFFSET_S);
4185 
4186 	// b) Convert these distances into world distances
4187 	FromScreenToCellCoordinates(gsStartPointX_S, gsStartPointY_S, &sTempPosX_W, &sTempPosY_W);
4188 
4189 	// c) World start point is Render center minus this distance
4190 	const INT16 sStartPointX_W = sRenderCenterX_W - sTempPosX_W + CELL_X_SIZE;
4191 	const INT16 sStartPointY_W = sRenderCenterY_W - sTempPosY_W;
4192 
4193 	// d) screen start point is screen distances minus screen center
4194 	gsStartPointX_S = sLeft - VIEWPORT_XOFFSET_S;
4195 	gsStartPointY_S = sTop  - VIEWPORT_YOFFSET_S;
4196 
4197 	// STEP FOUR - Determine Start block
4198 	// a) Find start block
4199 	gsStartPointX_M = floor(DOUBLE(sStartPointX_W) / DOUBLE(CELL_X_SIZE));
4200 	gsStartPointY_M = floor(DOUBLE(sStartPointY_W) / DOUBLE(CELL_Y_SIZE));
4201 
4202 	// STEP 5 - Determine offsets for tile center and convert to screen values
4203 	// Make sure these coordinates are multiples of scroll steps
4204 	const INT16 sOffsetX_W = sStartPointX_W - gsStartPointX_M * CELL_X_SIZE;
4205 	const INT16 sOffsetY_W = sStartPointY_W - gsStartPointY_M * CELL_Y_SIZE;
4206 
4207 	INT16 sOffsetX_S;
4208 	INT16 sOffsetY_S;
4209 	FromCellToScreenCoordinates(sOffsetX_W, sOffsetY_W, &sOffsetX_S, &sOffsetY_S);
4210 
4211 	gsStartPointX_S -= sOffsetX_S;
4212 	gsStartPointY_S -= sOffsetY_S;
4213 
4214 	/////////////////////////////////////////
4215 	//ATE: CALCULATE LARGER OFFSET VALUES
4216 	gsLEndXS = sRight  + LARGER_VIEWPORT_XOFFSET_S;
4217 	gsLEndYS = sBottom + LARGER_VIEWPORT_YOFFSET_S;
4218 
4219 	// STEP THREE - determine starting point in world coords
4220 	// a) Determine where in screen coords to start rendering
4221 	gsLStartPointX_S = g_ui.m_tacticalMapCenterX - (sLeft - LARGER_VIEWPORT_XOFFSET_S);
4222 	gsLStartPointY_S = g_ui.m_tacticalMapCenterY - (sTop  - LARGER_VIEWPORT_YOFFSET_S);
4223 
4224 	// b) Convert these distances into world distances
4225 	FromScreenToCellCoordinates(gsLStartPointX_S, gsLStartPointY_S, &sTempPosX_W, &sTempPosY_W);
4226 
4227 	// c) World start point is Render center minus this distance
4228 	const INT16 sLStartPointX_W = sRenderCenterX_W - sTempPosX_W + CELL_X_SIZE;
4229 	const INT16 sLStartPointY_W = sRenderCenterY_W - sTempPosY_W;
4230 
4231 	// d) screen start point is screen distances minus screen center
4232 	gsLStartPointX_S = sLeft - LARGER_VIEWPORT_XOFFSET_S;
4233 	gsLStartPointY_S = sTop  - LARGER_VIEWPORT_YOFFSET_S;
4234 
4235 	// STEP FOUR - Determine Start block
4236 	// a) Find start block
4237 	gsLStartPointX_M = floor(DOUBLE(sLStartPointX_W) / DOUBLE(CELL_X_SIZE));
4238 	gsLStartPointY_M = floor(DOUBLE(sLStartPointY_W) / DOUBLE(CELL_Y_SIZE));
4239 
4240 	// STEP 5 - Adjust screen coordinates to tile center, so it matches small viewport
4241 	gsLStartPointX_S -= sOffsetX_S;
4242 	gsLStartPointY_S -= sOffsetY_S;
4243 }
4244 
4245 
ResetRenderParameters(void)4246 static void ResetRenderParameters(void)
4247 {
4248 	// Restore clipping rect
4249 	gClippingRect = gOldClipRect;
4250 }
4251 
4252 
IsTileRedundant(UINT16 * pZBuffer,UINT16 usZValue,HVOBJECT hSrcVObject,INT32 iX,INT32 iY,UINT16 usIndex)4253 static BOOLEAN IsTileRedundant(UINT16* pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex)
4254 {
4255 	BOOLEAN fHidden = TRUE;
4256 
4257 	Assert(hSrcVObject != NULL);
4258 
4259 	// Get Offsets from Index into structure
4260 	ETRLEObject const& pTrav    = hSrcVObject->SubregionProperties(usIndex);
4261 	UINT32             usHeight = pTrav.usHeight;
4262 	UINT32      const  usWidth  = pTrav.usWidth;
4263 
4264 	// Add to start position of dest buffer
4265 	INT32 const iTempX = iX + pTrav.sOffsetX;
4266 	INT32 const iTempY = iY + pTrav.sOffsetY;
4267 
4268 	CHECKF(iTempX >= 0);
4269 	CHECKF(iTempY >= 0);
4270 
4271 	UINT8 const* SrcPtr   = hSrcVObject->PixData(pTrav);
4272 	const UINT8* ZPtr     = (const UINT8*)(pZBuffer + iTempY * SCREEN_WIDTH + iTempX);
4273 	const UINT32 LineSkip = (SCREEN_WIDTH - usWidth) * 2;
4274 
4275 	do
4276 	{
4277 		for (;;)
4278 		{
4279 			UINT8 data = *SrcPtr++;
4280 
4281 			if (data == 0) break;
4282 			if (data & 0x80)
4283 			{
4284 				data &= 0x7F;
4285 				ZPtr += 2 * data;
4286 			}
4287 			else
4288 			{
4289 				SrcPtr += data;
4290 				do
4291 				{
4292 					if (*(const UINT16*)ZPtr < usZValue) return FALSE;
4293 					ZPtr += 2;
4294 				}
4295 				while (--data > 0);
4296 			}
4297 		}
4298 		ZPtr += LineSkip;
4299 	}
4300 	while (--usHeight > 0);
4301 	return fHidden;
4302 }
4303 
4304 
SetRenderCenter(INT16 sNewX,INT16 sNewY)4305 void SetRenderCenter(INT16 sNewX, INT16 sNewY)
4306 {
4307 	if (gfIgnoreScrolling) return;
4308 
4309 	// Apply these new coordinates to the renderer!
4310 	ApplyScrolling(sNewX, sNewY, TRUE, FALSE);
4311 
4312 	// Set flag to ignore scrolling this frame
4313 	gfIgnoreScrollDueToCenterAdjust = TRUE;
4314 
4315 	// Set full render flag!
4316 	// DIRTY THE WORLD!
4317 	SetRenderFlags(RENDER_FLAG_FULL);
4318 
4319 	gfPlotNewMovement = TRUE;
4320 
4321 	if (gfScrollPending)
4322 	{
4323 		// Do a complete rebuild!
4324 		gfScrollPending = FALSE;
4325 
4326 		// Restore Interface!
4327 		RestoreInterface();
4328 
4329 		DeleteVideoOverlaysArea();
4330 	}
4331 
4332 	g_scroll_inertia = false;
4333 }
4334 
4335 
4336 #ifdef _DEBUG
4337 
RenderFOVDebug(void)4338 void RenderFOVDebug(void)
4339 {
4340 	RenderFOVDebugInfo(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
4341 }
4342 
RenderCoverDebug(void)4343 void RenderCoverDebug(void)
4344 {
4345 	RenderCoverDebugInfo(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
4346 }
4347 
4348 #endif
4349 
4350 
4351 #ifdef WITH_UNITTESTS
4352 #undef FAIL
4353 #include "gtest/gtest.h"
4354 
TEST(RenderWorld,asserts)4355 TEST(RenderWorld, asserts)
4356 {
4357 	EXPECT_EQ(lengthof(RenderFX), NUM_RENDER_FX_TYPES);
4358 	EXPECT_EQ(lengthof(RenderFXStartIndex), NUM_RENDER_FX_TYPES);
4359 	EXPECT_EQ(lengthof(g_render_fx_layer_flags), NUM_RENDER_FX_TYPES);
4360 }
4361 
4362 #endif
4363