JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
Group.java
Go to the documentation of this file.
1/**
2 * Copyright 2023-2024 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28package com.jogamp.graph.ui;
29
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.Collection;
33import java.util.Comparator;
34import java.util.List;
35import java.util.concurrent.CopyOnWriteArrayList;
36
37import com.jogamp.graph.curve.Region;
38import com.jogamp.graph.curve.opengl.RegionRenderer;
39import com.jogamp.graph.ui.layout.Padding;
40import com.jogamp.graph.ui.shapes.Rectangle;
41import com.jogamp.math.FloatUtil;
42import com.jogamp.math.Matrix4f;
43import com.jogamp.math.Vec2f;
44import com.jogamp.math.Vec3f;
45import com.jogamp.math.Vec4f;
46import com.jogamp.math.geom.AABBox;
47import com.jogamp.math.geom.Cube;
48import com.jogamp.math.geom.Frustum;
49import com.jogamp.math.util.PMVMatrix4f;
50import com.jogamp.opengl.GL2ES2;
51import com.jogamp.opengl.GLProfile;
52
53import jogamp.graph.ui.TreeTool;
54
55/**
56 * Group of {@link Shape}s, optionally utilizing a {@link Group.Layout}.
57 * @see Scene
58 * @see Shape
59 * @see Group.Layout
60 */
61public class Group extends Shape implements Container {
62 /** Layout for the GraphUI {@link Group}, called @ {@link Shape#validate(GL2ES2)} or {@link Shape#validate(GLProfile)}. */
63 public static interface Layout {
64 /** Prepare given {@link Shape} before {@link Shape#validate(GL2ES2) validation}, e.g. {@link Shape#setPaddding(Padding)}. */
65 void preValidate(final Shape s);
66
67 /**
68 * Performing the layout of {@link Group#getShapes()}, called @ {@link Shape#validate(GL2ES2)} or {@link Shape#validate(GLProfile)}.
69 * <p>
70 * According to the implemented layout, method
71 * - may scale the {@Link Shape}s
72 * - may move the {@Link Shape}s
73 * - may reuse the given {@link PMVMatrix4f} `pmv`
74 * - must update the given {@link AABBox} `box`
75 * </p>
76 * @param g the {@link Group} to layout
77 * @param box the bounding box of {@link Group} to be updated by this method.
78 * @param pmv a {@link PMVMatrix4f} which can be reused.
79 */
80 void layout(final Group g, final AABBox box, final PMVMatrix4f pmv);
81 }
82
83 private final List<Shape> shapes = new CopyOnWriteArrayList<Shape>();
84 private Shape[] drawShapeArray = new Shape[0]; // reduce memory re-alloc @ display
85 private final List<Shape> renderedShapesB0 = new ArrayList<Shape>();
86 private final List<Shape> renderedShapesB1 = new ArrayList<Shape>();
87 private final List<Shape> renderedShapesB2 = new ArrayList<Shape>();
88 private volatile List<Shape> renderedShapes = renderedShapesB1;
89 private int renderedShapesIdx = 1;
90 /** Enforced fixed size. In case z-axis is NaN, its 3D z-axis will be adjusted. */
91 private final Vec3f fixedSize = new Vec3f();
92 private Layout layouter;
93 private Rectangle border = null;
94
95 private boolean relayoutOnDirtyShapes = true;
96 private Scene topLevelHolder = null;
97 private boolean clipOnBounds = false;
98 private Frustum clipFrustum = null;
99
100 /**
101 * Create a group of {@link Shape}s w/o {@link Group.Layout}.
102 * <p>
103 * Default is {@link #setInteractive(boolean) non-interactive}.
104 * </p>
105 */
106 public Group() {
107 this(null, null, null, null);
108 }
109
110 /**
111 * Create a group of {@link Shape}s w/ given {@link Group.Layout}.
112 * <p>
113 * Default is {@link #setInteractive(boolean) non-interactive}.
114 * </p>
115 * @param l optional {@link Layout}, maybe {@code null}
116 */
117 public Group(final Layout l) {
118 this(null, l, null, null);
119 }
120
121 /**
122 * Create a group of {@link Shape}s w/ given {@link Group.Layout} and {@link Shape}.
123 * <p>
124 * Default is {@link #setInteractive(boolean) non-interactive}.
125 * </p>
126 * @param name optional name for {@link #setName(String)}
127 * @param l optional {@link Layout}, maybe {@code null}
128 * @param fixedSize optional fixed size for {@link #setFixedSize(Vec2f)}
129 * @param s optional {@link Shape} for {@link #addShape(Shape)}
130 */
131 public Group(final String name, final Layout l, final Vec2f fixedSize, final Shape s) {
132 super();
133 if( null != name ) {
134 this.setName(name);
135 }
136 this.layouter = l;
137 this.setInteractive(false);
138 if( null != fixedSize ) {
139 this.setFixedSize(fixedSize);
140 }
141 if( null != s ) {
142 addShape(s);
143 }
144 }
145
146 @Override
147 public final boolean isGroup() { return true; }
148
149 /** Return current {@link Group.Layout}. */
150 public Layout getLayout() { return layouter; }
151
152 /** Set {@link Group.Layout}. */
153 public Group setLayout(final Layout l) { layouter = l; return this; }
154
155 /** Enforce size of this group for all given 3 dimensions {@link #getBounds()} without adjusting 3D z-axis like {@link #setFixedSize(Vec2f)}. */
156 public Group setFixedSize(final Vec3f v) { fixedSize.set(v); return this; }
157 /**
158 * Enforce size of this group to given 2 dimensions,
159 * adjusting the 3D z-axis {@link #getBounds()} giving room for potential clipping via {@link #setClipOnBounds(boolean)} or {@link #setClipMvFrustum(Frustum)}.
160 * @see #setFixedSize(Vec3f)
161 */
162 public Group setFixedSize(final Vec2f v) { fixedSize.set(v.x(), v.y(), Float.NaN); return this; }
163 /** Returns borrowed fixed size instance, see {@link #setFixedSize(Vec3f)} and {@link #setFixedSize(Vec2f)}. */
164 public Vec3f getFixedSize() { return fixedSize; }
165 /** Returns given {@link Vec2f} instance set with 2 dimensions, see {@link #setFixedSize(Vec2f)}. */
166 public Vec2f getFixedSize(final Vec2f out) { out.set(fixedSize.x(), fixedSize.y()); return out; }
167
168 /**
169 * Enable Modelview (Mv) {@link Frustum} clipping on {@link #getBounds()} for this group and its shapes as follows
170 * <ul>
171 * <li>Discard {@link Shape} {@link #draw(GL2ES2, RegionRenderer) rendering} if not intersecting {@code clip-box}.</li>
172 * <li>Otherwise perform pixel-accurate clipping inside the shader to {@code clip-box}.</li>
173 * </ul>
174 * <p>
175 * {@link #setClipMvFrustum(Frustum)} takes precedence over {@link #setClipOnBounds(boolean)}.
176 * </p>
177 * <p>
178 * With clipping enabled, the 3D z-axis {@link #getBounds()} depth
179 * will be slightly increased for functional {@link Frustum} operation.
180 * </p>
181 * @param v boolean to toggle clipping
182 * @return this instance for chaining
183 * @see #setClipMvFrustum(Frustum)
184 * @see #setFixedSize(Vec2f)
185 * @see #setFixedSize(Vec3f)
186 */
187 public Group setClipOnBounds(final boolean v) { clipOnBounds = v; return this; }
188 /** Returns {@link #setClipOnBounds(boolean)} value */
189 public boolean getClipOnBounds() { return clipOnBounds; }
190
191 /**
192 * Enable Modelview (Mv) {@link Frustum} clipping on explicit given pre-multiplied w/ Mv-matrix {@code clip-box}
193 * for this group and its shapes as follows
194 * <ul>
195 * <li>Discard {@link Shape} {@link #draw(GL2ES2, RegionRenderer) rendering} if not intersecting {@code clip-box}.</li>
196 * <li>Otherwise perform pixel-accurate clipping inside the shader to {@code clip-box}.</li>
197 * </ul>
198 * <p>
199 * {@link #setClipMvFrustum(Frustum)} takes precedence over {@link #setClipOnBounds(boolean)}.
200 * </p>
201 * <p>
202 * With clipping enabled, the 3D z-axis {@link #getBounds()} depth
203 * will be slightly increased for functional {@link Frustum} operation.
204 * </p>
205 * @param v {@link Frustum} pre-multiplied w/ Mv-matrix
206 * @return this instance for chaining
207 * @see #setClipOnBounds(boolean)
208 * @see #setFixedSize(Vec2f)
209 * @see #setFixedSize(Vec3f)
210 */
211 public Group setClipMvFrustum(final Frustum v) { clipFrustum = v; return this; }
212 /** Returns {@link #setClipMvFrustum(Frustum)} value */
213 public Frustum getClipMvFrustum() { return clipFrustum; }
214
215 @Override
216 public int getShapeCount() { return shapes.size(); }
217
218 @Override
219 public List<Shape> getShapes() { return shapes; }
220
221 @Override
222 public List<Shape> getRenderedShapes() { return renderedShapes; }
223
224 @Override
225 public void addShape(final Shape s) {
226 shapes.add(s);
227 s.setParent(this);
229 }
230
231 /**
232 * Atomic replacement of the given {@link Shape} {@code remove} with {@link Shape} {@code replacement}.
233 * @param remove the shape to be replaced
234 * @param replacement the replacement shape to be inserted at same position
235 * @return true if shape {@code remove} is contained and replaced by {@code replacement}, otherwise false.
236 */
237 public boolean replaceShape(final Shape remove, final Shape replacement) {
238 final int idx = shapes.indexOf(remove);
239 if( 0 > idx ) {
240 return false;
241 }
242 if( null == shapes.remove(idx) ) {
243 return false;
244 }
245 remove.setParent(null);
246 shapes.add(idx, replacement);
247 replacement.setParent(this);
249 return true;
250 }
251
252 @Override
253 public Shape removeShape(final Shape s) {
254 if( shapes.remove(s) ) {
255 s.setParent(null);
257 return s;
258 } else {
259 return null;
260 }
261 }
262
263 @Override
264 public void removeShapes(final Collection<? extends Shape> shapes) {
265 for(final Shape s : shapes) {
266 removeShape(s);
267 }
268 }
269
270 @Override
271 public boolean removeShape(final GL2ES2 gl, final RegionRenderer renderer, final Shape s) {
272 if( shapes.remove(s) ) {
273 s.setParent(null);
275 s.destroy(gl, renderer);
276 return true;
277 } else {
278 return false;
279 }
280 }
281
282 @Override
283 public void addShapes(final Collection<? extends Shape> shapes) {
284 for(final Shape s : shapes) {
285 addShape(s);
286 }
287 }
288 @Override
289 public void removeShapes(final GL2ES2 gl, final RegionRenderer renderer, final Collection<? extends Shape> shapes) {
290 for(final Shape s : shapes) {
291 removeShape(gl, renderer, s);
292 }
293 }
294
295 @Override
296 public void removeAllShapes(final GL2ES2 gl, final RegionRenderer renderer) {
297 final int count = shapes.size();
298 for(int i=count-1; i>=0; --i) {
299 removeShape(gl, renderer, shapes.get(i));
300 }
301 }
302
303 @Override
304 public boolean hasColorChannel() {
305 return false; // FIXME
306 }
307
308 @Override
309 protected void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer) {
311 for(final Shape s : shapes) {
312 s.clear(gl, renderer);
313 }
314 shapes.clear();
315 drawShapeArray = new Shape[0];
316 renderedShapesB0.clear();
317 renderedShapesB1.clear();
318 renderedShapesB2.clear();
319 renderedShapes = renderedShapesB1;
320 renderedShapesIdx = 1;
321 }
322
323 @Override
324 protected void destroyImpl0(final GL2ES2 gl, final RegionRenderer renderer) {
326 for(final Shape s : shapes) {
327 // s.destroyImpl0(gl, renderer);
328 s.destroy(gl, renderer);
329 }
330 shapes.clear();
331 drawShapeArray = new Shape[0];
332 renderedShapesB0.clear();
333 renderedShapesB1.clear();
334 renderedShapesB2.clear();
335 renderedShapes = renderedShapesB1;
336 renderedShapesIdx = 1;
337 if( null != border ) {
338 border.destroy(gl, renderer);
339 border = null;
340 }
341 }
342
343 private boolean doFrustumCulling = false;
344
345 @Override
346 public final void setPMvCullingEnabled(final boolean v) { doFrustumCulling = v; }
347
348 @Override
349 public final boolean isPMvCullingEnabled() { return doFrustumCulling; }
350
351 @Override
352 public final boolean isCullingEnabled() { return doFrustumCulling || clipOnBounds || null != clipFrustum; }
353
354 @Override
355 public final boolean isOutside(final PMVMatrix4f pmv, final Shape shape) {
356 final AABBox shapeBox = shape.getBounds();
357 final boolean useClipFrustum = null != clipFrustum;
358 if( useClipFrustum || clipOnBounds ) {
359 final Frustum frustumMv = useClipFrustum ? clipFrustum : tempC00.set( box ).transform( pmv.getMv() ).updateFrustumPlanes(tempF00);
360 pmv.pushMv();
361 shape.applyMatToMv(pmv);
362 final boolean res;
363 if( doFrustumCulling && pmv.getFrustum().isOutside( shapeBox ) ) {
364 res = true;
365 } else {
366 final Cube shapeMv = tempC01.set( shapeBox ).transform( pmv.getMv() );
367 res = frustumMv.isOutside( shapeMv );
368 }
369 pmv.popMv();
370 return res;
371 } else if( doFrustumCulling ){
372 pmv.pushMv();
373 shape.applyMatToMv(pmv);
374 final boolean res = pmv.getFrustum().isOutside( shapeBox );
375 pmv.popMv();
376 return res;
377 } else {
378 return false;
379 }
380 }
381 @Override
382 public boolean isOutside2(final Matrix4f mvCont, final Shape shape, final PMVMatrix4f pmvShape) {
383 final AABBox shapeBox = shape.getBounds();
384 final boolean useClipFrustum = null != clipFrustum;
385 if( useClipFrustum || clipOnBounds ) {
386 final Frustum frustumMv = useClipFrustum ? clipFrustum : tempC00.set( box ).transform( mvCont ).updateFrustumPlanes(tempF00);
387 final boolean res;
388 if( doFrustumCulling && pmvShape.getFrustum().isOutside( shapeBox ) ) {
389 res = true;
390 } else {
391 final Cube shapeMv = tempC01.set( shapeBox ).transform( pmvShape.getMv() );
392 res = frustumMv.isOutside( shapeMv );
393 }
394 return res;
395 } else if( doFrustumCulling ){
396 return pmvShape.getFrustum().isOutside( shapeBox );
397 } else {
398 return false;
399 }
400 }
401
402 @Override
403 protected void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final Vec4f rgba) {
404 final PMVMatrix4f pmv = renderer.getMatrix();
405 final int shapeCount = shapes.size();
406 Arrays.fill(drawShapeArray, null); // flush old refs
407 final Shape[] shapeArray = shapes.toArray(drawShapeArray); // local-backup
408 drawShapeArray = shapeArray; // keep backup
409 Arrays.sort(shapeArray, 0, shapeCount, Shape.ZAscendingComparator);
410 // TreeTool.cullShapes(shapeArray, shapeCount);
411
412 final List<Shape> iShapes;
413 final int iShapeIdx;
414 switch(renderedShapesIdx) {
415 case 0: iShapeIdx = 1; iShapes = renderedShapesB1; break;
416 case 1: iShapeIdx = 2; iShapes = renderedShapesB2; break;
417 default: iShapeIdx = 0; iShapes = renderedShapesB0; break;
418 }
419 final boolean useClipFrustum = null != clipFrustum;
420 if( useClipFrustum || clipOnBounds ) {
421 final Frustum origClipFrustum = renderer.getClipFrustum();
422
423 final Frustum frustumMv = useClipFrustum ? clipFrustum : tempC00.set( box ).transform( pmv.getMv() ).updateFrustumPlanes(tempF00);
424 renderer.setClipFrustum( frustumMv );
425
426 synchronized( iShapes ) { // tripple-buffering is just almost enough
427 iShapes.clear();
428 for(int i=0; i<shapeCount; i++) {
429 final Shape shape = shapeArray[i];
430 if( shape.isVisible() ) { // && !shape.isDiscarded() ) {
431 pmv.pushMv();
432 shape.applyMatToMv(pmv);
433
434 final AABBox shapeBox = shape.getBounds();
435 final Cube shapeMv = tempC01.set( shapeBox ).transform( pmv.getMv() );
436
437 if( ( !frustumMv.isOutside( shapeMv ) ) &&
438 ( !doFrustumCulling || !pmv.getFrustum().isOutside( shapeBox ) ) )
439 {
440 shape.draw(gl, renderer);
441 iShapes.add(shape);
442 shape.setDiscarded(false);
443 } else {
444 shape.setDiscarded(true);
445 }
446 pmv.popMv();
447 }
448 }
449 }
450 renderer.setClipFrustum(origClipFrustum);
451 } else {
452 synchronized( iShapes ) { // tripple-buffering is just almost enough
453 iShapes.clear();
454 for(int i=0; i<shapeCount; i++) {
455 final Shape shape = shapeArray[i];
456 if( shape.isVisible() ) { // && !shape.isDiscarded() ) {
457 pmv.pushMv();
458 shape.applyMatToMv(pmv);
459 if( !doFrustumCulling || !pmv.getFrustum().isOutside( shape.getBounds() ) ) {
460 shape.draw(gl, renderer);
461 iShapes.add(shape);
462 shape.setDiscarded(false);
463 } else {
464 shape.setDiscarded(true);
465 }
466 pmv.popMv();
467 }
468 }
469 }
470 }
471 renderedShapes = iShapes;
472 renderedShapesIdx = iShapeIdx;
473 if( null != border && border.isVisible() ) {
474 border.draw(gl, renderer);
475 }
476 }
477 private final Frustum tempF00 = new Frustum(); // OK, synchronized
478 private final Cube tempC00 = new Cube(); // OK, synchronized
479 private final Cube tempC01 = new Cube(); // OK, synchronized
480
481 @SuppressWarnings({ "unchecked", "rawtypes" })
482 @Override
483 protected final void drawToSelectImpl0(final GL2ES2 gl, final RegionRenderer renderer) {
484 final PMVMatrix4f pmv = renderer.getMatrix();
485 final Object[] shapesS = shapes.toArray();
486 Arrays.sort(shapesS, (Comparator)Shape.ZAscendingComparator);
487
488 final int shapeCount = shapesS.length;
489 for(int i=0; i<shapeCount; i++) {
490 final Shape shape = (Shape) shapesS[i];
491 if( shape.isVisible() ) {
492 pmv.pushMv();
493 shape.applyMatToMv(pmv);
494
495 if( !doFrustumCulling || !pmv.getFrustum().isOutside( shape.getBounds() ) ) {
496 shape.drawToSelect(gl, renderer);
497 }
498 pmv.popMv();
499 }
500 }
501 if( null != border && border.isVisible() ) {
502 border.drawToSelect(gl, renderer);
503 }
504 }
505
506 /**
507 * Set relayout on dirty shapes mode, defaults to true.
508 * <p>
509 * If relayouting on dirty shape mode is enabler (default),
510 * {@link #isShapeDirty()} traverses through all shapes updating all dirty states of all its groups
511 * provoking a relayout if required.
512 * </p>
513 */
514 public void setRelayoutOnDirtyShapes(final boolean v) { relayoutOnDirtyShapes = v; }
515 public boolean getRelayoutOnDirtyShapes() { return relayoutOnDirtyShapes; }
516
517 /**
518 * Enables top-level widget behavior for this group, default is disabled.
519 * <p>
520 * Enabled top-level widget behavior for a group causes
521 * <ul>
522 * <li>the whole group to be shown on top on (mouse over) activation of one of its elements</li>
523 * <li>this group's {@link #addActivationListener(Listener)} to handle all it's elements activation events</li>
524 * <li>{@link #isActive()} of this group to return true if one of its elements is active</li>
525 * </ul>
526 * </p>
527 * <p>
528 * Disable this behavior via {@link #disableTopLevelWidget()}, otherwise done
529 * at {@link #clear(GL2ES2, RegionRenderer)} or {@link #destroy(GL2ES2, RegionRenderer)}.
530 * </p>
531 * @param scene the top-level widget holder where this {@link Group} gets registered
532 * @return this group for chaining
533 * @see #disableTopLevelWidget()
534 */
535 public final Group enableTopLevelWidget(final Scene scene) {
536 topLevelHolder = scene;
537 scene.addTopLevel(this);
538 return this;
539 }
540 /** Disables top-level widget behavior as potentially set via {@link #enableTopLevelWidget(Scene)}. NOP if not enabled. */
542 final Scene tlh = topLevelHolder;
543 topLevelHolder = null;
544 if( null != tlh ) {
545 tlh.removeTopLevel(this);
546 }
547 return this;
548 }
549 /** Returns whether {@link #setTopLevelWidget(boolean)} is enabled or disabled. */
550 public final boolean isTopLevelWidget() { return null != topLevelHolder; }
551
552 /**
553 * {@inheritDoc}
554 * <p>
555 * If re-layouting on dirty shape mode is enabled (default), see {@link #setRelayoutOnDirtyShapes(boolean)},
556 * this method traverses through all shapes updating all dirty states of all its groups
557 * provoking a re-layout if required.
558 * </p>
559 */
560 @Override
561 protected boolean isShapeDirty() {
562 if( relayoutOnDirtyShapes ) {
563 // Deep dirty state update:
564 // - Ensure all group member's dirty state is updated
565 // - Allowing all group member's validate to function
566 for(final Shape s : shapes) {
567 if( s.isShapeDirty() ) {
569 }
570 }
571 }
572 return super.isShapeDirty();
573 }
574
575 @Override
576 protected void validateImpl(final GL2ES2 gl, final GLProfile glp) {
577 if( isShapeDirty() ) {
578 final boolean needsRMs = hasBorder() && null == border;
579 GraphShape firstGS = null;
580
581 // box has been reset
582 final PMVMatrix4f pmv = new PMVMatrix4f();
583 if( null != layouter ) {
584 if( 0 == shapes.size() ) {
585 box.resize(0, 0, 0);
586 } else {
587 for(final Shape s : shapes) {
588 if( needsRMs && null == firstGS && s instanceof GraphShape ) {
589 firstGS = (GraphShape)s;
590 }
591 layouter.preValidate(s);
592 s.validate(gl, glp);
593 }
594 layouter.layout(this, box, pmv);
595 }
596 } else if( 0 == shapes.size() ) {
597 box.resize(0, 0, 0);
598 } else {
599 final AABBox tsbox = new AABBox();
600 for(final Shape s : shapes) {
601 if( needsRMs && null == firstGS && s instanceof GraphShape ) {
602 firstGS = (GraphShape)s;
603 }
604 s.validate(gl, glp);
605 pmv.pushMv();
606 s.applyMatToMv(pmv);
607 s.getBounds().transform(pmv.getMv(), tsbox);
608 pmv.popMv();
609 box.resize(tsbox);
610 }
611 }
612 if( hasPadding() ) {
613 final Padding p = getPadding();
614 final Vec3f l = box.getLow();
615 final Vec3f h = box.getHigh();
616 box.resize(l.x() - p.left, l.y() - p.bottom, l.z());
617 box.resize(h.x() + p.right, h.y() + p.top, l.z());
619 }
620 final boolean useFixedSize = !FloatUtil.isZero(fixedSize.x()) && !FloatUtil.isZero(fixedSize.y());
621 final boolean useClipping = null != clipFrustum || clipOnBounds;
622 if( useFixedSize || useClipping ) {
623 // final AABBox old = new AABBox(box);
624 final boolean adjustZ = useClipping || ( useFixedSize && Float.isNaN(fixedSize.z()) );
625 final Vec3f lo = box.getLow();
626 if( adjustZ ) {
627 final float oldDepth = box.getDepth();
628 final Vec3f hi;
629 final float zAdjustment = 10f*Scene.DEFAULT_ACTIVE_ZOFFSET_SCALE*Scene.DEFAULT_Z16_EPSILON;
630 lo.add( 0, 0, -(1f*zAdjustment));
631 if( useFixedSize ) {
632 hi = new Vec3f(lo);
633 hi.add(fixedSize.x(), fixedSize.y(), oldDepth+(2f*zAdjustment));
634 } else {
635 hi = box.getHigh();
636 hi.add( 0, 0, oldDepth+(1f*zAdjustment));
637 }
638 box.setSize(lo, hi);
639 } else if( useFixedSize ) {
640 final Vec3f hi = useFixedSize ? new Vec3f(lo) : box.getHigh();
641
642 hi.add(fixedSize.x(), fixedSize.y(), fixedSize.z());
643 box.setSize(lo, hi);
644 }
645 // System.err.println("- was "+old);
646 // System.err.println("- has "+box);
647 }
648
649 if( hasBorder() ) {
650 if( null == border ) {
651 final int firstRMs = null != firstGS ? firstGS.getRenderModes() : 0;
652 final int myRMs = Region.isVBAA(firstRMs) ? Region.VBAA_RENDERING_BIT : 0;
653 border = new Rectangle(myRMs, box, getBorderThickness());
654 } else {
655 border.setVisible(true);
657 }
658 border.setColor(getBorderColor());
659 } else if( null != border ) {
660 border.setVisible(false);
661 }
662 }
663 }
664
665 @Override
666 public boolean contains(final Shape s) {
667 return TreeTool.contains(this, s);
668 }
669 @Override
670 public Shape getShapeByIdx(final int id) {
671 if( 0 > id ) {
672 return null;
673 }
674 return shapes.get(id);
675 }
676 @Override
677 public Shape getShapeByID(final int id) {
678 return TreeTool.getShapeByID(this, id);
679 }
680 @Override
681 public Shape getShapeByName(final String name) {
682 return TreeTool.getShapeByName(this, name);
683 }
684
685 @Override
686 public AABBox getBounds(final PMVMatrix4f pmv, final Shape shape) {
687 pmv.reset();
688 applyMatToMv(pmv);
689 final AABBox res = new AABBox();
690 if( null == shape ) {
691 return res;
692 }
693 TreeTool.forOne(this, pmv, shape, () -> {
694 shape.getBounds().transform(pmv.getMv(), res);
695 });
696 return res;
697 }
698
699 @Override
700 public String getSubString() {
701 return super.getSubString()+", shapes "+shapes.size();
702 }
703}
704
Abstract Outline shape representation define the method an OutlineShape(s) is bound and rendered.
Definition: Region.java:62
static boolean isVBAA(final int renderModes)
Returns true if given renderModes has Region#VBAA_RENDERING_BIT set.
Definition: Region.java:198
final PMVMatrix4f getMatrix()
Borrow the current PMVMatrix4f.
final void setClipFrustum(final Frustum clipFrustum)
Set the optional clipping Frustum, which shall be pre-multiplied with the Mv-matrix or null to disabl...
final Frustum getClipFrustum()
Returns the optional Mv-premultiplied clipping Frustum or null if unused.
Graph based GLRegion Shape.
Definition: GraphShape.java:55
final int getRenderModes()
Returns validated Graph Region render modes, see create(..).
Definition: GraphShape.java:86
Group of Shapes, optionally utilizing a Group.Layout.
Definition: Group.java:61
Group()
Create a group of Shapes w/o Group.Layout.
Definition: Group.java:106
final boolean isOutside(final PMVMatrix4f pmv, final Shape shape)
Returns whether the given Shape is completely outside of this container.
Definition: Group.java:355
Group setFixedSize(final Vec2f v)
Enforce size of this group to given 2 dimensions, adjusting the 3D z-axis getBounds() giving room for...
Definition: Group.java:162
boolean removeShape(final GL2ES2 gl, final RegionRenderer renderer, final Shape s)
Removes given shape with Shape#destroy(GL2ES2, RegionRenderer), if contained.
Definition: Group.java:271
int getShapeCount()
Returns number of Shapes, see getShapes().
Definition: Group.java:216
Vec2f getFixedSize(final Vec2f out)
Returns given Vec2f instance set with 2 dimensions, see setFixedSize(Vec2f).
Definition: Group.java:166
final boolean isTopLevelWidget()
Returns whether setTopLevelWidget(boolean) is enabled or disabled.
Definition: Group.java:550
boolean hasColorChannel()
Returns true if implementation uses an extra color channel or texture which will be modulated with th...
Definition: Group.java:304
Group(final Layout l)
Create a group of Shapes w/ given Group.Layout.
Definition: Group.java:117
final void drawToSelectImpl0(final GL2ES2 gl, final RegionRenderer renderer)
Actual draw implementation, called by drawToSelect(GL2ES2, RegionRenderer).
Definition: Group.java:483
Shape getShapeByIdx(final int id)
Definition: Group.java:670
void addShape(final Shape s)
Adds a Shape.
Definition: Group.java:225
void removeAllShapes(final GL2ES2 gl, final RegionRenderer renderer)
Removes all contained shapes with Shape#destroy(GL2ES2, RegionRenderer).
Definition: Group.java:296
boolean getRelayoutOnDirtyShapes()
Definition: Group.java:515
final boolean isCullingEnabled()
Return whether Project-Modelview (PMv) frustum culling or Group's Modelview (Mv) frustum clipping is ...
Definition: Group.java:352
List< Shape > getRenderedShapes()
Returns added shapes which are rendered and sorted by z-axis in ascending order toward z-near.
Definition: Group.java:222
boolean replaceShape(final Shape remove, final Shape replacement)
Atomic replacement of the given Shape remove with Shape replacement.
Definition: Group.java:237
final boolean isPMvCullingEnabled()
Return whether Project-Modelview (PMv) frustum culling is enabled for this container.
Definition: Group.java:349
List< Shape > getShapes()
Returns added Shapes.
Definition: Group.java:219
Group setClipOnBounds(final boolean v)
Enable Modelview (Mv) Frustum clipping on getBounds() for this group and its shapes as follows.
Definition: Group.java:187
final Group enableTopLevelWidget(final Scene scene)
Enables top-level widget behavior for this group, default is disabled.
Definition: Group.java:535
void validateImpl(final GL2ES2 gl, final GLProfile glp)
Definition: Group.java:576
final boolean isGroup()
Returns true if this shape denotes a Group, otherwise false.
Definition: Group.java:147
Group(final String name, final Layout l, final Vec2f fixedSize, final Shape s)
Create a group of Shapes w/ given Group.Layout and Shape.
Definition: Group.java:131
Layout getLayout()
Return current Group.Layout.
Definition: Group.java:150
void removeShapes(final GL2ES2 gl, final RegionRenderer renderer, final Collection<? extends Shape > shapes)
Removes all given shapes with Shape#destroy(GL2ES2, RegionRenderer).
Definition: Group.java:289
final void setPMvCullingEnabled(final boolean v)
Enable or disable Project-Modelview (PMv) frustum culling per Shape for this container.
Definition: Group.java:346
AABBox getBounds(final PMVMatrix4f pmv, final Shape shape)
Returns AABBox dimension of given Shape from this container's perspective, i.e.
Definition: Group.java:686
void setRelayoutOnDirtyShapes(final boolean v)
Set relayout on dirty shapes mode, defaults to true.
Definition: Group.java:514
boolean isOutside2(final Matrix4f mvCont, final Shape shape, final PMVMatrix4f pmvShape)
Returns whether the given Shape is completely outside of this container.
Definition: Group.java:382
Group setFixedSize(final Vec3f v)
Enforce size of this group for all given 3 dimensions getBounds() without adjusting 3D z-axis like se...
Definition: Group.java:156
boolean getClipOnBounds()
Returns setClipOnBounds(boolean) value.
Definition: Group.java:189
final Group disableTopLevelWidget()
Disables top-level widget behavior as potentially set via enableTopLevelWidget(Scene).
Definition: Group.java:541
Shape removeShape(final Shape s)
Removes given shape, w/o Shape#destroy(GL2ES2, RegionRenderer).
Definition: Group.java:253
void addShapes(final Collection<? extends Shape > shapes)
Definition: Group.java:283
Frustum getClipMvFrustum()
Returns setClipMvFrustum(Frustum) value.
Definition: Group.java:213
Group setLayout(final Layout l)
Set Group.Layout.
Definition: Group.java:153
Group setClipMvFrustum(final Frustum v)
Enable Modelview (Mv) Frustum clipping on explicit given pre-multiplied w/ Mv-matrix clip-box for thi...
Definition: Group.java:211
Shape getShapeByID(final int id)
Definition: Group.java:677
Shape getShapeByName(final String name)
Definition: Group.java:681
boolean contains(final Shape s)
Definition: Group.java:666
void removeShapes(final Collection<? extends Shape > shapes)
Removes all given shapes, w/o Shape#destroy(GL2ES2, RegionRenderer).
Definition: Group.java:264
Vec3f getFixedSize()
Returns borrowed fixed size instance, see setFixedSize(Vec3f) and setFixedSize(Vec2f).
Definition: Group.java:164
void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final Vec4f rgba)
Actual draw implementation, called by draw(GL2ES2, RegionRenderer).
Definition: Group.java:403
boolean isShapeDirty()
Returns the shape's dirty state, see markShapeDirty().
Definition: Group.java:561
void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer)
Custom clear(GL2ES2, RegionRenderer) task, called 1st.
Definition: Group.java:309
void destroyImpl0(final GL2ES2 gl, final RegionRenderer renderer)
Custom destroy(GL2ES2, RegionRenderer) task, called 1st.
Definition: Group.java:324
GraphUI Scene.
Definition: Scene.java:102
static final float DEFAULT_ACTIVE_ZOFFSET_SCALE
Default Z precision scale, i.e.
Definition: Scene.java:114
static final float DEFAULT_Z16_EPSILON
Default Z precision on 16-bit depth buffer using DEFAULT_SCENE_DIST z-position and DEFAULT_ZNEAR.
Definition: Scene.java:112
Generic Shape, potentially using a Graph via GraphShape or other means of representing content.
Definition: Shape.java:87
Padding getPadding()
Returns unscaled Padding of this shape, which is included in unscaled getBounds() and also includes t...
Definition: Shape.java:387
Shape setColor(final float r, final float g, final float b, final float a)
Set base color.
Definition: Shape.java:1389
Shape setName(final String name)
Set a symbolic name for this shape for identification.
Definition: Shape.java:339
Shape()
Create a generic UI Shape.
Definition: Shape.java:320
final Shape setInteractive(final boolean v)
Set whether this shape is interactive in general, i.e.
Definition: Shape.java:1711
void draw(final GL2ES2 gl, final RegionRenderer renderer)
Renders the shape.
Definition: Shape.java:798
boolean hasPadding()
Returns true if setPaddding(Padding) added a non Padding#zeroSize() spacing to this shape.
Definition: Shape.java:390
final Shape setDiscarded(final boolean v)
Set whether this shape is discarded in last draw(GL2ES2, RegionRenderer), i.e.
Definition: Shape.java:1735
final boolean hasBorder()
Returns true if a border has been enabled via setBorder(float, Padding).
Definition: Shape.java:408
final void clear(final GL2ES2 gl, final RegionRenderer renderer)
Clears all data and reset all states as if this instance was newly created.
Definition: Shape.java:425
final float getBorderThickness()
Returns the border thickness, see setBorder(float, Padding).
Definition: Shape.java:411
static Comparator< Shape > ZAscendingComparator
Definition: Shape.java:2287
void setParent(final Group c)
Definition: Shape.java:322
final Vec4f getBorderColor()
Definition: Shape.java:1476
final AABBox getBounds()
Returns the unscaled bounding AABBox for this shape, borrowing internal instance.
Definition: Shape.java:732
final boolean isVisible()
Returns true if this shape is set visible by the user, otherwise false.
Definition: Shape.java:353
void drawToSelect(final GL2ES2 gl, final RegionRenderer renderer)
Experimental selection draw command used by Scene.
Definition: Shape.java:783
final Shape validate(final GL2ES2 gl)
Validates the shape's underlying GLRegion.
Definition: Shape.java:850
final void markShapeDirty()
Marks the shape dirty, causing next draw() to recreate the Graph shape and reset the region.
Definition: Shape.java:688
final void destroy(final GL2ES2 gl, final RegionRenderer renderer)
Destroys all data.
Definition: Shape.java:457
final void applyMatToMv(final PMVMatrix4f pmv)
Applies the internal Matrix4f to the given modelview matrix, i.e.
Definition: Shape.java:908
final Shape setVisible(final boolean v)
Enable (default) or disable this shape's visibility.
Definition: Shape.java:363
final Shape setRotationPivot(final float px, final float py, final float pz)
Set unscaled rotation origin, aka pivot.
Definition: Shape.java:620
GraphUI CSS property Padding, unscaled space belonging to the element and included in the element's s...
Definition: Padding.java:38
final float top
Top value (unscaled)
Definition: Padding.java:43
final float left
Left value (unscaled)
Definition: Padding.java:49
final float right
Right value (unscaled)
Definition: Padding.java:45
final float bottom
Bottom value (unscaled)
Definition: Padding.java:47
A GraphUI rectangle GraphShape.
Definition: Rectangle.java:47
void setBounds(final AABBox abox, final float lineWidth)
Definition: Rectangle.java:132
Basic Float math utility functions.
Definition: FloatUtil.java:83
static boolean isZero(final float a, final float epsilon)
Returns true if value is zero, i.e.
Basic 4x4 float matrix implementation using fields for intensive use-cases (host operations).
Definition: Matrix4f.java:89
2D Vector based upon two float components.
Definition: Vec2f.java:37
void set(final Vec2f o)
this = o, returns this.
Definition: Vec2f.java:73
3D Vector based upon three float components.
Definition: Vec3f.java:37
Vec3f set(final Vec3f o)
this = o, returns this.
Definition: Vec3f.java:79
Vec3f add(final float dx, final float dy, final float dz)
this = this + { dx, dy, dz }, returns this.
Definition: Vec3f.java:239
4D Vector based upon four float components.
Definition: Vec4f.java:37
Axis Aligned Bounding Box.
Definition: AABBox.java:54
final Vec3f getHigh()
Returns the maximum right-top-near (xyz) coordinate.
Definition: AABBox.java:131
final Vec3f getLow()
Returns the minimum left-bottom-far (xyz) coordinate.
Definition: AABBox.java:140
final AABBox setSize(final float[] low, final float[] high)
Set size of the AABBox specifying the coordinates of the low and high.
Definition: AABBox.java:173
final AABBox resize(final AABBox newBox)
Resize the AABBox to encapsulate another AABox.
Definition: AABBox.java:274
final Vec3f getCenter()
Returns computed center of this AABBox of getLow() and getHigh().
Definition: AABBox.java:737
final float getDepth()
Definition: AABBox.java:887
Simple 8-point Vec3f cube compound having z-far <= z-near @endiliteral.
Definition: Cube.java:48
Frustum updateFrustumPlanes(final Frustum frustum)
Calculate the frustum planes using this Cube.
Definition: Cube.java:194
Cube transform(final Matrix4f mat)
Affine 3f-vector transformation of all 8-points with given matrix, Matrix4f#mulVec3f(Vec3f).
Definition: Cube.java:163
Cube set(final AABBox box)
Setting this cube to given AABBox minimum and maximum.
Definition: Cube.java:126
Providing frustum planes derived by different inputs (P*MV, ..) used to classify objects.
Definition: Frustum.java:81
final boolean isOutside(final AABBox box)
Returns whether the given AABBox is completely outside of this frustum.
Definition: Frustum.java:424
PMVMatrix4f implements the basic computer graphics Matrix4f pack using projection (P),...
void reset()
Issues Matrix4f#loadIdentity() on all matrices and resets all internal states.
final Matrix4f getMv()
Returns the modelview matrix (Mv).
final Frustum getFrustum()
Returns the frustum, derived from projection x modelview.
final PMVMatrix4f popMv()
Pop the modelview matrix from its stack.
final PMVMatrix4f pushMv()
Push the modelview matrix to its stack, while preserving its values.
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
Container interface of UI Shapes.
Definition: Container.java:44
Layout for the GraphUI Group, called @ Shape#validate(GL2ES2) or Shape#validate(GLProfile).
Definition: Group.java:63
void preValidate(final Shape s)
Prepare given Shape before validation, e.g.
void layout(final Group g, final AABBox box, final PMVMatrix4f pmv)
Performing the layout of Group#getShapes(), called @ Shape#validate(GL2ES2) or Shape#validate(GLProfi...