1 package com.jed.core;
2
3 import com.jed.actor.AbstractEntity;
4 import com.jed.util.Rectangle;
5 import com.jed.util.Vector2f;
6 import org.lwjgl.opengl.GL11;
7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory;
9
10 import javax.annotation.Nonnull;
11 import java.util.ArrayList;
12 import java.util.List;
13
14
15
16
17
18
19 public class QuadTree implements Displayable {
20
21
22
23
24 private static final Logger LOGGER = LoggerFactory.getLogger(QuadTree.class);
25
26
27
28
29 private static final int MAX_OBJECTS = 2;
30
31
32
33
34 private static final int MAX_LEVELS = 5;
35
36
37
38
39 private final int level;
40
41
42
43
44 @Nonnull
45 private final List<AbstractEntity> objects;
46
47
48
49
50 private final Rectangle rectangle;
51
52
53
54
55 @Nonnull
56 private final QuadTree[] nodes;
57
58
59
60
61 private final Displayable parent;
62
63
64
65
66 private final Vector2f position;
67
68
69
70
71
72
73
74
75 public QuadTree(Vector2f position, int level, Rectangle rectangle, Displayable parent) {
76 this.position = position;
77 this.level = level;
78 this.objects = new ArrayList<>();
79 this.rectangle = rectangle;
80 this.nodes = new QuadTree[4];
81 this.parent = parent;
82 }
83
84
85
86
87 public void clear() {
88 objects.clear();
89 for (int i = 0; i < nodes.length; i++) {
90 if (nodes[i] != null) {
91 nodes[i].clear();
92 }
93 nodes[i] = null;
94 }
95 }
96
97
98
99
100
101
102 public void retrieve(@Nonnull List<AbstractEntity> returnObjects, @Nonnull AbstractEntity o) {
103 int index = getIndex(o);
104 if (index != -1) {
105 if (nodes[0] != null) {
106 nodes[index].retrieve(returnObjects, o);
107 }
108 returnObjects.addAll(objects);
109 } else {
110 returnObjects.addAll(getObjects());
111 }
112 }
113
114
115
116
117
118 @Nonnull
119 List<AbstractEntity> getObjects() {
120 List<AbstractEntity> ret = new ArrayList<>();
121 ret.addAll(objects);
122 if (nodes[0] != null) {
123 ret.addAll(nodes[0].getObjects());
124 ret.addAll(nodes[1].getObjects());
125 ret.addAll(nodes[2].getObjects());
126 ret.addAll(nodes[3].getObjects());
127 }
128 return ret;
129 }
130
131
132
133
134
135
136 private int getIndex(@Nonnull AbstractEntity o) {
137 int verticalMidpoint = (int) (position.x + (rectangle.getWidth() / 2));
138 int horizontalMidpoint = (int) (position.y + (rectangle.getHeight() / 2));
139
140 boolean topQuadrant = o.getBounds().getNextWorldPosition().y + o.getBounds().getHeight() < horizontalMidpoint;
141 boolean bottomQuadrant = o.getBounds().getNextWorldPosition().y > horizontalMidpoint;
142
143 if (o.getBounds().getNextWorldPosition().x + o.getBounds().getWidth() < verticalMidpoint) {
144 if (topQuadrant) {
145 return 1;
146 } else if (bottomQuadrant) {
147 return 2;
148 }
149 } else if (o.getBounds().getNextWorldPosition().x > verticalMidpoint) {
150 if (topQuadrant) {
151 return 0;
152 } else if (bottomQuadrant) {
153 return 3;
154 }
155 }
156
157 return -1;
158 }
159
160
161
162
163 private void split() {
164
165 float halfWidth = rectangle.getWidth() / 2.0f;
166 int subWidth = Math.round(halfWidth);
167 float halfHeight = rectangle.getHeight() / 2.0f;
168 int subHeight = Math.round(halfHeight);
169
170 int x = Math.round(position.x);
171 int y = Math.round(position.y);
172
173 Rectangle rect = new Rectangle(subWidth, subHeight);
174
175 this.nodes[0] = new QuadTree(new Vector2f(x + subWidth, y), this.level + 1, rect, parent);
176 this.nodes[1] = new QuadTree(new Vector2f(x, y), this.level + 1, rect, parent);
177 this.nodes[2] = new QuadTree(new Vector2f(x, y + subHeight), this.level + 1, rect, parent);
178 this.nodes[3] = new QuadTree(new Vector2f(x + subWidth, y + subHeight), this.level + 1, rect, parent);
179 }
180
181
182
183
184
185 public void insert(@Nonnull AbstractEntity o) {
186 if (nodes[0] != null) {
187 int index = getIndex(o);
188
189 if (index != -1) {
190 this.nodes[index].insert(o);
191 return;
192 }
193 }
194
195 objects.add(o);
196
197 if (objects.size() > MAX_OBJECTS && level < MAX_LEVELS) {
198 if (nodes[0] == null) {
199 split();
200 }
201
202 int i = 0;
203 while (i < objects.size()) {
204 int index = getIndex(objects.get(i));
205 if (index != -1) {
206 nodes[index].insert(objects.remove(i));
207 } else {
208 i++;
209 }
210 }
211 }
212 }
213
214 @Override
215 public void render() {
216 GL11.glColor3f(0.5f, 0.5f, 1.0f);
217
218 GL11.glBegin(GL11.GL_LINE_LOOP);
219
220 parent.drawChildVertex2f(position.x, position.y);
221 parent.drawChildVertex2f(position.x + rectangle.getWidth(), position.y);
222 parent.drawChildVertex2f(position.x + rectangle.getWidth(), position.y + rectangle.getHeight());
223 parent.drawChildVertex2f(position.x + rectangle.getWidth(), position.y + rectangle.getHeight());
224 parent.drawChildVertex2f(position.x, position.y + rectangle.getHeight());
225
226 GL11.glEnd();
227
228 if (nodes[0] != null) {
229 for (QuadTree eachNode : nodes) {
230 eachNode.render();
231 }
232 }
233 }
234
235 @Override
236 public void drawChildVertex2f(float x, float y) {
237 LOGGER.warn("{}","No OP com.jed.core.QuadTree#drawChildVertex2f");
238 }
239 }