diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index aa1a0a4e9..cdc427c56 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -276,7 +276,6 @@ - diff --git a/ClassicalSharp/Selections/SelectionBox.cs b/ClassicalSharp/Selections/SelectionBox.cs index a614f547a..fa0a54cd6 100644 --- a/ClassicalSharp/Selections/SelectionBox.cs +++ b/ClassicalSharp/Selections/SelectionBox.cs @@ -1,11 +1,12 @@ // Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 using System; +using System.Collections.Generic; using ClassicalSharp.GraphicsAPI; using OpenTK; namespace ClassicalSharp.Selections { - public class SelectionBox { + internal class SelectionBox { public byte ID; public Vector3I Min, Max; @@ -75,4 +76,40 @@ namespace ClassicalSharp.Selections { v.X = x2; v.Y = y2; v.Z = z2; vertices[index++] = v; } } + + internal class SelectionBoxComparer : IComparer { + + public int Compare(SelectionBox a, SelectionBox b) { + // Reversed comparison order because we need to render back to front for alpha blending. + return a.MinDist == b.MinDist + ? b.MaxDist.CompareTo(a.MaxDist) + : b.MinDist.CompareTo(a.MinDist); + } + + internal void Intersect(SelectionBox box, Vector3 origin) { + Vector3I min = box.Min, max = box.Max; + float closest = float.PositiveInfinity, furthest = float.NegativeInfinity; + // Bottom corners + UpdateDist(origin, min.X, min.Y, min.Z, ref closest, ref furthest); + UpdateDist(origin, max.X, min.Y, min.Z, ref closest, ref furthest); + UpdateDist(origin, max.X, min.Y, max.Z, ref closest, ref furthest); + UpdateDist(origin, min.X, min.Y, max.Z, ref closest, ref furthest); + // Top corners + UpdateDist(origin, min.X, max.Y, min.Z, ref closest, ref furthest); + UpdateDist(origin, max.X, max.Y, min.Z, ref closest, ref furthest); + UpdateDist(origin, max.X, max.Y, max.Z, ref closest, ref furthest); + UpdateDist(origin, min.X, max.Y, max.Z, ref closest, ref furthest); + box.MinDist = closest; box.MaxDist = furthest; + } + + + static void UpdateDist(Vector3 p, float x2, float y2, float z2, + ref float closest, ref float furthest) { + float dx = x2 - p.X, dy = y2 - p.Y, dz = z2 - p.Z; + float dist = dx * dx + dy * dy + dz * dz; + + if (dist < closest) closest = dist; + if (dist > furthest) furthest = dist; + } + } } diff --git a/ClassicalSharp/Selections/SelectionBoxComparer.cs b/ClassicalSharp/Selections/SelectionBoxComparer.cs deleted file mode 100644 index cb0a4679e..000000000 --- a/ClassicalSharp/Selections/SelectionBoxComparer.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 -using System; -using System.Collections.Generic; -using OpenTK; - -namespace ClassicalSharp.Selections { - - internal class SelectionBoxComparer : IComparer { - - public int Compare(SelectionBox a, SelectionBox b) { - // Reversed comparison order because we need to render back to front for alpha blending. - return a.MinDist == b.MinDist ? b.MaxDist.CompareTo(a.MaxDist) - : b.MinDist.CompareTo(a.MinDist); - } - - internal void Intersect(SelectionBox box, Vector3 origin) { - Vector3I min = box.Min, max = box.Max; - float closest = float.PositiveInfinity, furthest = float.NegativeInfinity; - // Bottom corners - UpdateDist(origin, min.X, min.Y, min.Z, ref closest, ref furthest); - UpdateDist(origin, max.X, min.Y, min.Z, ref closest, ref furthest); - UpdateDist(origin, max.X, min.Y, max.Z, ref closest, ref furthest); - UpdateDist(origin, min.X, min.Y, max.Z, ref closest, ref furthest); - // Top corners - UpdateDist(origin, min.X, max.Y, min.Z, ref closest, ref furthest); - UpdateDist(origin, max.X, max.Y, min.Z, ref closest, ref furthest); - UpdateDist(origin, max.X, max.Y, max.Z, ref closest, ref furthest); - UpdateDist(origin, min.X, max.Y, max.Z, ref closest, ref furthest); - box.MinDist = closest; box.MaxDist = furthest; - } - - static void UpdateDist(Vector3 p, float x2, float y2, float z2, - ref float closest, ref float furthest) { - float dist = Utils.DistanceSquared(p.X, p.Y, p.Z, x2, y2, z2); - if (dist < closest) closest = dist; - if (dist > furthest) furthest = dist; - } - } -} \ No newline at end of file diff --git a/ClassicalSharp/Utils/Utils.Math.cs b/ClassicalSharp/Utils/Utils.Math.cs index ddc06e9d2..921334f23 100644 --- a/ClassicalSharp/Utils/Utils.Math.cs +++ b/ClassicalSharp/Utils/Utils.Math.cs @@ -81,14 +81,7 @@ namespace ClassicalSharp { float cosA = (float)Math.Cos(angle), sinA = (float)Math.Sin(angle); return new Vector3(cosA * v.X + sinA * v.Y, -sinA * v.X + cosA * v.Y, v.Z); } - - /// Returns the square of the euclidean distance between two points. - public static float DistanceSquared(float x1, float y1, float z1, float x2, float y2, float z2) { - float dx = x2 - x1, dy = y2 - y1, dz = z2 - z1; - return dx * dx + dy * dy + dz * dz; - } - /// Returns a normalised vector that faces in the direction /// described by the given yaw and pitch. public static Vector3 GetDirVector(double yawRad, double pitchRad) { diff --git a/src/Client/BordersRenderer.c b/src/Client/BordersRenderer.c index 17ae30632..8c6b4d947 100644 --- a/src/Client/BordersRenderer.c +++ b/src/Client/BordersRenderer.c @@ -106,10 +106,10 @@ void BordersRenderer_DrawX(Int32 x, Int32 z1, Int32 z2, Int32 y1, Int32 y2, Int3 if (y2 > endY) y2 = endY; Real32 u2 = (Real32)z2 - (Real32)z1, v2 = (Real32)y2 - (Real32)y1; - v.Y = (Real32)y1; v.Z = (Real32)z1; v.U = 0.0f; v.V = v2; *ptr = v; ptr++; - v.Y = (Real32)y2; v.V = 0.0f; *ptr = v; ptr++; - v.Z = (Real32)z2; v.U = u2; *ptr = v; ptr++; - v.Y = (Real32)y1; v.V = v2; *ptr = v; ptr++; + v.Y = (Real32)y1; v.Z = (Real32)z1; v.U = 0.0f; v.V = v2; *ptr++ = v; + v.Y = (Real32)y2; v.V = 0.0f; *ptr++ = v; + v.Z = (Real32)z2; v.U = u2; *ptr++ = v; + v.Y = (Real32)y1; v.V = v2; *ptr++ = v; } } *vertices = ptr; @@ -130,10 +130,10 @@ void BordersRenderer_DrawZ(Int32 z, Int32 x1, Int32 x2, Int32 y1, Int32 y2, Int3 if (y2 > endY) y2 = endY; Real32 u2 = (Real32)x2 - (Real32)x1, v2 = (Real32)y2 - (Real32)y1; - v.X = (Real32)x1; v.Y = (Real32)y1; v.U = 0.0f; v.V = v2; *ptr = v; ptr++; - v.Y = (Real32)y2; v.V = 0.0f; *ptr = v; ptr++; - v.X = (Real32)x2; v.U = u2; *ptr = v; ptr++; - v.Y = (Real32)y1; v.V = v2; *ptr = v; ptr++; + v.X = (Real32)x1; v.Y = (Real32)y1; v.U = 0.0f; v.V = v2; *ptr++ = v; + v.Y = (Real32)y2; v.V = 0.0f; *ptr++ = v; + v.X = (Real32)x2; v.U = u2; *ptr++ = v; + v.Y = (Real32)y1; v.V = v2; *ptr++ = v; } } *vertices = ptr; @@ -154,10 +154,10 @@ void BordersRenderer_DrawY(Int32 x1, Int32 z1, Int32 x2, Int32 z2, Real32 y, Int if (z2 > endZ) z2 = endZ; Real32 u2 = (Real32)x2 - (Real32)x1, v2 = (Real32)z2 - (Real32)z1; - v.X = (Real32)x1 + offset; v.Z = (Real32)z1 + offset; v.U = 0.0f; v.V = 0.0f; *ptr = v; ptr++; - v.Z = (Real32)z2 + offset; v.V = v2; *ptr = v; ptr++; - v.X = (Real32)x2 + offset; v.U = u2; *ptr = v; ptr++; - v.Z = (Real32)z1 + offset; v.V = 0.0f; *ptr = v; ptr++; + v.X = (Real32)x1 + offset; v.Z = (Real32)z1 + offset; v.U = 0.0f; v.V = 0.0f; *ptr++ = v; + v.Z = (Real32)z2 + offset; v.V = v2; *ptr++ = v; + v.X = (Real32)x2 + offset; v.U = u2; *ptr++ = v; + v.Z = (Real32)z1 + offset; v.V = 0.0f; *ptr++ = v; } } *vertices = ptr; diff --git a/src/Client/Drawer.c b/src/Client/Drawer.c index 3ef35dfd0..8794bfb72 100644 --- a/src/Client/Drawer.c +++ b/src/Client/Drawer.c @@ -2,8 +2,6 @@ #include "TerrainAtlas.h" #include "Constants.h" -#define AddVertex *ptr = v; ptr++ - /* Performance critical, use macro to ensure always inlined. */ #define ApplyTint \ if (Drawer_Tinted) {\ @@ -23,10 +21,10 @@ void Drawer_XMin(Int32 count, PackedCol col, TextureLoc texLoc, VertexP3fT2fC4b* VertexP3fT2fC4b* ptr = *vertices; VertexP3fT2fC4b v; v.X = Drawer_X1; v.Col = col; - v.Y = Drawer_Y2; v.Z = Drawer_Z2 + (count - 1); v.U = u2; v.V = v1; AddVertex; - v.Z = Drawer_Z1; v.U = u1; AddVertex; - v.Y = Drawer_Y1; v.V = v2; AddVertex; - v.Z = Drawer_Z2 + (count - 1); v.U = u2; AddVertex; + v.Y = Drawer_Y2; v.Z = Drawer_Z2 + (count - 1); v.U = u2; v.V = v1; *ptr++ = v; + v.Z = Drawer_Z1; v.U = u1; *ptr++ = v; + v.Y = Drawer_Y1; v.V = v2; *ptr++ = v; + v.Z = Drawer_Z2 + (count - 1); v.U = u2; *ptr++ = v; *vertices = ptr; } @@ -40,10 +38,10 @@ void Drawer_XMax(Int32 count, PackedCol col, TextureLoc texLoc, VertexP3fT2fC4b* VertexP3fT2fC4b* ptr = *vertices; VertexP3fT2fC4b v; v.X = Drawer_X2; v.Col = col; - v.Y = Drawer_Y2; v.Z = Drawer_Z1; v.U = u1; v.V = v1; AddVertex; - v.Z = Drawer_Z2 + (count - 1); v.U = u2; AddVertex; - v.Y = Drawer_Y1; v.V = v2; AddVertex; - v.Z = Drawer_Z1; v.U = u1; AddVertex; + v.Y = Drawer_Y2; v.Z = Drawer_Z1; v.U = u1; v.V = v1; *ptr++ = v; + v.Z = Drawer_Z2 + (count - 1); v.U = u2; *ptr++ = v; + v.Y = Drawer_Y1; v.V = v2; *ptr++ = v; + v.Z = Drawer_Z1; v.U = u1; *ptr++ = v; *vertices = ptr; } @@ -57,10 +55,10 @@ void Drawer_ZMin(Int32 count, PackedCol col, TextureLoc texLoc, VertexP3fT2fC4b* VertexP3fT2fC4b* ptr = *vertices; VertexP3fT2fC4b v; v.Z = Drawer_Z1; v.Col = col; - v.X = Drawer_X2 + (count - 1); v.Y = Drawer_Y1; v.U = u2; v.V = v2; AddVertex; - v.X = Drawer_X1; v.U = u1; AddVertex; - v.Y = Drawer_Y2; v.V = v1; AddVertex; - v.X = Drawer_X2 + (count - 1); v.U = u2; AddVertex; + v.X = Drawer_X2 + (count - 1); v.Y = Drawer_Y1; v.U = u2; v.V = v2; *ptr++ = v; + v.X = Drawer_X1; v.U = u1; *ptr++ = v; + v.Y = Drawer_Y2; v.V = v1; *ptr++ = v; + v.X = Drawer_X2 + (count - 1); v.U = u2; *ptr++ = v; *vertices = ptr; } @@ -74,10 +72,10 @@ void Drawer_ZMax(Int32 count, PackedCol col, TextureLoc texLoc, VertexP3fT2fC4b* VertexP3fT2fC4b* ptr = *vertices; VertexP3fT2fC4b v; v.Z = Drawer_Z2; v.Col = col; - v.X = Drawer_X2 + (count - 1); v.Y = Drawer_Y2; v.U = u2; v.V = v1; AddVertex; - v.X = Drawer_X1; v.U = u1; AddVertex; - v.Y = Drawer_Y1; v.V = v2; AddVertex; - v.X = Drawer_X2 + (count - 1); v.U = u2; AddVertex; + v.X = Drawer_X2 + (count - 1); v.Y = Drawer_Y2; v.U = u2; v.V = v1; *ptr++ = v; + v.X = Drawer_X1; v.U = u1; *ptr++ = v; + v.Y = Drawer_Y1; v.V = v2; *ptr++ = v; + v.X = Drawer_X2 + (count - 1); v.U = u2; *ptr++ = v; *vertices = ptr; } @@ -91,10 +89,10 @@ void Drawer_YMin(Int32 count, PackedCol col, TextureLoc texLoc, VertexP3fT2fC4b* VertexP3fT2fC4b* ptr = *vertices; VertexP3fT2fC4b v; v.Y = Drawer_Y1; v.Col = col; - v.X = Drawer_X2 + (count - 1); v.Z = Drawer_Z2; v.U = u2; v.V = v2; AddVertex; - v.X = Drawer_X1; v.U = u1; AddVertex; - v.Z = Drawer_Z1; v.V = v1; AddVertex; - v.X = Drawer_X2 + (count - 1); v.U = u2; AddVertex; + v.X = Drawer_X2 + (count - 1); v.Z = Drawer_Z2; v.U = u2; v.V = v2; *ptr++ = v; + v.X = Drawer_X1; v.U = u1; *ptr++ = v; + v.Z = Drawer_Z1; v.V = v1; *ptr++ = v; + v.X = Drawer_X2 + (count - 1); v.U = u2; *ptr++ = v; *vertices = ptr; } @@ -108,9 +106,9 @@ void Drawer_YMax(Int32 count, PackedCol col, TextureLoc texLoc, VertexP3fT2fC4b* VertexP3fT2fC4b* ptr = *vertices; VertexP3fT2fC4b v; v.Y = Drawer_Y2; v.Col = col; - v.X = Drawer_X2 + (count - 1); v.Z = Drawer_Z1; v.U = u2; v.V = v1; AddVertex; - v.X = Drawer_X1; v.U = u1; AddVertex; - v.Z = Drawer_Z2; v.V = v2; AddVertex; - v.X = Drawer_X2 + (count - 1); v.U = u2; AddVertex; + v.X = Drawer_X2 + (count - 1); v.Z = Drawer_Z1; v.U = u2; v.V = v1; *ptr++ = v; + v.X = Drawer_X1; v.U = u1; *ptr++ = v; + v.Z = Drawer_Z2; v.V = v2; *ptr++ = v; + v.X = Drawer_X2 + (count - 1); v.U = u2; *ptr++ = v; *vertices = ptr; } \ No newline at end of file diff --git a/src/Client/EnvRenderer.c b/src/Client/EnvRenderer.c index 277f0a9b3..15b54a5db 100644 --- a/src/Client/EnvRenderer.c +++ b/src/Client/EnvRenderer.c @@ -165,10 +165,10 @@ void EnvRenderer_DrawSkyY(Int32 x1, Int32 z1, Int32 x2, Int32 z2, Int32 y, Int32 z2 = z1 + axisSize; if (z2 > endZ) z2 = endZ; - v.X = (Real32)x1; v.Z = (Real32)z1; *vertices = v; vertices++; - v.Z = (Real32)z2; *vertices = v; vertices++; - v.X = (Real32)x2; *vertices = v; vertices++; - v.Z = (Real32)z1; *vertices = v; vertices++; + v.X = (Real32)x1; v.Z = (Real32)z1; *vertices++ = v; + v.Z = (Real32)z2; *vertices++ = v; + v.X = (Real32)x2; *vertices++ = v; + v.Z = (Real32)z1; *vertices++ = v; } } } @@ -190,10 +190,10 @@ void EnvRenderer_DrawCloudsY(Int32 x1, Int32 z1, Int32 x2, Int32 z2, Int32 y, In Real32 u1 = (Real32)x1 / 2048.0f + offset, u2 = (Real32)x2 / 2048.0f + offset; Real32 v1 = (Real32)z1 / 2048.0f + offset, v2 = (Real32)z2 / 2048.0f + offset; - v.X = (Real32)x1; v.Z = (Real32)z1; v.U = u1; v.V = v1; *vertices = v; vertices++; - v.Z = (Real32)z2; v.V = v2; *vertices = v; vertices++; - v.X = (Real32)x2; v.U = u2; *vertices = v; vertices++; - v.Z = (Real32)z1; v.V = v1; *vertices = v; vertices++; + v.X = (Real32)x1; v.Z = (Real32)z1; v.U = u1; v.V = v1; *vertices++ = v; + v.Z = (Real32)z2; v.V = v2; *vertices++ = v; + v.X = (Real32)x2; v.U = u2; *vertices++ = v; + v.Z = (Real32)z1; v.V = v1; *vertices++ = v; } } } diff --git a/src/Client/GraphicsAPI.h b/src/Client/GraphicsAPI.h index f17dbfa2e..f042331d6 100644 --- a/src/Client/GraphicsAPI.h +++ b/src/Client/GraphicsAPI.h @@ -62,7 +62,7 @@ void Gfx_Clear(void); void Gfx_ClearColour(PackedCol col); void Gfx_SetDepthTest(bool enabled); void Gfx_SetDepthTestFunc(Int32 compareFunc); -void Gfx_SetColourWrite(bool enabled); +void Gfx_SetColourWriteMask(bool r, bool g, bool b, bool a); void Gfx_SetDepthWrite(bool enabled); /* Creates a vertex buffer that can have its data dynamically updated. */ diff --git a/src/Client/PickedPosRenderer.c b/src/Client/PickedPosRenderer.c index 67ae9cd0e..28320b13c 100644 --- a/src/Client/PickedPosRenderer.c +++ b/src/Client/PickedPosRenderer.c @@ -47,24 +47,27 @@ void PickedPosRenderer_Render(Real64 delta) { } void PickedPosRenderer_XQuad(Real32 x, Real32 z1, Real32 y1, Real32 z2, Real32 y2) { - VertexP3fC4b_Set(pickedPos_ptr, x, y1, z1, pickedPos_col); pickedPos_ptr++; - VertexP3fC4b_Set(pickedPos_ptr, x, y2, z1, pickedPos_col); pickedPos_ptr++; - VertexP3fC4b_Set(pickedPos_ptr, x, y2, z2, pickedPos_col); pickedPos_ptr++; - VertexP3fC4b_Set(pickedPos_ptr, x, y1, z2, pickedPos_col); pickedPos_ptr++; -} - -void PickedPosRenderer_ZQuad(Real32 z, Real32 x1, Real32 y1, Real32 x2, Real32 y2) { - VertexP3fC4b_Set(pickedPos_ptr, x1, y1, z, pickedPos_col); pickedPos_ptr++; - VertexP3fC4b_Set(pickedPos_ptr, x1, y2, z, pickedPos_col); pickedPos_ptr++; - VertexP3fC4b_Set(pickedPos_ptr, x2, y2, z, pickedPos_col); pickedPos_ptr++; - VertexP3fC4b_Set(pickedPos_ptr, x2, y1, z, pickedPos_col); pickedPos_ptr++; + VertexP3fC4b v; v.X = x; v.Col = pickedPos_col; + v.Y = y1; v.Z = z1; *pickedPos_ptr++ = v; + v.Y = y2; *pickedPos_ptr++ = v; + v.Z = z2; *pickedPos_ptr++ = v; + v.Y = y1; *pickedPos_ptr++ = v; } void PickedPosRenderer_YQuad(Real32 y, Real32 x1, Real32 z1, Real32 x2, Real32 z2) { - VertexP3fC4b_Set(pickedPos_ptr, x1, y, z1, pickedPos_col); pickedPos_ptr++; - VertexP3fC4b_Set(pickedPos_ptr, x1, y, z2, pickedPos_col); pickedPos_ptr++; - VertexP3fC4b_Set(pickedPos_ptr, x2, y, z2, pickedPos_col); pickedPos_ptr++; - VertexP3fC4b_Set(pickedPos_ptr, x2, y, z1, pickedPos_col); pickedPos_ptr++; + VertexP3fC4b v; v.Y = y; v.Col = pickedPos_col; + v.X = x1; v.Z = z1; *pickedPos_ptr++ = v; + v.Z = z2; *pickedPos_ptr++ = v; + v.X = x2; *pickedPos_ptr++ = v; + v.Z = z1; *pickedPos_ptr++ = v; +} + +void PickedPosRenderer_ZQuad(Real32 z, Real32 x1, Real32 y1, Real32 x2, Real32 y2) { + VertexP3fC4b v; v.Z = z; v.Col = pickedPos_col; + v.X = x1; v.Y = y1; *pickedPos_ptr++ = v; + v.Y = y2; *pickedPos_ptr++ = v; + v.X = x2; *pickedPos_ptr++ = v; + v.Y = y1; *pickedPos_ptr++ = v; } void PickedPosRenderer_UpdateState(PickedPos* selected) { diff --git a/src/Client/Screens.c b/src/Client/Screens.c index 02df20c37..72ecbdc65 100644 --- a/src/Client/Screens.c +++ b/src/Client/Screens.c @@ -456,7 +456,7 @@ void StatusScreen_Render(GuiElement* elem, Real64 delta) { Widget_Render(&screen->Status, delta); if (!Game_ClassicMode && Gui_Active == NULL) { - if (StatusScreen_HacksChanged(screen)) { StatusScreen_UpdateHackState(screen, false); } + if (StatusScreen_HacksChanged(screen)) { StatusScreen_UpdateHackState(screen); } StatusScreen_DrawPosition(screen); Widget_Render(&screen->HackStates, delta); } @@ -974,7 +974,7 @@ bool HUDScreen_HandlesKeyDown(GuiElement* elem, Key key) { if (key == playerListKey && handles) { if (!screen->ShowingList && !ServerConnection_IsSinglePlayer) { screen->WasShowingList = true; - ContextRecreated(); + HUDScreen_ContextRecreated(screen); } return true; } diff --git a/src/Client/SelectionBox.c b/src/Client/SelectionBox.c index a63b85116..2077709fc 100644 --- a/src/Client/SelectionBox.c +++ b/src/Client/SelectionBox.c @@ -1,12 +1,16 @@ #include "SelectionBox.h" +#include "ExtMath.h" +#include "GraphicsAPI.h" +#include "GraphicsCommon.h" +#include "Event.h" +#include "Funcs.h" -void SelectionBox_Make(SelectionBox* box, Vector3I* p1, Vector3I* p2, PackedCol col) { - box->ID = 0; - box->MinDist = 0.0f; box->MaxDist = 0.0f; - Vector3I_Min(&box->Min, p1, p2); - Vector3I_Max(&box->Max, p1, p2); - box->Col = col; -} +/* Data for a selection box. */ +typedef struct SelectionBox_ { + Vector3I Min, Max; + PackedCol Col; + Real32 MinDist, MaxDist; +} SelectionBox; void SelectionBox_Render(SelectionBox* box, VertexP3fC4b** vertices, VertexP3fC4b** lineVertices) { Real32 offset = box->MinDist < 32.0f * 32.0f ? (1.0f / 32.0f) : (1.0f / 16.0f); @@ -46,27 +50,197 @@ void SelectionBox_Render(SelectionBox* box, VertexP3fC4b** vertices, VertexP3fC4 void SelectionBox_VerQuad(VertexP3fC4b** vertices, PackedCol col, Real32 x1, Real32 y1, Real32 z1, Real32 x2, Real32 y2, Real32 z2) { VertexP3fC4b* ptr = *vertices; - VertexP3fC4b_Set(ptr, x1, y1, z1, col); ptr++; - VertexP3fC4b_Set(ptr, x1, y2, z1, col); ptr++; - VertexP3fC4b_Set(ptr, x2, y2, z2, col); ptr++; - VertexP3fC4b_Set(ptr, x2, y1, z2, col); ptr++; + VertexP3fC4b v; v.Col = col; + + v.X = x1; v.Y = y1; v.Z = z1; *ptr++ = v; + v.Y = y2; *ptr++ = v; + v.X = x2; v.Z = z2; *ptr++ = v; + v.Y = y1; *ptr++ = v; *vertices = ptr; } void SelectionBox_HorQuad(VertexP3fC4b** vertices, PackedCol col, Real32 x1, Real32 z1, Real32 x2, Real32 z2, Real32 y) { VertexP3fC4b* ptr = *vertices; - VertexP3fC4b_Set(ptr, x1, y, z1, col); ptr++; - VertexP3fC4b_Set(ptr, x1, y, z2, col); ptr++; - VertexP3fC4b_Set(ptr, x2, y, z2, col); ptr++; - VertexP3fC4b_Set(ptr, x2, y, z1, col); ptr++; + VertexP3fC4b v; v.Y = y; v.Col = col; + + v.X = x1; v.Z = z1; *ptr++ = v; + v.Z = z2; *ptr++ = v; + v.X = x2; *ptr++ = v; + v.Z = z1; *ptr++ = v; *vertices = ptr; } void SelectionBox_Line(VertexP3fC4b** vertices, PackedCol col, Real32 x1, Real32 y1, Real32 z1, Real32 x2, Real32 y2, Real32 z2) { - VertexP3fC4b* ptr = *vertices; - VertexP3fC4b_Set(ptr, x1, y1, z1, col); ptr++; - VertexP3fC4b_Set(ptr, x2, y2, z2, col); ptr++; + VertexP3fC4b* ptr = *vertices; + VertexP3fC4b v; v.Col = col; + + v.X = x1; v.Y = y1; v.Z = z1; *ptr++ = v; + v.X = x2; v.Y = y2; v.Z = z2; *ptr++ = v; *vertices = ptr; +} + + +Int32 SelectionBox_Compare(SelectionBox* a, SelectionBox* b) { + Real32 aDist, bDist; + if (a->MinDist == b->MinDist) { + aDist = a->MaxDist; bDist = b->MaxDist; + } else { + aDist = a->MinDist; bDist = b->MinDist; + } + + /* Reversed comparison order result, because we need to render back to front for alpha blending */ + if (aDist < bDist) return 1; + if (aDist > bDist) return -1; + return 0; +} + +void SelectionBox_UpdateDist(Vector3 p, Real32 x2, Real32 y2, Real32 z2, Real32* closest, Real32* furthest) { + Real32 dx = x2 - p.X, dy = y2 - p.Y, dz = z2 - p.Z; + Real32 dist = dx * dx + dy * dy + dz * dz; + + if (dist < *closest) *closest = dist; + if (dist > *furthest) *furthest = dist; +} + +void SelectionBox_Intersect(SelectionBox* box, Vector3 origin) { + Vector3I min = box->Min, max = box->Max; + Real32 closest = MATH_POS_INF, furthest = -MATH_POS_INF; + /* Bottom corners */ + SelectionBox_UpdateDist(origin, min.X, min.Y, min.Z, &closest, &furthest); + SelectionBox_UpdateDist(origin, max.X, min.Y, min.Z, &closest, &furthest); + SelectionBox_UpdateDist(origin, max.X, min.Y, max.Z, &closest, &furthest); + SelectionBox_UpdateDist(origin, min.X, min.Y, max.Z, &closest, &furthest); + /* Top corners */ + SelectionBox_UpdateDist(origin, min.X, max.Y, min.Z, &closest, &furthest); + SelectionBox_UpdateDist(origin, max.X, max.Y, min.Z, &closest, &furthest); + SelectionBox_UpdateDist(origin, max.X, max.Y, max.Z, &closest, &furthest); + SelectionBox_UpdateDist(origin, min.X, max.Y, max.Z, &closest, &furthest); + box->MinDist = closest; box->MaxDist = furthest; +} + + +#define SELECTIONS_MAX 256 +#define SELECTIONS_VERTICES 24 +#define SELECTIONS_MAX_VERTICES SELECTIONS_MAX * SELECTIONS_VERTICES + +UInt32 selections_count; +SelectionBox selections_list[SELECTIONS_MAX]; +UInt8 selections_ids[SELECTIONS_MAX]; +GfxResourceID selections_VB, selections_LineVB; +bool selections_allocated; + +void Selections_Add(UInt8 id, Vector3I p1, Vector3I p2, PackedCol col) { + SelectionBox sel; + Vector3I_Min(&sel.Min, &p1, &p2); + Vector3I_Max(&sel.Max, &p1, &p2); + sel.Col = col; + + Selections_Remove(id); + selections_list[selections_count] = sel; + selections_ids[selections_count] = id; + selections_count++; +} + +void Selections_Remove(UInt8 id) { + UInt32 i; + for (i = 0; i < selections_count; i++) { + if (selections_ids[i] != id) continue; + + for (; i < selections_count - 1; i++) { + selections_list[i] = selections_list[i + 1]; + selections_ids[i] = selections_ids[i + 1]; + } + + selections_count--; + return; + } +} + +void Selections_ContextLost(void) { + Gfx_DeleteVb(&selections_VB); + Gfx_DeleteVb(&selections_LineVB); +} + +void Selections_ContextRecreated(void) { + if (!selections_allocated) return; + selections_VB = Gfx_CreateDynamicVb(VERTEX_FORMAT_P3FC4B, SELECTIONS_MAX_VERTICES); + selections_LineVB = Gfx_CreateDynamicVb(VERTEX_FORMAT_P3FC4B, SELECTIONS_MAX_VERTICES); +} + +void Selections_QuickSort(Int32 left, Int32 right) { + UInt8* values = selections_ids; UInt8 value; + SelectionBox* keys = selections_list; SelectionBox key; + while (left < right) { + Int32 i = left, j = right; + SelectionBox* pivot = &keys[(i + j) / 2]; + + /* partition the list */ + while (i <= j) { + while (SelectionBox_Compare(pivot, &keys[i]) > 0) i++; + while (SelectionBox_Compare(pivot, &keys[j]) < 0) j--; + QuickSort_Swap_KV_Maybe(); + } + /* recurse into the smaller subset */ + QuickSort_Recurse(Selections_QuickSort) + } +} + +void Selections_Render(Real64 delta) { + if (selections_count == 0 || Gfx_LostContext) return; + /* TODO: Proper selection box sorting. But this is very difficult because + we can have boxes within boxes, intersecting boxes, etc. Probably not worth it. */ + Vector3 camPos = Game_CurrentCameraPos; + UInt32 i; + for (i = 0; i < selections_count; i++) { + SelectionBox_Intersect(&selections_list[i], camPos); + } + Selections_QuickSort(0, selections_count - 1); + + if (!selections_allocated) { /* lazy init as most servers don't use this */ + Selections_ContextRecreated(); + selections_allocated = true; + } + + VertexP3fC4b vertices[SELECTIONS_MAX_VERTICES]; VertexP3fC4b* ptr = vertices; + VertexP3fC4b lineVertices[SELECTIONS_MAX_VERTICES]; VertexP3fC4b* linePtr = lineVertices; + for (i = 0; i < selections_count; i++) { + SelectionBox_Render(&selections_list[i], &ptr, &linePtr); + } + + Gfx_SetBatchFormat(VERTEX_FORMAT_P3FC4B); + GfxCommon_UpdateDynamicVb_Lines(selections_LineVB, lineVertices, + selections_count * SELECTIONS_VERTICES); + + Gfx_SetDepthWrite(false); + Gfx_SetAlphaBlending(true); + GfxCommon_UpdateDynamicVb_IndexedTris(selections_VB, vertices, + selections_count * SELECTIONS_VERTICES); + Gfx_SetDepthWrite(true); + Gfx_SetAlphaBlending(false); +} + +void Selections_Init(void) { + Event_RegisterVoid(&GfxEvents_ContextLost, NULL, Selections_ContextLost); + Event_RegisterVoid(&GfxEvents_ContextRecreated, NULL, Selections_ContextRecreated); +} + +void Selections_Reset(void) { + selections_count = 0; +} + +void Selections_Free(void) { + Selections_ContextLost(); + Event_UnregisterVoid(&GfxEvents_ContextLost, NULL, Selections_ContextLost); + Event_UnregisterVoid(&GfxEvents_ContextRecreated, NULL, Selections_ContextRecreated); +} + +IGameComponent Selections_MakeComponent(void) { + IGameComponent comp = IGameComponent_MakeEmpty(); + comp.Init = Selections_Init; + comp.Free = Selections_Free; + comp.Reset = Selections_Reset; + comp.OnNewMap = Selections_Reset; + return comp; } \ No newline at end of file diff --git a/src/Client/SelectionBox.h b/src/Client/SelectionBox.h index 58c59c93c..40f06a46a 100644 --- a/src/Client/SelectionBox.h +++ b/src/Client/SelectionBox.h @@ -1,35 +1,13 @@ #ifndef CC_SELECTIONBOX_H #define CC_SELECTIONBOX_H #include "Typedefs.h" -#include "PackedCol.h" -#include "Vectors.h" #include "VertexStructs.h" +#include "GameStructs.h" +#include "Vectors.h" /* Describes a selection box, and contains methods related to the selection box. Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 */ -/* Data for a selection box. */ -typedef struct SelectionBox_ { - /* ID of this selection box.*/ - UInt8 ID; - /* Minimum corner of the box. */ - Vector3I Min; - /* Maximum corner of the box. */ - Vector3I Max; - /* Colour of this box. */ - PackedCol Col; - /* Closest distance to player of any of the eight corners of the box. */ - Real32 MinDist; - /* Furthest distance to player of any of the eight corners of the box. */ - Real32 MaxDist; -} SelectionBox; - - -/* Constructs a selection box. */ -void SelectionBox_Make(SelectionBox* box, Vector3I* p1, Vector3I* p2, PackedCol col); -/* Constructs the vertices and line vertices for a selection box. */ -void SelectionBox_Render(SelectionBox* box, VertexP3fC4b** vertices, VertexP3fC4b** lineVertices); - /* Draws a vertical quad. */ void SelectionBox_VerQuad(VertexP3fC4b** vertices, PackedCol col, Real32 x1, Real32 y1, Real32 z1, Real32 x2, Real32 y2, Real32 z2); @@ -39,4 +17,9 @@ void SelectionBox_HorQuad(VertexP3fC4b** vertices, PackedCol col, /* Draws a line between two points. */ void SelectionBox_Line(VertexP3fC4b** vertices, PackedCol col, Real32 x1, Real32 y1, Real32 z1, Real32 x2, Real32 y2, Real32 z2); + +IGameComponent Selections_MakeComponent(void); +void Selections_Render(Real64 delta); +void Selections_Add(UInt8 id, Vector3I p1, Vector3I p2, PackedCol col); +void Selections_Remove(UInt8 id); #endif \ No newline at end of file diff --git a/src/Client/WeatherRenderer.c b/src/Client/WeatherRenderer.c index 4e6618264..714e2a8f5 100644 --- a/src/Client/WeatherRenderer.c +++ b/src/Client/WeatherRenderer.c @@ -151,15 +151,15 @@ void WeatherRenderer_Render(Real64 deltaTime) { Real32 x1 = (Real32)x, y1 = (Real32)y, z1 = (Real32)z; Real32 x2 = (Real32)(x + 1), y2 = (Real32)(y + height), z2 = (Real32)(z + 1); - v.X = x1; v.Y = y1; v.Z = z1; v.U = 0.0f; v.V = v1; *ptr = v; ptr++; - v.Y = y2; v.V = v2; *ptr = v; ptr++; - v.X = x2; v.Z = z2; v.U = 1.0f; *ptr = v; ptr++; - v.Y = y1; v.V = v1; *ptr = v; ptr++; + v.X = x1; v.Y = y1; v.Z = z1; v.U = 0.0f; v.V = v1; *ptr++ = v; + v.Y = y2; v.V = v2; *ptr++ = v; + v.X = x2; v.Z = z2; v.U = 1.0f; *ptr++ = v; + v.Y = y1; v.V = v1; *ptr++ = v; - v.Z = z1; *ptr = v; ptr++; - v.Y = y2; v.V = v2; *ptr = v; ptr++; - v.X = x1; v.Z = z2; v.U = 0.0f; *ptr = v; ptr++; - v.Y = y1; v.V = v1; *ptr = v; ptr++; + v.Z = z1; *ptr++ = v; + v.Y = y2; v.V = v2; *ptr++ = v; + v.X = x1; v.Z = z2; v.U = 0.0f; *ptr++ = v; + v.Y = y1; v.V = v1; *ptr++ = v; } } diff --git a/src/Client/Widgets.c b/src/Client/Widgets.c index 141ea0567..a2d7e2525 100644 --- a/src/Client/Widgets.c +++ b/src/Client/Widgets.c @@ -1993,7 +1993,7 @@ Int32 PlayerListWidget_GetGroupCount(PlayerListWidget* widget, UInt16 id, Int32 Int32 PlayerListWidget_PlayerCompare(UInt16 x, UInt16 y) { UInt8 xRank = TabList_GroupRanks[x]; UInt8 yRank = TabList_GroupRanks[y]; - if (xRank != yRank) return (xRank < yRank ? 1 : -1); + if (xRank != yRank) return (xRank < yRank ? -1 : 1); UInt8 xNameBuffer[String_BufferSize(STRING_SIZE)]; String xName = String_InitAndClearArray(xNameBuffer);