1+ /*
2+ * Copyright 2025 Lambda
3+ *
4+ * This program is free software: you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation, either version 3 of the License, or
7+ * (at your option) any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+ package com.lambda.graphics.renderer.esp.builders
19+
20+ import com.lambda.graphics.RenderMain
21+ import com.lambda.graphics.renderer.esp.DynamicAABB
22+ import com.lambda.graphics.renderer.esp.impl.DynamicESPRenderer
23+ import com.lambda.graphics.renderer.gui.LineRenderer
24+ import net.minecraft.util.math.Vec3d
25+ import java.awt.Color
26+ import org.joml.Vector2d
27+ import org.joml.Vector4f
28+
29+ /* *
30+ * Draws a line in 3D space using the LineRenderer.
31+ *
32+ * @param points List of 3D points to connect with lines
33+ * @param color Color of the line
34+ * @param width Width of the line
35+ * @param dashiness Dashiness of the line (1.0 = solid, 0.0 = fully dashed)
36+ * @param dashPeriod Period of the dashes
37+ */
38+ fun DynamicESPRenderer.drawLine (
39+ points : List <Vec3d >,
40+ color : Color ,
41+ width : Double = 1.0,
42+ dashiness : Double = 1.0,
43+ dashPeriod : Double = 1.0
44+ ) {
45+ if (points.size < 2 ) return
46+
47+ // Project 3D points to 2D screen coordinates
48+ val screenPoints = points.mapNotNull { point ->
49+ val screenPos = project3DTo2D(point) ? : return @mapNotNull null
50+ LineRenderer .Point (Vector2d (screenPos.x, screenPos.y), color)
51+ }
52+
53+ if (screenPoints.size < 2 ) return
54+
55+ // Draw the line using LineRenderer
56+ LineRenderer .lines(
57+ dashiness = dashiness,
58+ dashPeriod = dashPeriod,
59+ batching = false
60+ ) {
61+ line(width) {
62+ screenPoints.forEach { point ->
63+ point(point.pos, point.color)
64+ }
65+ }
66+ }
67+ }
68+
69+ /* *
70+ * Draws a line in 3D space using the LineRenderer.
71+ *
72+ * @param start Starting point of the line
73+ * @param end Ending point of the line
74+ * @param startColor Color at the start of the line
75+ * @param endColor Color at the end of the line
76+ * @param width Width of the line
77+ * @param dashiness Dashiness of the line (1.0 = solid, 0.0 = fully dashed)
78+ * @param dashPeriod Period of the dashes
79+ */
80+ fun DynamicESPRenderer.drawLine (
81+ start : Vec3d ,
82+ end : Vec3d ,
83+ startColor : Color ,
84+ endColor : Color = startColor,
85+ width : Double = 1.0,
86+ dashiness : Double = 1.0,
87+ dashPeriod : Double = 1.0
88+ ) {
89+ // Project 3D points to 2D screen coordinates
90+ val startScreen = project3DTo2D(start) ? : return
91+ val endScreen = project3DTo2D(end) ? : return
92+
93+ // Draw the line using LineRenderer
94+ LineRenderer .lines(
95+ dashiness = dashiness,
96+ dashPeriod = dashPeriod,
97+ batching = false
98+ ) {
99+ line(width) {
100+ point(Vector2d (startScreen.x, startScreen.y), startColor)
101+ point(Vector2d (endScreen.x, endScreen.y), endColor)
102+ }
103+ }
104+ }
105+
106+ /* *
107+ * Draws a line between two dynamic boxes in 3D space using the LineRenderer.
108+ *
109+ * @param box1 First dynamic box
110+ * @param box2 Second dynamic box
111+ * @param color Color of the line
112+ * @param width Width of the line
113+ * @param dashiness Dashiness of the line (1.0 = solid, 0.0 = fully dashed)
114+ * @param dashPeriod Period of the dashes
115+ */
116+ fun DynamicESPRenderer.drawLineBetweenBoxes (
117+ box1 : DynamicAABB ,
118+ box2 : DynamicAABB ,
119+ color : Color ,
120+ width : Double = 1.0,
121+ dashiness : Double = 1.0,
122+ dashPeriod : Double = 1.0
123+ ) {
124+ val box1Pair = box1.getBoxPair() ? : return
125+ val box2Pair = box2.getBoxPair() ? : return
126+
127+ val center1 = Vec3d (
128+ (box1Pair.first.minX + box1Pair.first.maxX) / 2 ,
129+ (box1Pair.first.minY + box1Pair.first.maxY) / 2 ,
130+ (box1Pair.first.minZ + box1Pair.first.maxZ) / 2
131+ )
132+
133+ val center2 = Vec3d (
134+ (box2Pair.first.minX + box2Pair.first.maxX) / 2 ,
135+ (box2Pair.first.minY + box2Pair.first.maxY) / 2 ,
136+ (box2Pair.first.minZ + box2Pair.first.maxZ) / 2
137+ )
138+
139+ drawLine(center1, center2, color, color, width, dashiness, dashPeriod)
140+ }
141+
142+ /* *
143+ * Projects a 3D point to 2D screen coordinates.
144+ * Returns null if the point is behind the camera or outside the screen.
145+ */
146+ private fun project3DTo2D (point : Vec3d ): Vector2d ? {
147+ // Create a 4D vector from the 3D point
148+ val vec4 = Vector4f (
149+ point.x.toFloat(),
150+ point.y.toFloat(),
151+ point.z.toFloat(),
152+ 1f
153+ )
154+
155+ // Transform the point using the projection-model matrix
156+ RenderMain .projModel.transform(vec4)
157+
158+ // Check if the point is behind the camera
159+ if (vec4.w <= 0f ) return null
160+
161+ // Perform perspective division
162+ vec4.div(vec4.w)
163+
164+ // Convert from normalized device coordinates (-1 to 1) to screen coordinates (0 to screen width/height)
165+ val screenX = (vec4.x * 0.5f + 0.5f ) * RenderMain .screenSize.x.toFloat()
166+ val screenY = (1f - (vec4.y * 0.5f + 0.5f )) * RenderMain .screenSize.y.toFloat()
167+
168+ // Check if the point is outside the screen
169+ if (screenX < 0 || screenX > RenderMain .screenSize.x.toFloat() || screenY < 0 || screenY > RenderMain .screenSize.y.toFloat()) {
170+ return null
171+ }
172+
173+ return Vector2d (screenX.toDouble(), screenY.toDouble())
174+ }
0 commit comments