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