Skip to content

Commit 16d51be

Browse files
committed
Shape mesh prototype
1 parent 405ff12 commit 16d51be

File tree

2 files changed

+116
-116
lines changed

2 files changed

+116
-116
lines changed

common/src/main/kotlin/com/lambda/graphics/renderer/esp/EspRenderer.kt

Lines changed: 106 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,20 @@ import com.lambda.module.modules.client.RenderSettings
2020
import com.lambda.util.primitives.extension.max
2121
import com.lambda.util.primitives.extension.min
2222
import net.minecraft.util.math.Box
23+
import net.minecraft.util.math.Vec3d
2324
import java.awt.Color
2425
import java.util.concurrent.ConcurrentHashMap
25-
import kotlin.math.abs
26-
import kotlin.math.hypot
2726

2827
class EspRenderer(
2928
usage: BufferUsage = BufferUsage.STATIC
3029
) {
31-
private val filled = VAO(VertexMode.TRIANGLES, VertexAttrib.Group.STATIC_RENDERER, usage, true)
32-
private val filledVertices = ConcurrentHashMap<Vertex, Int>()
30+
private val faces = VAO(VertexMode.TRIANGLES, VertexAttrib.Group.STATIC_RENDERER, usage, true)
31+
private val faceVertices = ConcurrentHashMap<Vertex, Int>()
3332

34-
private val outline = VAO(VertexMode.LINES, VertexAttrib.Group.STATIC_RENDERER, usage, true)
33+
private val outlines = VAO(VertexMode.LINES, VertexAttrib.Group.STATIC_RENDERER, usage, true)
3534
private val outlineVertices = ConcurrentHashMap<Vertex, Int>()
3635

37-
private var updateFilled = false
36+
private var updateFaces = false
3837
private var updateOutline = false
3938

4039
fun build(
@@ -48,93 +47,8 @@ class EspRenderer(
4847
buildOutline(box, outlineColor, sides, outlineMode)
4948
}
5049

51-
fun buildConvexHull(
52-
boxes: Set<Box>,
53-
color: Color
54-
) = outline.use {
55-
updateOutline = true
56-
57-
// Step 1: Collect all vertices
58-
val vertices = mutableSetOf<Vertex>()
59-
boxes.forEach { box ->
60-
val pos1 = box.min
61-
val pos2 = box.max
62-
63-
vertices.add(Vertex(pos1.x, pos1.y, pos1.z, color))
64-
vertices.add(Vertex(pos1.x, pos1.y, pos2.z, color))
65-
vertices.add(Vertex(pos2.x, pos1.y, pos1.z, color))
66-
vertices.add(Vertex(pos2.x, pos1.y, pos2.z, color))
67-
vertices.add(Vertex(pos1.x, pos2.y, pos1.z, color))
68-
vertices.add(Vertex(pos1.x, pos2.y, pos2.z, color))
69-
vertices.add(Vertex(pos2.x, pos2.y, pos1.z, color))
70-
vertices.add(Vertex(pos2.x, pos2.y, pos2.z, color))
71-
}
72-
73-
// Step 2: Find the convex hull
74-
val convexHull = findConvexHull(vertices)
75-
76-
// Step 3: Build outline of convex hull
77-
for (i in convexHull.indices) {
78-
val v1 = convexHull[i]
79-
val v2 = convexHull[(i + 1) % convexHull.size]
80-
val intV1 = vec3(v1.x, v1.y, v1.z).color(v1.color).end()
81-
val intV2 = vec3(v2.x, v2.y, v2.z).color(v2.color).end()
82-
putLine(intV1, intV2)
83-
}
84-
}
85-
86-
// Utility function to find the convex hull using the QuickHull algorithm
87-
private fun findConvexHull(vertices: Set<Vertex>): List<Vertex> {
88-
if (vertices.size <= 1) return vertices.toList()
89-
90-
val points = vertices.toMutableList()
91-
points.sortWith(compareBy({ it.x }, { it.y }))
92-
val left = points.first()
93-
val right = points.last()
94-
95-
val (leftSet, rightSet) = points.partition { isLeft(left, right, it) }
96-
97-
val hull = mutableListOf<Vertex>()
98-
hull.add(left)
99-
hull.addAll(findHull(left, right, leftSet))
100-
hull.add(right)
101-
hull.addAll(findHull(right, left, rightSet))
102-
103-
return hull
104-
}
105-
106-
// Check if the point is on the left side of the line from start to end
107-
private fun isLeft(start: Vertex, end: Vertex, point: Vertex): Boolean {
108-
return (end.x - start.x) * (point.y - start.y) - (end.y - start.y) * (point.x - start.x) > 0
109-
}
110-
111-
// Recursively find the hull points
112-
private fun findHull(start: Vertex, end: Vertex, points: List<Vertex>): List<Vertex> {
113-
if (points.isEmpty()) return emptyList()
114-
115-
val farthest = points.maxByOrNull { distanceFromLine(start, end, it) } ?: return emptyList()
116-
117-
// Partition points into two sets: those to the left of the line (start, farthest) and those to the left of (farthest, end)
118-
val (leftSetStartFarthest, _) = points.partition { isLeft(start, farthest, it) }
119-
val (leftSetFarthestEnd, _) = points.partition { isLeft(farthest, end, it) }
120-
121-
val hull = mutableListOf<Vertex>()
122-
hull.addAll(findHull(start, farthest, leftSetStartFarthest))
123-
hull.add(farthest)
124-
hull.addAll(findHull(farthest, end, leftSetFarthestEnd))
125-
126-
return hull
127-
}
128-
129-
// Calculate the distance from the line
130-
private fun distanceFromLine(start: Vertex, end: Vertex, point: Vertex): Double {
131-
val area = abs((end.x - start.x) * (point.y - start.y) - (end.y - start.y) * (point.x - start.x))
132-
val base = Math.hypot((end.x - start.x), (end.y - start.y))
133-
return area / base
134-
}
135-
136-
fun buildFilled(box: Box, color: Color, sides: Int = DirectionMask.ALL) = filled.use {
137-
updateFilled = true
50+
fun buildFilled(box: Box, color: Color, sides: Int = DirectionMask.ALL) = faces.use {
51+
updateFaces = true
13852
val pos1 = box.min
13953
val pos2 = box.max
14054

@@ -157,7 +71,12 @@ class EspRenderer(
15771
if (sides.hasDirection(NORTH)) putQuad(blb, tlb, trb, brb)
15872
}
15973

160-
fun buildOutline(box: Box, color: Color, sides: Int = DirectionMask.ALL, outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR) = outline.use {
74+
fun buildOutline(
75+
box: Box,
76+
color: Color,
77+
sides: Int = DirectionMask.ALL,
78+
outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR
79+
) = outlines.use {
16180
updateOutline = true
16281
val pos1 = box.min
16382
val pos2 = box.max
@@ -196,32 +115,112 @@ class EspRenderer(
196115
if (outlineMode.check(hasSouth, hasWest)) putLine(tlf, blf)
197116
}
198117

118+
infix operator fun Vec3d.compareTo(other: Vec3d) =
119+
lengthSquared().compareTo(other.lengthSquared())
120+
121+
fun buildMesh(boxes: Set<Box>, color: Color) {
122+
val edges = hashMapOf<Edge, Int>()
123+
val faces = hashMapOf<Face, Int>()
124+
125+
fun addFace(v1: Vec3d, v2: Vec3d, v3: Vec3d, v4: Vec3d) {
126+
val face = Face(v1, v2, v3, v4)
127+
faces[face] = faces.getOrDefault(face, 0) + 1
128+
}
129+
130+
fun addEdge(v1: Vec3d, v2: Vec3d) {
131+
val edge = if (v1 < v2) Edge(v1, v2) else Edge(v2, v1)
132+
edges[edge] = edges.getOrDefault(edge, 0) + 1
133+
}
134+
135+
boxes.forEach { box ->
136+
val pos1 = box.min
137+
val pos2 = box.max
138+
139+
val blb = Vec3d(pos1.x, pos1.y, pos1.z)
140+
val blf = Vec3d(pos1.x, pos1.y, pos2.z)
141+
val brb = Vec3d(pos2.x, pos1.y, pos1.z)
142+
val brf = Vec3d(pos2.x, pos1.y, pos2.z)
143+
val tlb = Vec3d(pos1.x, pos2.y, pos1.z)
144+
val tlf = Vec3d(pos1.x, pos2.y, pos2.z)
145+
val trb = Vec3d(pos2.x, pos2.y, pos1.z)
146+
val trf = Vec3d(pos2.x, pos2.y, pos2.z)
147+
148+
addFace(blb, blf, brf, brb)
149+
addFace(tlb, tlf, trf, trb)
150+
addFace(blb, brb, trb, tlb)
151+
addFace(blf, brf, trf, tlf)
152+
addFace(blb, blf, tlf, tlb)
153+
addFace(brb, brf, trf, trb)
154+
155+
addEdge(tlb, trb)
156+
addEdge(tlf, trf)
157+
addEdge(tlb, tlf)
158+
addEdge(trf, trb)
159+
160+
addEdge(blb, brb)
161+
addEdge(blf, brf)
162+
addEdge(blb, blf)
163+
addEdge(brb, brf)
164+
165+
addEdge(tlb, blb)
166+
addEdge(trb, brb)
167+
addEdge(trf, brf)
168+
addEdge(tlf, blf)
169+
}
170+
171+
this.faces.use {
172+
updateFaces = true
173+
faces.forEach { (face, count) ->
174+
if (count % 2 == 0) return@forEach
175+
grow(1)
176+
putQuad(
177+
vec3(face.v1.x, face.v1.y, face.v1.z).color(color).end(),
178+
vec3(face.v2.x, face.v2.y, face.v2.z).color(color).end(),
179+
vec3(face.v3.x, face.v3.y, face.v3.z).color(color).end(),
180+
vec3(face.v4.x, face.v4.y, face.v4.z).color(color).end()
181+
)
182+
}
183+
}
184+
185+
outlines.use {
186+
updateOutline = true
187+
edges.forEach { (edge, count) ->
188+
if (count % 2 == 0) return@forEach
189+
grow(1)
190+
putLine(
191+
vec3(edge.start.x, edge.start.y, edge.start.z).color(color).end(),
192+
vec3(edge.end.x, edge.end.y, edge.end.z).color(color).end()
193+
)
194+
}
195+
}
196+
}
197+
199198
fun upload() {
200-
if (updateFilled) {
201-
updateFilled = false
202-
filled.upload()
199+
if (updateFaces) {
200+
updateFaces = false
201+
faces.upload()
203202
}
204203

205204
if (updateOutline) {
206205
updateOutline = false
207-
outline.upload()
206+
outlines.upload()
208207
}
209208
}
210209

211210
fun render() {
212211
shader.use()
213212
shader["u_CameraPosition"] = mc.gameRenderer.camera.pos
214213

215-
withFaceCulling(filled::render)
216-
withLineWidth(RenderSettings.outlineWidth, outline::render)
214+
withFaceCulling(faces::render)
215+
withLineWidth(RenderSettings.outlineWidth, outlines::render)
217216
}
218217

219218
fun clear() {
220-
filledVertices.clear()
219+
faceVertices.clear()
221220
outlineVertices.clear()
222221

223-
filled.clear()
224-
outline.clear()
222+
faces.clear()
223+
outlines.clear()
225224
}
226225

227226
private fun IRenderContext.vertex(
@@ -233,12 +232,13 @@ class EspRenderer(
233232
}
234233

235234
if (RenderSettings.vertexMapping) {
236-
filledVertices.getOrPut(Vertex(x, y, z, color), newVertex)
235+
faceVertices.getOrPut(Vertex(x, y, z, color), newVertex)
237236
} else newVertex()
238237
}
239238

240-
private data class Vertex(val x: Double, val y: Double, val z: Double, val color: Color)
241-
private data class Edge(val vertex1: Vertex, val vertex2: Vertex)
239+
data class Vertex(val x: Double, val y: Double, val z: Double, val color: Color)
240+
data class Edge(val start: Vec3d, val end: Vec3d)
241+
data class Face(val v1: Vec3d, val v2: Vec3d, val v3: Vec3d, val v4: Vec3d)
242242

243243
companion object {
244244
private val shader = Shader("renderer/pos_color", "renderer/box_static")

common/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ object BlockESP : Module(
5454
private val shaped: Boolean by setting("Shaped", false, "Render outline shape").apply {
5555
onValueSet { _, _ -> esp.rebuild() }
5656
}
57-
private val blocks: Set<Block> by setting("Blocks", setOf(Blocks.ANVIL), "Render blocks").apply {
57+
private val blocks: Set<Block> by setting("Blocks", setOf(Blocks.BEDROCK), "Render blocks").apply {
5858
onValueSet { _, _ -> esp.rebuild() }
5959
}
6060

@@ -79,25 +79,25 @@ object BlockESP : Module(
7979
val state = view.getBlockState(blockPos)
8080
if (state.block !in blocks) return@newChunkedESP
8181

82-
var sides = DirectionMask.ALL
83-
84-
if (mesh) {
85-
Direction.entries
86-
.filter { blockPos.offset(it).blockState(view).block in blocks }
87-
.forEach { sides = sides.exclude(it.mask) }
88-
}
89-
9082
if (shaped) {
9183
val shape = state.getOutlineShape(view, blockPos)
9284
if (shape.isEmpty) return@newChunkedESP
9385
val boxes = shape.boundingBoxes
9486
.map { it.offset(blockPos) }
9587
.toSet()
9688

97-
buildConvexHull(boxes, outlineColor)
89+
buildMesh(boxes, outlineColor)
9890
return@newChunkedESP
9991
}
10092

93+
var sides = DirectionMask.ALL
94+
95+
if (mesh) {
96+
Direction.entries
97+
.filter { blockPos.offset(it).blockState(view).block in blocks }
98+
.forEach { sides = sides.exclude(it.mask) }
99+
}
100+
101101
build(Box(blockPos), sides)
102102
}
103103

0 commit comments

Comments
 (0)