99
1010#include " outlines.h"
1111
12- static int ClampedIndex (int x, int y, int w, int h)
13- {
14- x = std::clamp (x, 0 , w - 1 );
15- y = std::clamp (y, 0 , h - 1 );
16- return x + y * w;
17- }
18-
1912void COutlines::OnConsoleInit ()
2013{
2114 auto FixColorAlpha = [&](const char *pName, unsigned int &ColorInt) {
@@ -48,35 +41,26 @@ void COutlines::OnRender()
4841 if (!g_Config.m_TcOutline )
4942 return ;
5043
51- auto RenderGameTileOutlines = [&](CTile *pTiles, int w, int h, float Scale, int TileType) {
52- // Config
53- float Width;
54- ColorRGBA Color;
55- if (TileType == TILE_SOLID)
56- {
57- Width = g_Config.m_TcOutlineWidthSolid ;
58- Color = color_cast<ColorRGBA>(ColorHSLA (g_Config.m_TcOutlineColorSolid ));
59- }
60- else if (TileType == TILE_FREEZE)
61- {
62- Width = g_Config.m_TcOutlineWidthFreeze ;
63- Color = color_cast<ColorRGBA>(ColorHSLA (g_Config.m_TcOutlineColorFreeze ));
64- }
65- else if (TileType == TILE_UNFREEZE)
66- {
67- Width = g_Config.m_TcOutlineWidthUnfreeze ;
68- Color = color_cast<ColorRGBA>(ColorHSLA (g_Config.m_TcOutlineColorUnfreeze ));
69- }
70- else if (TileType == TILE_DEATH)
71- {
72- Width = g_Config.m_TcOutlineWidthKill ;
73- Color = color_cast<ColorRGBA>(ColorHSLA (g_Config.m_TcOutlineColorKill ));
74- }
75- else
76- {
77- dbg_assert (false , " Invalid value for TileType" );
78- }
44+ auto DoLayer = [&](CMapItemLayerTilemap *pTMap) {
45+ if (!pTMap)
46+ return ;
47+ CTile *pTiles = (CTile *)GameClient ()->Layers ()->Map ()->GetData (pTMap->m_Data );
48+ if (!pTiles)
49+ return ;
50+ const unsigned Size = GameClient ()->Layers ()->Map ()->GetDataSize (pTMap->m_Data );
51+ if (Size < (size_t )pTMap->m_Width * pTMap->m_Height * sizeof (CTile))
52+ return ;
7953
54+ const int w = pTMap->m_Width ;
55+ const int h = pTMap->m_Height ;
56+ auto ClampedIndex = [&](int x, int y)
57+ {
58+ x = std::clamp (x, 0 , w - 1 );
59+ y = std::clamp (y, 0 , h - 1 );
60+ return x + y * w;
61+ };
62+ const float Scale = 32 .0f ;
63+
8064 float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
8165 Graphics ()->GetScreen (&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
8266
@@ -94,193 +78,98 @@ void COutlines::OnRender()
9478 StartY += EdgeY / 2 ;
9579 EndY -= EdgeY / 2 ;
9680 }
81+
9782 Graphics ()->TextureClear ();
9883 Graphics ()->QuadsBegin ();
99- Graphics ()->SetColor (Color);
100-
10184 for (int y = StartY; y < EndY; y++)
10285 {
10386 for (int x = StartX; x < EndX; x++)
10487 {
105- int mx = x;
106- int my = y;
10788
108- int c = ClampedIndex (mx, my, w, h);
109-
110- const unsigned char Index = pTiles[c].m_Index ;
111- const bool IsSolid = Index == TILE_SOLID || Index == TILE_NOHOOK;
112- const bool IsFreeze = Index == TILE_FREEZE || Index == TILE_DFREEZE;
113- const bool IsUnfreeze = Index == TILE_UNFREEZE || Index == TILE_DUNFREEZE;
114- const bool IsKill = Index == TILE_DEATH;
115- const bool Render = (TileType == TILE_SOLID && IsSolid) ||
116- (TileType == TILE_FREEZE && IsFreeze) ||
117- (TileType == TILE_UNFREEZE && IsUnfreeze) ||
118- (TileType == TILE_DEATH && IsKill);
119- if (!Render)
120- continue ;
121-
122- IGraphics::CQuadItem Array[8 ];
123- bool Neighbors[8 ];
124- int Tile;
125- if (IsFreeze && TileType == TILE_FREEZE)
126- {
127- Tile = pTiles[ClampedIndex (mx - 1 , my - 1 , w, h)].m_Index ;
128- Neighbors[0 ] = Tile == TILE_AIR || Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE;
129- Tile = pTiles[ClampedIndex (mx - 0 , my - 1 , w, h)].m_Index ;
130- Neighbors[1 ] = Tile == TILE_AIR || Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE;
131- Tile = pTiles[ClampedIndex (mx + 1 , my - 1 , w, h)].m_Index ;
132- Neighbors[2 ] = Tile == TILE_AIR || Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE;
133- Tile = pTiles[ClampedIndex (mx - 1 , my + 0 , w, h)].m_Index ;
134- Neighbors[3 ] = Tile == TILE_AIR || Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE;
135- Tile = pTiles[ClampedIndex (mx + 1 , my + 0 , w, h)].m_Index ;
136- Neighbors[4 ] = Tile == TILE_AIR || Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE;
137- Tile = pTiles[ClampedIndex (mx - 1 , my + 1 , w, h)].m_Index ;
138- Neighbors[5 ] = Tile == TILE_AIR || Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE;
139- Tile = pTiles[ClampedIndex (mx + 0 , my + 1 , w, h)].m_Index ;
140- Neighbors[6 ] = Tile == TILE_AIR || Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE;
141- Tile = pTiles[ClampedIndex (mx + 1 , my + 1 , w, h)].m_Index ;
142- Neighbors[7 ] = Tile == TILE_AIR || Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE;
143- }
144- else if (IsSolid && TileType == TILE_SOLID)
145- {
146- Tile = pTiles[ClampedIndex (mx - 1 , my - 1 , w, h)].m_Index ;
147- Neighbors[0 ] = Tile != TILE_NOHOOK && Tile != Index;
148- Tile = pTiles[ClampedIndex (mx - 0 , my - 1 , w, h)].m_Index ;
149- Neighbors[1 ] = Tile != TILE_NOHOOK && Tile != Index;
150- Tile = pTiles[ClampedIndex (mx + 1 , my - 1 , w, h)].m_Index ;
151- Neighbors[2 ] = Tile != TILE_NOHOOK && Tile != Index;
152- Tile = pTiles[ClampedIndex (mx - 1 , my + 0 , w, h)].m_Index ;
153- Neighbors[3 ] = Tile != TILE_NOHOOK && Tile != Index;
154- Tile = pTiles[ClampedIndex (mx + 1 , my + 0 , w, h)].m_Index ;
155- Neighbors[4 ] = Tile != TILE_NOHOOK && Tile != Index;
156- Tile = pTiles[ClampedIndex (mx - 1 , my + 1 , w, h)].m_Index ;
157- Neighbors[5 ] = Tile != TILE_NOHOOK && Tile != Index;
158- Tile = pTiles[ClampedIndex (mx + 0 , my + 1 , w, h)].m_Index ;
159- Neighbors[6 ] = Tile != TILE_NOHOOK && Tile != Index;
160- Tile = pTiles[ClampedIndex (mx + 1 , my + 1 , w, h)].m_Index ;
161- Neighbors[7 ] = Tile != TILE_NOHOOK && Tile != Index;
162- }
163- else if (IsKill && TileType == TILE_DEATH)
164- {
165- Tile = pTiles[ClampedIndex (mx - 1 , my - 1 , w, h)].m_Index ;
166- Neighbors[0 ] = Tile != TILE_DEATH && Tile != Index;
167- Tile = pTiles[ClampedIndex (mx - 0 , my - 1 , w, h)].m_Index ;
168- Neighbors[1 ] = Tile != TILE_DEATH && Tile != Index;
169- Tile = pTiles[ClampedIndex (mx + 1 , my - 1 , w, h)].m_Index ;
170- Neighbors[2 ] = Tile != TILE_DEATH && Tile != Index;
171- Tile = pTiles[ClampedIndex (mx - 1 , my + 0 , w, h)].m_Index ;
172- Neighbors[3 ] = Tile != TILE_DEATH && Tile != Index;
173- Tile = pTiles[ClampedIndex (mx + 1 , my + 0 , w, h)].m_Index ;
174- Neighbors[4 ] = Tile != TILE_DEATH && Tile != Index;
175- Tile = pTiles[ClampedIndex (mx - 1 , my + 1 , w, h)].m_Index ;
176- Neighbors[5 ] = Tile != TILE_DEATH && Tile != Index;
177- Tile = pTiles[ClampedIndex (mx + 0 , my + 1 , w, h)].m_Index ;
178- Neighbors[6 ] = Tile != TILE_DEATH && Tile != Index;
179- Tile = pTiles[ClampedIndex (mx + 1 , my + 1 , w, h)].m_Index ;
180- Neighbors[7 ] = Tile != TILE_DEATH && Tile != Index;
181- }
182- else
183- {
184- Tile = pTiles[ClampedIndex (mx - 1 , my - 1 , w, h)].m_Index ;
185- Neighbors[0 ] = Tile != TILE_UNFREEZE && Tile != TILE_DUNFREEZE;
186- Tile = pTiles[ClampedIndex (mx - 0 , my - 1 , w, h)].m_Index ;
187- Neighbors[1 ] = Tile != TILE_UNFREEZE && Tile != TILE_DUNFREEZE;
188- Tile = pTiles[ClampedIndex (mx + 1 , my - 1 , w, h)].m_Index ;
189- Neighbors[2 ] = Tile != TILE_UNFREEZE && Tile != TILE_DUNFREEZE;
190- Tile = pTiles[ClampedIndex (mx - 1 , my + 0 , w, h)].m_Index ;
191- Neighbors[3 ] = Tile != TILE_UNFREEZE && Tile != TILE_DUNFREEZE;
192- Tile = pTiles[ClampedIndex (mx + 1 , my + 0 , w, h)].m_Index ;
193- Neighbors[4 ] = Tile != TILE_UNFREEZE && Tile != TILE_DUNFREEZE;
194- Tile = pTiles[ClampedIndex (mx - 1 , my + 1 , w, h)].m_Index ;
195- Neighbors[5 ] = Tile != TILE_UNFREEZE && Tile != TILE_DUNFREEZE;
196- Tile = pTiles[ClampedIndex (mx + 0 , my + 1 , w, h)].m_Index ;
197- Neighbors[6 ] = Tile != TILE_UNFREEZE && Tile != TILE_DUNFREEZE;
198- Tile = pTiles[ClampedIndex (mx + 1 , my + 1 , w, h)].m_Index ;
199- Neighbors[7 ] = Tile != TILE_UNFREEZE && Tile != TILE_DUNFREEZE;
200- }
201-
202- int NumQuads = 0 ;
203-
204- // Do lonely corners first
205- if (Neighbors[0 ] && !Neighbors[1 ] && !Neighbors[3 ])
206- {
207- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale, my * Scale, Width, Width);
208- NumQuads++;
209- }
210- if (Neighbors[2 ] && !Neighbors[1 ] && !Neighbors[4 ])
211- {
212- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale + Scale - Width, my * Scale, Width, Width);
213- NumQuads++;
214- }
215- if (Neighbors[5 ] && !Neighbors[3 ] && !Neighbors[6 ])
216- {
217- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale, my * Scale + Scale - Width, Width, Width);
218- NumQuads++;
219- }
220- if (Neighbors[7 ] && !Neighbors[6 ] && !Neighbors[4 ])
221- {
222- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale + Scale - Width, my * Scale + Scale - Width, Width, Width);
223- NumQuads++;
224- }
225- // Top
226- if (Neighbors[1 ])
227- {
228- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale, my * Scale, Scale, Width);
229- NumQuads++;
230- }
231- // Bottom
232- if (Neighbors[6 ])
233- {
234- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale, my * Scale + Scale - Width, Scale, Width);
235- NumQuads++;
236- }
237- // Left
238- if (Neighbors[3 ])
239- {
240- if (!Neighbors[1 ] && !Neighbors[6 ])
241- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale, my * Scale, Width, Scale);
242- else if (!Neighbors[6 ])
243- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale, my * Scale + Width, Width, Scale - Width);
244- else if (!Neighbors[1 ])
245- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale, my * Scale, Width, Scale - Width);
246- else
247- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale, my * Scale + Width, Width, Scale - Width * 2 .0f );
248- NumQuads++;
249- }
250- // Right
251- if (Neighbors[4 ])
252- {
253- if (!Neighbors[1 ] && !Neighbors[6 ])
254- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale + Scale - Width, my * Scale, Width, Scale);
255- else if (!Neighbors[6 ])
256- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale + Scale - Width, my * Scale + Width, Width, Scale - Width);
257- else if (!Neighbors[1 ])
258- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale + Scale - Width, my * Scale, Width, Scale - Width);
259- else
260- Array[NumQuads] = IGraphics::CQuadItem (mx * Scale + Scale - Width, my * Scale + Width, Width, Scale - Width * 2 .0f );
261- NumQuads++;
262- }
263-
264- Graphics ()->QuadsDrawTL (Array, NumQuads);
89+ const unsigned char Index = pTiles[ClampedIndex (x, y)].m_Index ;
90+ auto DoType = [&](bool (*IsMatchingType)(unsigned char ), const int &Width, const unsigned int &Color) {
91+ if (!IsMatchingType (Index))
92+ return ;
93+ // Find neighbours
94+ const bool aNeighbors[8 ] = {
95+ IsMatchingType (pTiles[ClampedIndex (x - 1 , y - 1 )].m_Index ),
96+ IsMatchingType (pTiles[ClampedIndex (x - 0 , y - 1 )].m_Index ),
97+ IsMatchingType (pTiles[ClampedIndex (x + 1 , y - 1 )].m_Index ),
98+ IsMatchingType (pTiles[ClampedIndex (x - 1 , y + 0 )].m_Index ),
99+ IsMatchingType (pTiles[ClampedIndex (x + 1 , y + 0 )].m_Index ),
100+ IsMatchingType (pTiles[ClampedIndex (x - 1 , y + 1 )].m_Index ),
101+ IsMatchingType (pTiles[ClampedIndex (x + 0 , y + 1 )].m_Index ),
102+ IsMatchingType (pTiles[ClampedIndex (x + 1 , y + 1 )].m_Index ),
103+ };
104+ // Figure out edges
105+ IGraphics::CQuadItem aQuads[8 ];
106+ int NumQuads = 0 ;
107+ // Lone corners first
108+ if (!aNeighbors[0 ] && aNeighbors[1 ] && aNeighbors[3 ])
109+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale, Width, Width);
110+ if (!aNeighbors[2 ] && aNeighbors[1 ] && aNeighbors[4 ])
111+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale, Width, Width);
112+ if (!aNeighbors[5 ] && aNeighbors[3 ] && aNeighbors[6 ])
113+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale + Scale - Width, Width, Width);
114+ if (!aNeighbors[7 ] && aNeighbors[6 ] && aNeighbors[4 ])
115+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale + Scale - Width, Width, Width);
116+ // Top
117+ if (!aNeighbors[1 ])
118+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale, Scale, Width);
119+ // Bottom
120+ if (!aNeighbors[6 ])
121+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale + Scale - Width, Scale, Width);
122+ // Left
123+ if (!aNeighbors[3 ])
124+ {
125+ if (aNeighbors[1 ] && aNeighbors[6 ])
126+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale, Width, Scale);
127+ else if (aNeighbors[6 ])
128+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale + Width, Width, Scale - Width);
129+ else if (aNeighbors[1 ])
130+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale, Width, Scale - Width);
131+ else
132+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale + Width, Width, Scale - Width * 2 .0f );
133+ }
134+ // Right
135+ if (!aNeighbors[4 ])
136+ {
137+ if (aNeighbors[1 ] && aNeighbors[6 ])
138+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale, Width, Scale);
139+ else if (aNeighbors[6 ])
140+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale + Width, Width, Scale - Width);
141+ else if (aNeighbors[1 ])
142+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale, Width, Scale - Width);
143+ else
144+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale + Width, Width, Scale - Width * 2 .0f );
145+ }
146+ if (NumQuads <= 0 )
147+ return ;
148+ Graphics ()->SetColor (color_cast<ColorRGBA>(ColorHSLA (Color)));
149+ Graphics ()->QuadsDrawTL (aQuads, NumQuads);
150+ };
151+ if (g_Config.m_TcOutlineSolid )
152+ DoType ([](unsigned char Tile){ return Tile == TILE_SOLID || Tile == TILE_NOHOOK; }, g_Config.m_TcOutlineWidthSolid , g_Config.m_TcOutlineColorSolid );
153+ if (g_Config.m_TcOutlineFreeze )
154+ DoType ([](unsigned char Tile){ return Tile == TILE_FREEZE || Tile == TILE_DFREEZE || Tile == TILE_LFREEZE; }, g_Config.m_TcOutlineWidthFreeze , g_Config.m_TcOutlineColorFreeze );
155+ if (g_Config.m_TcOutlineUnfreeze )
156+ DoType ([](unsigned char Tile){ return Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE || Tile == TILE_LUNFREEZE; }, g_Config.m_TcOutlineWidthUnfreeze , g_Config.m_TcOutlineColorUnfreeze );
157+ if (g_Config.m_TcOutlineKill )
158+ DoType ([](unsigned char Tile){ return Tile == TILE_DEATH; }, g_Config.m_TcOutlineWidthKill , g_Config.m_TcOutlineColorKill );
159+ if (g_Config.m_TcOutlineKill )
160+ DoType ([](unsigned char Tile){ return Tile == TILE_DEATH; }, g_Config.m_TcOutlineWidthKill , g_Config.m_TcOutlineColorKill );
161+ if (g_Config.m_TcOutlineTele )
162+ DoType ([](unsigned char Tile){ return Tile == TILE_TELEOUT || Tile == TILE_TELEIN || Tile == TILE_TELEINEVIL || Tile == TILE_TELECHECKIN || Tile == TILE_TELECHECKINEVIL || Tile == TILE_TELEINHOOK || Tile == TILE_TELEINWEAPON; }, g_Config.m_TcOutlineWidthTele , g_Config.m_TcOutlineColorTele );
265163 }
266164 }
267165 Graphics ()->QuadsEnd ();
268166 Graphics ()->MapScreen (ScreenX0, ScreenY0, ScreenX1, ScreenY1);
269167 };
270-
271- auto DoLayer = [&](CMapItemLayerTilemap *pTMap) {
272- if (!pTMap)
273- return ;
274- CTile *pTiles = (CTile *)GameClient ()->Layers ()->Map ()->GetData (pTMap->m_Data );
275- if (!pTiles)
276- return ;
277- const unsigned Size = GameClient ()->Layers ()->Map ()->GetDataSize (pTMap->m_Data );
278- if (Size < (size_t )pTMap->m_Width * pTMap->m_Height * sizeof (CTile))
279- return ;
280- RenderGameTileOutlines (pTiles, pTMap->m_Width , pTMap->m_Height , 32 .0f , TILE_SOLID);
281- };
282168 if (g_Config.m_TcOutlineSolid || g_Config.m_TcOutlineFreeze || g_Config.m_TcOutlineUnfreeze || g_Config.m_TcOutlineKill )
169+ {
283170 DoLayer (GameClient ()->Layers ()->GameLayer ());
171+ DoLayer (GameClient ()->Layers ()->FrontLayer ());
172+ }
284173 if (g_Config.m_TcOutlineTele )
285174 DoLayer (GameClient ()->Layers ()->TeleLayer ());
286175}
0 commit comments