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,37 +41,31 @@ 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+ float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
45+ Graphics ()->GetScreen (&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
46+ const float Scale = 32 .0f ;
47+
48+ Graphics ()->TextureClear ();
49+ Graphics ()->QuadsBegin ();
50+
51+ auto DoLayer = [&](CMapItemLayerTilemap *pTMap, int CMapItemLayerTilemap::* pTMapData) {
52+ if (!pTMap)
53+ return ;
54+ CTile *pTiles = (CTile *)GameClient ()->Layers ()->Map ()->GetData (pTMap->*pTMapData);
55+ if (!pTiles)
56+ return ;
57+ const unsigned Size = GameClient ()->Layers ()->Map ()->GetDataSize (pTMap->*pTMapData);
58+ if (Size < (size_t )pTMap->m_Width * pTMap->m_Height * sizeof (CTile))
59+ return ;
7960
80- float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
81- Graphics ()->GetScreen (&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
61+ const int w = pTMap->m_Width ;
62+ const int h = pTMap->m_Height ;
63+ auto ClampedIndex = [&](int x, int y)
64+ {
65+ x = std::clamp (x, 0 , w - 1 );
66+ y = std::clamp (y, 0 , h - 1 );
67+ return x + y * w;
68+ };
8269
8370 int StartY = (int )(ScreenY0 / Scale) - 1 ;
8471 int StartX = (int )(ScreenX0 / Scale) - 1 ;
@@ -94,193 +81,94 @@ void COutlines::OnRender()
9481 StartY += EdgeY / 2 ;
9582 EndY -= EdgeY / 2 ;
9683 }
97- Graphics ()->TextureClear ();
98- Graphics ()->QuadsBegin ();
99- Graphics ()->SetColor (Color);
10084
10185 for (int y = StartY; y < EndY; y++)
10286 {
10387 for (int x = StartX; x < EndX; x++)
10488 {
105- int mx = x;
106- int my = y;
107-
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 = [&](const bool &Enable, bool (*IsMatchingType)(unsigned char ), const int &Width, const unsigned int &Color) {
91+ if (!Enable)
92+ return ;
93+ if (!IsMatchingType (Index))
94+ return ;
95+ // Find neighbours
96+ const bool aNeighbors[8 ] = {
97+ IsMatchingType (pTiles[ClampedIndex (x - 1 , y - 1 )].m_Index ),
98+ IsMatchingType (pTiles[ClampedIndex (x - 0 , y - 1 )].m_Index ),
99+ IsMatchingType (pTiles[ClampedIndex (x + 1 , y - 1 )].m_Index ),
100+ IsMatchingType (pTiles[ClampedIndex (x - 1 , y + 0 )].m_Index ),
101+ IsMatchingType (pTiles[ClampedIndex (x + 1 , y + 0 )].m_Index ),
102+ IsMatchingType (pTiles[ClampedIndex (x - 1 , y + 1 )].m_Index ),
103+ IsMatchingType (pTiles[ClampedIndex (x + 0 , y + 1 )].m_Index ),
104+ IsMatchingType (pTiles[ClampedIndex (x + 1 , y + 1 )].m_Index ),
105+ };
106+ // Figure out edges
107+ IGraphics::CQuadItem aQuads[8 ];
108+ int NumQuads = 0 ;
109+ // Lone corners first
110+ if (!aNeighbors[0 ] && aNeighbors[1 ] && aNeighbors[3 ])
111+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale, Width, Width);
112+ if (!aNeighbors[2 ] && aNeighbors[1 ] && aNeighbors[4 ])
113+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale, Width, Width);
114+ if (!aNeighbors[5 ] && aNeighbors[3 ] && aNeighbors[6 ])
115+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale + Scale - Width, Width, Width);
116+ if (!aNeighbors[7 ] && aNeighbors[6 ] && aNeighbors[4 ])
117+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale + Scale - Width, Width, Width);
118+ // Top
119+ if (!aNeighbors[1 ])
120+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale, Scale, Width);
121+ // Bottom
122+ if (!aNeighbors[6 ])
123+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale + Scale - Width, Scale, Width);
124+ // Left
125+ if (!aNeighbors[3 ])
126+ {
127+ if (aNeighbors[1 ] && aNeighbors[6 ])
128+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale, Width, Scale);
129+ else if (aNeighbors[6 ])
130+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale + Width, Width, Scale - Width);
131+ else if (aNeighbors[1 ])
132+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale, Width, Scale - Width);
133+ else
134+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale, y * Scale + Width, Width, Scale - Width * 2 .0f );
135+ }
136+ // Right
137+ if (!aNeighbors[4 ])
138+ {
139+ if (aNeighbors[1 ] && aNeighbors[6 ])
140+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale, Width, Scale);
141+ else if (aNeighbors[6 ])
142+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale + Width, Width, Scale - Width);
143+ else if (aNeighbors[1 ])
144+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale, Width, Scale - Width);
145+ else
146+ aQuads[NumQuads++] = IGraphics::CQuadItem (x * Scale + Scale - Width, y * Scale + Width, Width, Scale - Width * 2 .0f );
147+ }
148+ if (NumQuads <= 0 )
149+ return ;
150+ Graphics ()->SetColor (color_cast<ColorRGBA>(ColorHSLA (Color)));
151+ Graphics ()->QuadsDrawTL (aQuads, NumQuads);
152+ };
153+ DoType (g_Config.m_TcOutlineSolid , [](unsigned char Tile){ return Tile == TILE_SOLID || Tile == TILE_NOHOOK; }, g_Config.m_TcOutlineWidthSolid , g_Config.m_TcOutlineColorSolid );
154+ DoType (g_Config.m_TcOutlineFreeze , [](unsigned char Tile){ return Tile == TILE_FREEZE || Tile == TILE_DFREEZE || Tile == TILE_LFREEZE; }, g_Config.m_TcOutlineWidthFreeze , g_Config.m_TcOutlineColorFreeze );
155+ DoType (g_Config.m_TcOutlineUnfreeze , [](unsigned char Tile){ return Tile == TILE_UNFREEZE || Tile == TILE_DUNFREEZE || Tile == TILE_LUNFREEZE; }, g_Config.m_TcOutlineWidthUnfreeze , g_Config.m_TcOutlineColorUnfreeze );
156+ DoType (g_Config.m_TcOutlineKill , [](unsigned char Tile){ return Tile == TILE_DEATH; }, g_Config.m_TcOutlineWidthKill , g_Config.m_TcOutlineColorKill );
157+ DoType (g_Config.m_TcOutlineKill , [](unsigned char Tile){ return Tile == TILE_DEATH; }, g_Config.m_TcOutlineWidthKill , g_Config.m_TcOutlineColorKill );
158+ DoType (g_Config.m_TcOutlineTele , [](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 );
265159 }
266160 }
267- Graphics ()->QuadsEnd ();
268- Graphics ()->MapScreen (ScreenX0, ScreenY0, ScreenX1, ScreenY1);
269161 };
270162
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- };
282163 if (g_Config.m_TcOutlineSolid || g_Config.m_TcOutlineFreeze || g_Config.m_TcOutlineUnfreeze || g_Config.m_TcOutlineKill )
283- DoLayer (GameClient ()->Layers ()->GameLayer ());
164+ {
165+ DoLayer (GameClient ()->Layers ()->GameLayer (), &CMapItemLayerTilemap::m_Data);
166+ DoLayer (GameClient ()->Layers ()->FrontLayer (), &CMapItemLayerTilemap::m_Front);
167+ }
284168 if (g_Config.m_TcOutlineTele )
285- DoLayer (GameClient ()->Layers ()->TeleLayer ());
169+ {
170+ DoLayer (GameClient ()->Layers ()->TeleLayer (), &CMapItemLayerTilemap::m_Tele);
171+ }
172+
173+ Graphics ()->QuadsEnd ();
286174}
0 commit comments