JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
Shape.java
Go to the documentation of this file.
1/**
2 * Copyright 2010-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.Comparator;
32import java.util.concurrent.atomic.AtomicInteger;
33
34import com.jogamp.nativewindow.NativeWindowException;
35import com.jogamp.opengl.GL2ES2;
36import com.jogamp.opengl.GLProfile;
37import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
38import com.jogamp.graph.curve.opengl.RegionRenderer;
39import com.jogamp.graph.ui.layout.Padding;
40import com.jogamp.math.FloatUtil;
41import com.jogamp.math.Matrix4f;
42import com.jogamp.math.Quaternion;
43import com.jogamp.math.Recti;
44import com.jogamp.math.Vec2f;
45import com.jogamp.math.Vec3f;
46import com.jogamp.math.Vec4f;
47import com.jogamp.math.geom.AABBox;
48import com.jogamp.math.util.PMVMatrix4f;
49import com.jogamp.newt.event.GestureHandler.GestureEvent;
50import com.jogamp.newt.event.GestureHandler.GestureListener;
51import com.jogamp.newt.event.KeyEvent;
52import com.jogamp.newt.event.KeyListener;
53import com.jogamp.newt.event.MouseAdapter;
54import com.jogamp.newt.event.NEWTEvent;
55import com.jogamp.newt.event.PinchToZoomGesture;
56import com.jogamp.newt.event.MouseEvent;
57import com.jogamp.newt.event.MouseListener;
58
59/**
60 * Generic Shape, potentially using a Graph via {@link GraphShape} or other means of representing content.
61 * <p>
62 * A shape includes the following build-in user-interactions
63 * - drag shape w/ 1-pointer click, see {@link #setDraggable(boolean)}
64 * - resize shape w/ 1-pointer click and drag in 1/4th bottom-left and bottom-right corner, see {@link #setResizable(boolean)}.
65 * </p>
66 * <p>
67 * A shape is expected to have its 0/0 origin in its bottom-left corner, otherwise the drag-zoom sticky-edge will not work as expected.
68 * </p>
69 * <p>
70 * A shape's {@link #getBounds()} includes its optional {@link #getPadding()} and optional {@link #getBorderThickness()}.
71 * </p>
72 * <p>
73 * GraphUI is GPU based and resolution independent.
74 * </p>
75 * <p>
76 * GraphUI is intended to become an immediate- and retained-mode API.
77 * </p>
78 * <p>
79 * Default colors (toggle-off is full color):
80 * - non-toggle: 0.6 * color, static -> 0.6
81 * - pressed: 0.8 * color, static -> 0.5
82 * - toggle-off: 1.0 * color, static -> 0.6
83 * - toggle-on: 0.8 * color
84 * </p>
85 * @see Scene
86 */
87public abstract class Shape {
88 /**
89 * General {@link Shape} visitor
90 */
91 public static interface Visitor1 {
92 /**
93 * Visitor method
94 * @param s the {@link Shape} to process
95 * @return true to signal operation complete and to stop traversal, otherwise false
96 */
97 boolean visit(Shape s);
98 }
99
100 /**
101 * General {@link Shape} visitor
102 */
103 public static interface Visitor2 {
104 /**
105 * Visitor method
106 * @param s the {@link Shape} to process
107 * @param pmv the {@link PMVMatrix4f} setup from the {@link Scene} down to the {@link Shape}
108 * @return true to signal operation complete and to stop traversal, otherwise false
109 */
110 boolean visit(Shape s, final PMVMatrix4f pmv);
111 }
112
113 /**
114 * {@link Shape} move listener
115 */
116 public static interface MoveListener {
117 /**
118 * Move callback
119 * @param s the moved shape
120 * @param origin original position, relative object coordinates to the associated {@link Shape}
121 * @param dest new position, relative object coordinates to the associated {@link Shape}
122 * @param e original Newt {@link MouseEvent}
123 */
124 void run(Shape s, Vec3f origin, Vec3f dest, MouseEvent e);
125 }
126
127 /**
128 * {@link Shape} pointer listener, e.g. for {@link Shape#onClicked(PointerListener)}
129 */
130 public static interface PointerListener {
131 /**
132 * Event callback
133 * @param s the associated {@link Shape} for this event
134 * @param pos relative object coordinates to the associated {@link Shape}
135 * @param e original Newt {@link MouseEvent}
136 */
137 void run(Shape s, final Vec3f pos, MouseEvent e);
138 }
139
140 /**
141 * General {@link Shape} listener action
142 */
143 public static interface Listener {
144 void run(final Shape shape);
145 }
146 /**
147 * {@link Shape} draw listener action returning a boolean value
148 * <p>
149 * If {@link #run(Shape, GL2ES2, RegionRenderer)} returns {@code true},
150 * the listener will be removed at {@link Shape#draw(GL2ES2, RegionRenderer)}
151 * otherwise kept calling.
152 * </p>
153 */
154 public static interface DrawListener {
155 /**
156 * Return {@code true} to remove this {@link DrawListener} at {@link Shape#draw(GL2ES2, RegionRenderer)},
157 * otherwise it is being kept and called.
158 * @param shape The shape
159 * @param gl the current {@link GL2ES2} object
160 * @param renderer the {@link RegionRenderer}
161 */
162 boolean run(final Shape shape, GL2ES2 gl, RegionRenderer renderer);
163 }
164
165 /**
166 * Forward {@link KeyListener}, to be attached to a key event source forwarded to the receiver set at constructor.
167 * <p>
168 * This given receiver {@link Shape} must be {@link #setInteractive(boolean)} to have the events forwarded.
169 * </p>
170 * @see Shape#receiveKeyEvents(Shape)
171 */
172 public static class ForwardKeyListener implements KeyListener {
173 public final Shape receiver;
174 /**
175 * {@link ForwardKeyListener} Constructor
176 * @param receiver the {@link KeyListener} receiver
177 */
179 this.receiver = receiver;
180 }
181
182 private void dispatch(final KeyEvent e) {
183 if( receiver.isInteractive() ) {
184 receiver.dispatchKeyEvent(e);
185 }
186 }
187 @Override
188 public void keyPressed(final KeyEvent e) { dispatch(e); }
189 @Override
190 public void keyReleased(final KeyEvent e) { dispatch(e); }
191 }
192
193 /**
194 * Forward {@link MouseGestureListener}, to be attached to a mouse event source forwarded to the receiver set at constructor.
195 * <p>
196 * This given receiver {@link Shape} must be {@link #setInteractive(boolean)} to have the events forwarded.
197 * </p>
198 * @see Shape#receiveMouseEvents(Shape)
199 */
200 public static class ForwardMouseListener implements MouseGestureListener {
201 public final Shape receiver;
202 /**
203 * {@link ForwardMouseListener} Constructor
204 * @param receiver the {@link MouseGestureListener} receiver
205 */
207 this.receiver = receiver;
208 }
209 private void dispatch(final MouseEvent e) {
210 if( receiver.isInteractive() ) {
211 receiver.dispatchMouseEvent(e);
212 }
213 }
214 @Override
215 public void mouseClicked(final MouseEvent e) { dispatch(e); }
216 @Override
217 public void mouseEntered(final MouseEvent e) { dispatch(e); }
218 @Override
219 public void mouseExited(final MouseEvent e) { dispatch(e); }
220 @Override
221 public void mousePressed(final MouseEvent e) { dispatch(e); }
222 @Override
223 public void mouseReleased(final MouseEvent e) { dispatch(e); }
224 @Override
225 public void mouseMoved(final MouseEvent e) { dispatch(e); }
226 @Override
227 public void mouseDragged(final MouseEvent e) { dispatch(e); }
228 @Override
229 public void mouseWheelMoved(final MouseEvent e) { dispatch(e); }
230 @Override
231 public void gestureDetected(final GestureEvent e) {
232 if( receiver.isInteractive() ) {
233 receiver.dispatchGestureEvent(e);
234 }
235 }
236 };
237
238 protected static final boolean DEBUG_DRAW = false;
239 private static final boolean DEBUG = false;
240
241 private static final int DIRTY_SHAPE = 1 << 0 ;
242 private static final int DIRTY_STATE = 1 << 1 ;
243
244 private volatile Group parent = null;
245 protected final AABBox box = new AABBox();
246
247 private final Vec3f position = new Vec3f();
248 private float zOffset = 0;
249 private final Quaternion rotation = new Quaternion();
250 private Vec3f rotPivot = null;
251 private final Vec3f scale = new Vec3f(1f, 1f, 1f);
252 private final Matrix4f iMat = new Matrix4f();
253 private final Matrix4f tmpMat = new Matrix4f();
254 private volatile boolean iMatIdent = true;
255 private volatile boolean iMatDirty = false;
256
257 private final AtomicInteger dirty = new AtomicInteger(DIRTY_SHAPE | DIRTY_STATE);
258 private final Object dirtySync = new Object();
259
260 /** Default base-color w/o color channel, will be modulated w/ pressed- and toggle color */
261 protected final Vec4f rgbaColor = new Vec4f(0.60f, 0.60f, 0.60f, 1.0f);
262 /** Default pressed color-factor (darker and slightly transparent), modulates base-color. ~0.65 (due to alpha) */
263 protected final Vec4f pressedRGBAModulate = new Vec4f(0.70f, 0.70f, 0.70f, 0.8f);
264 /** Default toggle color-factor (darker), modulates base-color. 0.60 * 0.83 ~= 0.50 */
265 protected final Vec4f toggleOnRGBAModulate = new Vec4f(0.83f, 0.83f, 0.83f, 1.0f);
266 /** Default toggle color-factor (original), modulates base-color. 0.60 * 1.00 ~= 0.60 */
267 protected final Vec4f toggleOffRGBAModulate = new Vec4f(1.00f, 1.00f, 1.00f, 1.0f);
268 /** Default active color-factor (dark), modulates base-color. 0.60 * 0.25 ~= 0.15 */
269 protected final Vec4f activeRGBAModulate = new Vec4f(0.25f, 0.25f, 0.25f, 1.0f);
270 protected boolean activeRGBAModulateOn = false;
271
272 private final Vec4f rgba_tmp = new Vec4f(0, 0, 0, 1);
273 private final Vec4f cWhite = new Vec4f(1, 1, 1, 1);
274
275 private int id = -1;
276 private String name = "noname";
277
278 private static final int IO_VISIBLE = 1 << 0;
279 private static final int IO_INTERACTIVE = 1 << 1;
280 private static final int IO_ACTIVABLE = 1 << 2;
281 private static final int IO_TOGGLEABLE = 1 << 3;
282 private static final int IO_DRAGGABLE = 1 << 4;
283 private static final int IO_RESIZABLE = 1 << 5;
284 private static final int IO_RESIZE_FIXED_RATIO = 1 << 6;
285 private static final int IO_ACTIVE = 1 << 7;
286 private static final int IO_DISCARDED = 1 << 25;
287 private static final int IO_DOWN = 1 << 26;
288 private static final int IO_TOGGLE = 1 << 27;
289 private static final int IO_DRAG_FIRST = 1 << 28;
290 private static final int IO_IN_MOVE = 1 << 29;
291 private static final int IO_IN_RESIZE_BR = 1 << 30;
292 private static final int IO_IN_RESIZE_BL = 1 << 31;
293 private volatile int ioState = IO_DRAGGABLE | IO_RESIZABLE | IO_INTERACTIVE | IO_ACTIVABLE | IO_VISIBLE;
294 private final boolean isIO(final int mask) { return mask == ( ioState & mask ); }
295 private final Shape setIO(final int mask, final boolean v) { if( v ) { ioState |= mask; } else { ioState &= ~mask; } return this; }
296
297 private float borderThickness = 0f;
298 private Padding padding = null;
299 private final Vec4f borderColor = new Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
300 private ArrayList<MouseGestureListener> mouseListeners = new ArrayList<MouseGestureListener>();
301 private ArrayList<KeyListener> keyListeners = new ArrayList<KeyListener>();
302
303 private DrawListener onDrawListener = null;
304 private PointerListener onHoverListener = null;
305 private MoveListener onMoveListener = null;
306 private Listener onToggleListener = null;
307 private ArrayList<Listener> activationListeners = new ArrayList<Listener>();
308 private PointerListener onClickedListener = null;
309
310 private final Vec2f objDraggedFirst = new Vec2f(); // b/c its relative to Shape and we stick to it
311 private final int[] winDraggedLast = { 0, 0 }; // b/c its absolute window pos
312 private static final float resize_sxy_min = 1f/200f; // 1/2% - TODO: Maybe customizable?
313 private static final float resize_section = 1f/5f; // resize action in a corner
314
315 private volatile Tooltip tooltip = null;
316
317 /**
318 * Create a generic UI {@link Shape}
319 */
320 protected Shape() { }
321
322 protected void setParent(final Group c) { parent = c; }
323
324 /**
325 * Returns the last parent container {@link Group} this shape has been added to or {@code null}.
326 * <p>
327 * Since a shape can be added to multiple container (DAG),
328 * usability of this information depends on usage.
329 * </p>
330 */
331 public Group getParent() { return parent; }
332
333 /** Set a symbolic ID for this shape for identification. Default is -1 for noname. */
334 public final Shape setID(final int id) { this.id = id; return this; }
335 /** Return the optional symbolic ID for this shape. */
336 public final int getID() { return this.id; }
337
338 /** Set a symbolic name for this shape for identification. Default is `noname`. */
339 public Shape setName(final String name) { this.name = name; return this; }
340 /** Return the optional symbolic name for this shape, defaults to `noname`. */
341 public final String getName() { return this.name; }
342
343 /** Returns true if this shape denotes a {@link Group}, otherwise false. */
344 public boolean isGroup() { return false; }
345
346 /**
347 * Returns true if this shape is set {@link #setVisible(boolean) visible} by the user, otherwise false. Defaults to true.
348 * <p>
349 * Note that invisible shapes are not considered for picking/activation.
350 * </p>
351 * @see #isInteractive()
352 */
353 public final boolean isVisible() { return isIO(IO_VISIBLE); }
354 /**
355 * Enable (default) or disable this shape's visibility.
356 * <p>
357 * Note that invisible shapes are not considered for picking/activation.
358 * </p>
359 * <p>
360 * This visibility flag is toggled by the user only.
361 * </p>
362 */
363 public final Shape setVisible(final boolean v) { return setIO(IO_VISIBLE, v); }
364
365 /**
366 * Sets the unscaled padding for this shape, which is included in unscaled {@link #getBounds()} and also includes the border. Default is zero.
367 * <p>
368 * Method issues {@link #markShapeDirty()}.
369 * </p>
370 * @param padding distance of shape to the border, i.e. padding
371 * @return this shape for chaining
372 * @see #getPadding()
373 * @see #hasPadding()
374 * @see #markShapeDirty()
375 */
376 public final Shape setPaddding(final Padding padding) {
377 this.padding = padding;
379 return this;
380 }
381
382 /**
383 * Returns unscaled {@link Padding} of this shape, which is included in unscaled {@link #getBounds()} and also includes the border. Default is zero.
384 * @see #setPaddding(Padding)
385 * @see #hasPadding()
386 */
387 public Padding getPadding() { return padding; }
388
389 /** Returns true if {@link #setPaddding(Padding)} added a non {@link Padding#zeroSize()} spacing to this shape. */
390 public boolean hasPadding() { return null != padding && !padding.zeroSize(); }
391
392 /**
393 * Sets the thickness of the border, which is included in {@link #getBounds()} and is outside of {@link #getPadding()}. Default is zero for no border.
394 * <p>
395 * Method issues {@link #markShapeDirty()}.
396 * </p>
397 * @param thickness border thickness, zero for no border
398 * @return this shape for chaining
399 * @see #setBorderColor(Vec4f)
400 * @see #markShapeDirty()
401 */
402 public final Shape setBorder(final float thickness) {
403 borderThickness = Math.max(0f, thickness);
405 return this;
406 }
407 /** Returns true if a border has been enabled via {@link #setBorder(float, Padding)}. */
408 public final boolean hasBorder() { return !FloatUtil.isZero(borderThickness); }
409
410 /** Returns the border thickness, see {@link #setBorder(float, Padding)}. */
411 public final float getBorderThickness() { return borderThickness; }
412
413 /** Perform given {@link Runnable} action synchronized */
414 public final void runSynced(final Runnable action) {
415 synchronized ( dirtySync ) {
416 action.run();
417 }
418 }
419
420 /**
421 * Clears all data and reset all states as if this instance was newly created
422 * @param gl current {@link GL2ES2} instance used to release GPU resources
423 * @param renderer {@link RegionRenderer} used to release GPU resources
424 */
425 public final void clear(final GL2ES2 gl, final RegionRenderer renderer) {
426 synchronized ( dirtySync ) {
427 stopToolTip();
428 clearImpl0(gl, renderer);
429 resetState();
430 }
431 }
432 private final void resetState() {
433 position.set(0f, 0f, 0f);
434 rotation.setIdentity();
435 rotPivot = null;
436 scale.set(1f, 1f, 1f);
437 iMat.loadIdentity();
438 iMatIdent = true;
439 iMatDirty = false;
440 box.reset();
441 mouseListeners.clear();
442 keyListeners.clear();
443 onDrawListener = null;
444 onMoveListener = null;
445 onToggleListener = null;
446 activationListeners.clear();
447 onClickedListener = null;
448 onHoverListener = null;
450 }
451
452 /**
453 * Destroys all data
454 * @param gl current {@link GL2ES2} instance used to release GPU resources
455 * @param renderer {@link RegionRenderer} used to release GPU resources
456 */
457 public final void destroy(final GL2ES2 gl, final RegionRenderer renderer) {
459 destroyImpl0(gl, renderer);
460 resetState();
461 }
462
463 /**
464 * Set a user one-shot initializer callback or custom {@link #draw(GL2ES2, RegionRenderer)} hook.
465 * <p>
466 * {@link #run(Shape, GL2ES2, RegionRenderer)} is called at {@link Shape#draw(GL2ES2, RegionRenderer)}
467 * and if returning {@code true}, the listener will be removed.
468 * Otherwise kept calling.
469 * </p>
470 * <p>
471 * This instrument allows the user either to be signaled when initialization
472 * of this {@link Shape} is completed, or just too hook-up custom {@link #draw(GL2ES2, RegionRenderer)}
473 * actions.
474 * </p>
475 * @param l callback, which shall return true to be removed, i.e. user initialization is done.
476 */
477 public final void onDraw(final DrawListener l) { onDrawListener = l; }
478 /**
479 * Set user callback to be notified when a pointer/mouse is moving over this shape
480 */
481 public final void onHover(final PointerListener l) { onHoverListener = l; }
482 /**
483 * Set user callback to be notified when shape is {@link #move(Vec3f)}'ed.
484 */
485 public final void onMove(final MoveListener l) { onMoveListener = l; }
486 /**
487 * Set user callback to be notified when shape {@link #toggle()}'ed.
488 * <p>
489 * This is usually the case when clicked, see {@link #onClicked(PointerListener)}.
490 * </p>
491 * <p>
492 * Use {@link #isToggleOn()} to retrieve the state.
493 * </p>
494 */
495 public final void onToggle(final Listener l) { onToggleListener = l; }
496 /**
497 * Set user callback to be notified when shape is clicked.
498 * <p>
499 * Usually shape is {@link #toggle()}'ed when clicked, see {@link #onToggle(Listener)}.
500 * However, in case shape is not {@link #isToggleable()} this is the last resort.
501 * </p>
502 */
503 public final void onClicked(final PointerListener l) { onClickedListener = l; }
504
505 /**
506 * Add user callback to be notified when shape is activated (pointer-over and/or click) or de-activated (pointer left).
507 * <p>
508 * Use {@link #isActive()} to retrieve the state.
509 * </p>
510 */
511 public final Shape addActivationListener(final Listener l) {
512 if(l == null) {
513 return this;
514 }
515 @SuppressWarnings("unchecked")
516 final ArrayList<Listener> clonedListeners = (ArrayList<Listener>) activationListeners.clone();
517 clonedListeners.add(l);
518 activationListeners = clonedListeners;
519 return this;
520 }
522 if (l == null) {
523 return this;
524 }
525 @SuppressWarnings("unchecked")
526 final ArrayList<Listener> clonedListeners = (ArrayList<Listener>) activationListeners.clone();
527 clonedListeners.remove(l);
528 activationListeners = clonedListeners;
529 return this;
530 }
531 /**
532 * Dispatch activation event event to this shape
533 * @return true to signal operation complete and to stop traversal, otherwise false
534 */
535 protected final void dispatchActivationEvent(final Shape s) {
536 final int sz = activationListeners.size();
537 for(int i = 0; i < sz; i++ ) {
538 activationListeners.get(i).run(s);
539 }
540 }
541
542 /** Move to scaled position. Position ends up in PMVMatrix4f unmodified. No {@link MoveListener} notification will occur. */
543 public final Shape moveTo(final float tx, final float ty, final float tz) {
544 position.set(tx, ty, tz);
545 iMatDirty = true;
546 return this;
547 }
548
549 /** Move to scaled position. Position ends up in PMVMatrix4f unmodified. No {@link MoveListener} notification will occur. */
550 public final Shape moveTo(final Vec3f t) {
551 position.set(t);
552 iMatDirty = true;
553 return this;
554 }
555
556 /** Move about scaled distance. Position ends up in PMVMatrix4f unmodified. No {@link MoveListener} notification will occur. */
557 public final Shape move(final float dtx, final float dty, final float dtz) {
558 position.add(dtx, dty, dtz);
559 iMatDirty = true;
560 return this;
561 }
562
563 /** Move about scaled distance. Position ends up in PMVMatrix4f unmodified. No {@link MoveListener} notification will occur. */
564 public final Shape move(final Vec3f dt) {
565 position.add(dt);
566 iMatDirty = true;
567 return this;
568 }
569
570 private final Shape moveNotify(final float dtx, final float dty, final float dtz, final MouseEvent e) {
571 forwardMove(position.copy(), position.add(dtx, dty, dtz), e);
572 return this;
573 }
574
575 private final void forwardMove(final Vec3f origin, final Vec3f dest, final MouseEvent e) {
576 if( !origin.isEqual(dest) ) {
577 iMatDirty = true;
578 if( null != onMoveListener ) {
579 onMoveListener.run(this, origin, dest, e);
580 }
581 }
582 }
583
584 /**
585 * Returns position {@link Vec3f} reference, i.e. scaled translation as set via {@link #moveTo(float, float, float) or {@link #move(float, float, float)}}.
586 */
587 public final Vec3f getPosition() {
588 iMatDirty = true;
589 return position;
590 }
591
592 /**
593 * Returns {@link Quaternion} for rotation.
594 */
595 public final Quaternion getRotation() {
596 iMatDirty = true;
597 return rotation;
598 }
599
600 /**
601 * Sets the rotation {@link Quaternion}.
602 * @return this shape for chaining
603 */
604 public final Shape setRotation(final Quaternion q) {
605 rotation.set(q);
606 iMatDirty = true;
607 return this;
608 }
609
610 /**
611 * Return unscaled rotation origin {@link Vec3f} reference, aka pivot. Null if not set via {@link #setRotationPivot(float, float, float)}.
612 * @see #updateMat()
613 */
614 public final Vec3f getRotationPivot() { return rotPivot; }
615
616 /**
617 * Set unscaled rotation origin, aka pivot. Usually the {@link #getBounds()} center and should be set while {@link #validateImpl(GL2ES2, GLProfile)}.
618 * @return this shape for chaining
619 */
620 public final Shape setRotationPivot(final float px, final float py, final float pz) {
621 rotPivot = new Vec3f(px, py, pz);
622 iMatDirty = true;
623 return this;
624 }
625 /**
626 * Set unscaled rotation origin, aka pivot. Usually the {@link #getBounds()} center and should be set while {@link #validateImpl(GL2ES2, GLProfile)}.
627 * @param pivot rotation origin
628 * @return this shape for chaining
629 */
630 public final Shape setRotationPivot(final Vec3f pivot) {
631 rotPivot = new Vec3f(pivot);
632 iMatDirty = true;
633 return this;
634 }
635
636 /**
637 * Set scale factor to given scale.
638 * @see #scale(Vec3f)
639 * @see #getScale()
640 */
641 public final Shape setScale(final Vec3f s) {
642 scale.set(s);
643 iMatDirty = true;
644 return this;
645 }
646 /**
647 * Set scale factor to given scale.
648 * @see #scale(float, float, float)
649 * @see #getScale()
650 */
651 public final Shape setScale(final float sx, final float sy, final float sz) {
652 scale.set(sx, sy, sz);
653 iMatDirty = true;
654 return this;
655 }
656 /**
657 * Multiply current scale factor by given scale.
658 * @see #setScale(Vec3f)
659 * @see #getScale()
660 */
661 public final Shape scale(final Vec3f s) {
662 scale.mul(s);
663 iMatDirty = true;
664 return this;
665 }
666 /**
667 * Multiply current scale factor by given scale.
668 * @see #setScale(float, float, float)
669 * @see #getScale()
670 */
671 public final Shape scale(final float sx, final float sy, final float sz) {
672 scale.mul(sx, sy, sz);
673 iMatDirty = true;
674 return this;
675 }
676 /**
677 * Returns scale {@link Vec3f} reference.
678 * @see #setScale(float, float, float)
679 * @see #scale(float, float, float)
680 * @see #updateMat()
681 */
682 public final Vec3f getScale() { return scale; }
683
684 /**
685 * Marks the shape dirty, causing next {@link #draw(GL2ES2, RegionRenderer) draw()}
686 * to recreate the Graph shape and reset the region.
687 */
688 public final void markShapeDirty() {
689 dirty.updateAndGet((final int pre) -> { return pre | DIRTY_SHAPE; } );
690 }
691
692 /**
693 * Marks the rendering state dirty, causing next {@link #draw(GL2ES2, RegionRenderer) draw()}
694 * to notify the Graph region to reselect shader and repaint potentially used FBOs.
695 */
696 public final void markStateDirty() {
697 dirty.updateAndGet((final int pre) -> { return pre | DIRTY_STATE; } );
698 }
699
700 /** Returns the shape's dirty state, see {@link #markShapeDirty()}. */
701 protected boolean isShapeDirty() {
702 return 0 != ( dirty.get() & DIRTY_SHAPE ) ;
703 }
704 /** Returns the rendering dirty state, see {@link #markStateDirty()}. */
705 protected final boolean isStateDirty() {
706 return 0 != ( dirty.get() & DIRTY_STATE ) ;
707 }
708
709 protected final String getDirtyString() {
710 if( isShapeDirty() && isShapeDirty() ) {
711 return "dirty[shape, state]";
712 } else if( isShapeDirty() ) {
713 return "dirty[shape]";
714 } else if( isStateDirty() ) {
715 return "dirty[state]";
716 } else {
717 return "clean";
718 }
719 }
720
721 /**
722 * Returns the unscaled bounding {@link AABBox} for this shape, borrowing internal instance.
723 *
724 * The returned {@link AABBox} will cover the unscaled shape
725 * as well as its optional {@link #getPadding()} and optional {@link #getBorderThickness()}.
726 *
727 * The returned {@link AABBox} is only valid after an initial call to {@link #draw(GL2ES2, RegionRenderer) draw(..)}
728 * or {@link #validate(GL2ES2)}.
729 *
730 * @see #getBounds(GLProfile)
731 */
732 public final AABBox getBounds() { return box; }
733
734 /**
735 * Returns the scaled width of the bounding {@link AABBox} for this shape.
736 *
737 * The returned width will cover the scaled shape
738 * as well as its optional scaled {@link #getPadding()} and optional scaled {@link #getBorderThickness()}.
739 *
740 * The returned width is only valid after an initial call to {@link #draw(GL2ES2, RegionRenderer) draw(..)}
741 * or {@link #validate(GL2ES2)}.
742 *
743 * @see #getBounds()
744 */
745 public final float getScaledWidth() {
746 return box.getWidth() * getScale().x();
747 }
748
749 /**
750 * Returns the scaled height of the bounding {@link AABBox} for this shape.
751 *
752 * The returned height will cover the scaled shape
753 * as well as its optional scaled {@link #getPadding()} and optional scaled {@link #getBorderThickness()}.
754 *
755 * The returned height is only valid after an initial call to {@link #draw(GL2ES2, RegionRenderer) draw(..)}
756 * or {@link #validate(GL2ES2)}.
757 *
758 * @see #getBounds()
759 */
760 public final float getScaledHeight() {
761 return box.getHeight() * getScale().y();
762 }
763
764 public final float getScaledDepth() {
765 return box.getDepth() * getScale().z();
766 }
767
768 /**
769 * Returns the unscaled bounding {@link AABBox} for this shape.
770 *
771 * This variant differs from {@link #getBounds()} as it
772 * returns a valid {@link AABBox} even before {@link #draw(GL2ES2, RegionRenderer) draw(..)}
773 * and having an OpenGL instance available.
774 *
775 * @see #getBounds()
776 */
777 public final AABBox getBounds(final GLProfile glp) {
778 validate(glp);
779 return box;
780 }
781
782 /** Experimental selection draw command used by {@link Scene}. */
783 public void drawToSelect(final GL2ES2 gl, final RegionRenderer renderer) {
784 synchronized ( dirtySync ) {
785 validate(gl);
786 drawToSelectImpl0(gl, renderer);
787 }
788 }
789
790 /**
791 * Renders the shape.
792 * <p>
793 * {@link #applyMatToMv(PMVMatrix4f)} is expected to be completed beforehand.
794 * </p>
795 * @param gl the current GL object
796 * @param renderer {@link RegionRenderer} which might be used for Graph Curve Rendering, also source of {@link RegionRenderer#getMatrix()} and {@link RegionRenderer#getViewport()}.
797 */
798 public void draw(final GL2ES2 gl, final RegionRenderer renderer) {
799 final boolean isPressed = isPressed(), isToggleOn = isToggleOn();
800 final Vec4f rgba;
801 if( hasColorChannel() ) {
802 if( isPressed ) {
803 rgba = pressedRGBAModulate;
804 } else if( isToggleable() ) {
805 if( isToggleOn ) {
807 } else {
809 }
810 } else if( activeRGBAModulateOn && isActive() ) {
811 rgba = activeRGBAModulate;
812 } else {
813 rgba = cWhite;
814 }
815 } else {
816 rgba = rgba_tmp;
817 if( isPressed ) {
819 } else if( isToggleable() ) {
820 if( isToggleOn ) {
822 } else {
824 }
825 } else if( activeRGBAModulateOn && isActive() ) {
827 } else {
828 rgba.set(rgbaColor);
829 }
830 }
831 synchronized ( dirtySync ) {
832 validate(gl);
833 drawImpl0(gl, renderer, rgba);
834 }
835 if( null != onDrawListener ) {
836 if( onDrawListener.run(this, gl, renderer) ) {
837 onDrawListener = null;
838 }
839 }
840 }
841
842 /**
843 * Validates the shape's underlying {@link GLRegion}.
844 * <p>
845 * If the region is dirty, it gets {@link GLRegion#clear(GL2ES2) cleared} and is reused.
846 * </p>
847 * @param gl current {@link GL2ES2} object
848 * @see #validate(GLProfile)
849 */
850 public final Shape validate(final GL2ES2 gl) {
851 synchronized ( dirtySync ) {
852 if( isShapeDirty() ) {
853 box.reset();
854 }
855 validateImpl(gl, gl.getGLProfile());
856 dirty.set(0);
857 }
858 return this;
859 }
860
861 /**
862 * Validates the shape's underlying {@link GLRegion} w/o a current {@link GL2ES2} object
863 * <p>
864 * If the region is dirty a new region is created
865 * and the old one gets pushed to a dirty-list to get disposed when a GL context is available.
866 * </p>
867 * @see #validate(GL2ES2)
868 */
869 public final Shape validate(final GLProfile glp) {
870 synchronized ( dirtySync ) {
871 if( isShapeDirty() ) {
872 box.reset();
873 }
874 validateImpl(null, glp);
875 dirty.set(0);
876 }
877 return this;
878 }
879
880 /**
881 * Validate the shape via {@link #validate(GL2ES2)} if {@code gl} is not null,
882 * otherwise uses {@link #validate(GLProfile)}.
883 * @see #validate(GL2ES2)
884 * @see #validate(GLProfile)
885 */
886 public final Shape validate(final GL2ES2 gl, final GLProfile glp) {
887 if( null != gl ) {
888 return validate(gl);
889 } else {
890 return validate(glp);
891 }
892 }
893
894 /**
895 * Applies the internal {@link Matrix4f} to the given {@link PMVMatrix4f#getMv() modelview matrix},
896 * i.e. {@code pmv.mulMv( getMat() )}.
897 * <p>
898 * Calls {@link #updateMat()} if dirty.
899 * </p>
900 * In case {@link #isMatIdentity()} is {@code true}, implementation is a no-operation.
901 * </p>
902 * @param pmv the matrix
903 * @see #isMatIdentity()
904 * @see #updateMat()
905 * @see #getMat()
906 * @see PMVMatrix4f#mulMv(Matrix4f)
907 */
908 public final void applyMatToMv(final PMVMatrix4f pmv) {
909 if( iMatDirty ) {
910 updateMat();
911 }
912 if( !iMatIdent ) {
913 pmv.mulMv(iMat);
914 }
915 }
916
917 /**
918 * Returns the internal {@link Matrix4f} reference.
919 * <p>
920 * Calls {@link #updateMat()} if dirty.
921 * </p>
922 * @see #getMat(Matrix4f)
923 * @see #applyMatToMv(PMVMatrix4f)
924 * @see #updateMat()
925 */
926 public final Matrix4f getMat() { if( iMatDirty ) { updateMat(); } return iMat; }
927
928 /**
929 * Returns a copy of the internal {@link Matrix4f} to {@code out}.
930 * <p>
931 * Calls {@link #updateMat()} if dirty.
932 * </p>
933 * @see #getMat()
934 * @see #applyMatToMv(PMVMatrix4f)
935 * @see #updateMat()
936 */
937 public final Matrix4f getMat(final Matrix4f out) { if( iMatDirty ) { updateMat(); } out.load(iMat); return out; }
938
939 /**
940 * Returns true if {@link #getMat()} has not been mutated, i.e. contains identity.
941 * @see #updateMat()
942 */
943 public final boolean isMatIdentity() { return iMatIdent; }
944
945 /**
946 * Updates the internal {@link Matrix4f} with local position, rotation and scale.
947 * <ul>
948 * <li>Scale shape from its center position</li>
949 * <li>Rotate shape around optional scaled pivot, see {@link #setRotationPivot(float[])}), otherwise rotate around its scaled center (default)</li>
950 * </ul>
951 * <p>
952 * Shape's origin should be bottom-left @ 0/0 to have build-in drag-zoom work properly.
953 * </p>
954 * </p>
955 * Sets {@link #isMatIdentity()} to {@code true} if neither position, scale or rotate is performed, otherwise to {@code false}.
956 * </p>
957 * <p>
958 * Called by {@link #applyMatToMv(PMVMatrix4f)}, {@link #getMat()} and {@link #getMat(Matrix4f)} if internal matrix is dirty.
959 * </p>
960 * <p>
961 * After any mutating operations, .e.g {@link #move(float, float, float)} etc, the internal matrix is marked dirty.
962 * </p>
963 * @see #isMatIdentity()
964 * @see #getMat()
965 * @see #getPosition()
966 * @see #getScale()
967 * @see #getRotation()
968 * @see #getRotationPivot()
969 * @see #applyMatToMv(PMVMatrix4f)
970 */
971 public final void updateMat() {
972 final boolean hasPos = !position.isZero();
973 final boolean hasScale = !scale.isEqual(Vec3f.ONE);
974 final boolean hasRotate = !rotation.isIdentity();
975 final boolean hasRotPivot = null != rotPivot;
976 final Vec3f ctr = box.getCenter();
977 final boolean sameScaleRotatePivot = hasScale && hasRotate && ( !hasRotPivot || rotPivot.isEqual(ctr) );
978
979 if( sameScaleRotatePivot ) {
980 iMatIdent = false;
981 iMat.setToTranslation(position); // identity + translate, scaled
982 // Scale shape from its center position and rotate around its center
983 iMat.translate(ctr.x()*scale.x(), ctr.y()*scale.y(), ctr.z()*scale.z(), tmpMat); // add-back center, scaled
984 iMat.rotate(rotation, tmpMat);
985 iMat.scale(scale.x(), scale.y(), scale.z(), tmpMat);
986 iMat.translate(-ctr.x(), -ctr.y(), -ctr.z(), tmpMat); // move to center
987 } else if( hasRotate || hasScale ) {
988 iMatIdent = false;
989 iMat.setToTranslation(position); // identity + translate, scaled
990 if( hasRotate ) {
991 if( hasRotPivot ) {
992 // Rotate shape around its scaled pivot
993 iMat.translate(rotPivot.x()*scale.x(), rotPivot.y()*scale.y(), rotPivot.z()*scale.z(), tmpMat); // pivot back from rot-pivot, scaled
994 iMat.rotate(rotation, tmpMat);
995 iMat.translate(-rotPivot.x()*scale.x(), -rotPivot.y()*scale.y(), -rotPivot.z()*scale.z(), tmpMat); // pivot to rot-pivot, scaled
996 } else {
997 // Rotate shape around its scaled center
998 iMat.translate(ctr.x()*scale.x(), ctr.y()*scale.y(), ctr.z()*scale.z(), tmpMat); // pivot back from center-pivot, scaled
999 iMat.rotate(rotation, tmpMat);
1000 iMat.translate(-ctr.x()*scale.x(), -ctr.y()*scale.y(), -ctr.z()*scale.z(), tmpMat); // pivot to center-pivot, scaled
1001 }
1002 }
1003 if( hasScale ) {
1004 // Scale shape from its center position
1005 iMat.translate(ctr.x()*scale.x(), ctr.y()*scale.y(), ctr.z()*scale.z(), tmpMat); // add-back center, scaled
1006 iMat.scale(scale.x(), scale.y(), scale.z(), tmpMat);
1007 iMat.translate(-ctr.x(), -ctr.y(), -ctr.z(), tmpMat); // move to center
1008 }
1009 } else if( hasPos ) {
1010 iMatIdent = false;
1011 iMat.setToTranslation(position); // identity + translate, scaled
1012
1013 } else {
1014 iMatIdent = true;
1015 iMat.loadIdentity();
1016 }
1017 iMatDirty = false;
1018 }
1019
1020 /**
1021 * {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) Setup} the given {@link PMVMatrix4f}
1022 * and apply this shape's {@link #applyMatToMv(PMVMatrix4f) transformation}.
1023 * </p>
1024 * @param pmvMatrixSetup {@link Scene.PMVMatrixSetup} to {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} given {@link PMVMatrix4f} {@code pmv}.
1025 * @param viewport used viewport for {@link PMVMatrix4f#mapObjToWin(Vec3f, Recti, Vec3f)}
1026 * @param pmv a new {@link PMVMatrix4f} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) be setup},
1027 * {@link #applyMatToMv(PMVMatrix4f) shape-transformed} and can be reused by the caller.
1028 * @return the given {@link PMVMatrix4f} for chaining
1029 * @see Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti)
1030 * @see #applyMatToMv(PMVMatrix4f)
1031 * @see #setPMVMatrix(Scene, PMVMatrix4f)
1032 */
1033 public final PMVMatrix4f setPMVMatrix(final Scene.PMVMatrixSetup pmvMatrixSetup, final Recti viewport, final PMVMatrix4f pmv) {
1034 pmvMatrixSetup.set(pmv, viewport);
1035 applyMatToMv(pmv);
1036 return pmv;
1037 }
1038
1039 /**
1040 * {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) Setup} the given {@link PMVMatrix4f}
1041 * and apply this shape's {@link #applyMatToMv(PMVMatrix4f) transformation}.
1042 * </p>
1043 * @param scene {@link Scene} to retrieve {@link Scene.PMVMatrixSetup} and the viewport.
1044 * @param pmv a new {@link PMVMatrix4f} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) be setup},
1045 * {@link #applyMatToMv(PMVMatrix4f) shape-transformed} and can be reused by the caller.
1046 * @return the given {@link PMVMatrix4f} for chaining
1047 * @see Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti)
1048 * @see #applyMatToMv(PMVMatrix4f)
1049 * @see #setPMVMatrix(com.jogamp.graph.ui.Scene.PMVMatrixSetup, Recti, PMVMatrix4f)
1050 */
1051 public final PMVMatrix4f setPMVMatrix(final Scene scene, final PMVMatrix4f pmv) {
1052 return setPMVMatrix(scene.getPMVMatrixSetup(), scene.getViewport(), pmv);
1053 }
1054
1055 /**
1056 * Retrieve surface (view) port of this shape, i.e. lower x/y position and size.
1057 * <p>
1058 * The given {@link PMVMatrix4f} has to be setup properly for this object,
1059 * i.e. its {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} for the surrounding scene
1060 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}. See {@link #setPMVMatrix(Scene, PMVMatrix4f)}.
1061 * </p>
1062 * @param pmv well formed {@link PMVMatrix4f}, e.g. could have been setup via {@link Shape#setPMVMatrix(Scene, PMVMatrix4f)}.
1063 * @param viewport the int[4] viewport
1064 * @param surfacePort Recti target surface port
1065 * @return given Recti {@code surfacePort} for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)} operation, otherwise {@code null}
1066 */
1067 public final Recti getSurfacePort(final PMVMatrix4f pmv, final Recti viewport, final Recti surfacePort) {
1068 final Vec3f winCoordHigh = new Vec3f();
1069 final Vec3f winCoordLow = new Vec3f();
1070 final Vec3f high = box.getHigh();
1071 final Vec3f low = box.getLow();
1072
1073 final Matrix4f matPMv = pmv.getPMv();
1074 if( Matrix4f.mapObjToWin(high, matPMv, viewport, winCoordHigh) ) {
1075 if( Matrix4f.mapObjToWin(low, matPMv, viewport, winCoordLow) ) {
1076 surfacePort.setX( (int)Math.abs( winCoordLow.x() ) );
1077 surfacePort.setY( (int)Math.abs( winCoordLow.y() ) );
1078 surfacePort.setWidth( (int)Math.abs( winCoordHigh.x() - winCoordLow.x() ) );
1079 surfacePort.setHeight( (int)Math.abs( winCoordHigh.y() - winCoordLow.y() ) );
1080 return surfacePort;
1081 }
1082 }
1083 return null;
1084 }
1085
1086 /**
1087 * Retrieve surface (view) size in pixels of this shape.
1088 * <p>
1089 * The given {@link PMVMatrix4f} has to be setup properly for this object,
1090 * i.e. its {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} for the surrounding scene
1091 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}. See {@link #setPMVMatrix(Scene, PMVMatrix4f)}.
1092 * </p>
1093 * @param pmv well formed {@link PMVMatrix4f}, e.g. could have been setup via {@link Shape#setPMVMatrix(Scene, PMVMatrix4f)}.
1094 * @param viewport the int[4] viewport
1095 * @param surfaceSize int[2] target surface size
1096 * @return given int[2] {@code surfaceSize} in pixels for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)} operation, otherwise {@code null}
1097 * @see #getSurfaceSize(com.jogamp.graph.ui.Scene.PMVMatrixSetup, Recti, PMVMatrix4f, int[])
1098 * @see #getSurfaceSize(Scene, PMVMatrix4f, int[])
1099 */
1100 public final int[/*2*/] getSurfaceSize(final PMVMatrix4f pmv, final Recti viewport, final int[/*2*/] surfaceSize) {
1101 // System.err.println("Shape::getSurfaceSize.VP "+viewport[0]+"/"+viewport[1]+" "+viewport[2]+"x"+viewport[3]);
1102 final Vec3f winCoordHigh = new Vec3f();
1103 final Vec3f winCoordLow = new Vec3f();
1104 final Vec3f high = box.getHigh();
1105 final Vec3f low = box.getLow();
1106
1107 final Matrix4f matPMv = pmv.getPMv();
1108 if( Matrix4f.mapObjToWin(high, matPMv, viewport, winCoordHigh) ) {
1109 if( Matrix4f.mapObjToWin(low, matPMv, viewport, winCoordLow) ) {
1110 surfaceSize[0] = (int)Math.abs(winCoordHigh.x() - winCoordLow.x());
1111 surfaceSize[1] = (int)Math.abs(winCoordHigh.y() - winCoordLow.y());
1112 return surfaceSize;
1113 }
1114 }
1115 return null;
1116 }
1117
1118 /**
1119 * Retrieve surface (view) size in pixels of this shape.
1120 * <p>
1121 * The given {@link PMVMatrix4f} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} properly for this shape
1122 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}.
1123 * </p>
1124 * @param pmvMatrixSetup {@link Scene.PMVMatrixSetup} to {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} given {@link PMVMatrix4f} {@code pmv}.
1125 * @param viewport used viewport for {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)}
1126 * @param pmv a new {@link PMVMatrix4f} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) be setup},
1127 * {@link #applyMatToMv(PMVMatrix4f) shape-transformed} and can be reused by the caller.
1128 * @param surfaceSize int[2] target surface size
1129 * @return given int[2] {@code surfaceSize} in pixels for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)} operation, otherwise {@code null}
1130 * @see #getSurfaceSize(PMVMatrix4f, Recti, int[])
1131 * @see #getSurfaceSize(Scene, PMVMatrix4f, int[])
1132 */
1133 public final int[/*2*/] getSurfaceSize(final Scene.PMVMatrixSetup pmvMatrixSetup, final Recti viewport, final PMVMatrix4f pmv, final int[/*2*/] surfaceSize) {
1134 return getSurfaceSize(setPMVMatrix(pmvMatrixSetup, viewport, pmv), viewport, surfaceSize);
1135 }
1136
1137 /**
1138 * Retrieve surface (view) size in pixels of this shape.
1139 * <p>
1140 * The given {@link PMVMatrix4f} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} properly for this shape
1141 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}.
1142 * </p>
1143 * @param scene {@link Scene} to retrieve {@link Scene.PMVMatrixSetup} and the viewport.
1144 * @param pmv a new {@link PMVMatrix4f} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) be setup},
1145 * {@link #applyMatToMv(PMVMatrix4f) shape-transformed} and can be reused by the caller.
1146 * @param surfaceSize int[2] target surface size
1147 * @return given int[2] {@code surfaceSize} in pixels for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)} operation, otherwise {@code null}
1148 * @see #getSurfaceSize(PMVMatrix4f, Recti, int[])
1149 * @see #getSurfaceSize(com.jogamp.graph.ui.Scene.PMVMatrixSetup, Recti, PMVMatrix4f, int[])
1150 */
1151 public final int[/*2*/] getSurfaceSize(final Scene scene, final PMVMatrix4f pmv, final int[/*2*/] surfaceSize) {
1152 return getSurfaceSize(scene.getPMVMatrixSetup(), scene.getViewport(), pmv, surfaceSize);
1153 }
1154
1155 /**
1156 * Retrieve pixel per scaled shape-coordinate unit, i.e. [px]/[obj].
1157 * @param shapeSizePx int[2] shape size in pixel as retrieved via e.g. {@link #getSurfaceSize(com.jogamp.graph.ui.Scene.PMVMatrixSetup, Recti, PMVMatrix4f, int[])}
1158 * @param pixPerShape float[2] pixel scaled per shape-coordinate unit result storage
1159 * @return given float[2] {@code pixPerShape}
1160 * @see #getPixelPerShapeUnit(Scene, PMVMatrix4f, float[])
1161 * @see #getSurfaceSize(com.jogamp.graph.ui.Scene.PMVMatrixSetup, Recti, PMVMatrix4f, int[])
1162 * @see #getScaledWidth()
1163 * @see #getScaledHeight()
1164 */
1165 public final float[] getPixelPerShapeUnit(final int[] shapeSizePx, final float[] pixPerShape) {
1166 pixPerShape[0] = shapeSizePx[0] / getScaledWidth();
1167 pixPerShape[0] = shapeSizePx[1] / getScaledHeight();
1168 return pixPerShape;
1169 }
1170
1171 /**
1172 * Retrieve pixel per scaled shape-coordinate unit, i.e. [px]/[obj].
1173 * <p>
1174 * The given {@link PMVMatrix4f} has to be setup properly for this object,
1175 * i.e. its {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} for the surrounding scene
1176 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}. See {@link #setPMVMatrix(Scene, PMVMatrix4f)}.
1177 * </p>
1178 * @param pmv well formed {@link PMVMatrix4f}, e.g. could have been setup via {@link Shape#setPMVMatrix(Scene, PMVMatrix4f)}.
1179 * @param viewport the int[4] viewport
1180 * @param pixPerShape float[2] pixel per scaled shape-coordinate unit result storage
1181 * @return given float[2] {@code pixPerShape} for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)} operation, otherwise {@code null}
1182 * @see #getPixelPerShapeUnit(int[], float[])
1183 * @see #getSurfaceSize(Scene, PMVMatrix4f, int[])
1184 * @see #getScaledWidth()
1185 * @see #getScaledHeight()
1186 */
1187 public final float[] getPixelPerShapeUnit(final PMVMatrix4f pmv, final Recti viewport, final float[] pixPerShape) {
1188 final int[] shapeSizePx = new int[2];
1189 if( null != getSurfaceSize(pmv, viewport, shapeSizePx) ) {
1190 return getPixelPerShapeUnit(shapeSizePx, pixPerShape);
1191 } else {
1192 return null;
1193 }
1194 }
1195
1196 /**
1197 * Retrieve pixel per scaled shape-coordinate unit, i.e. [px]/[obj].
1198 * <p>
1199 * The given {@link PMVMatrix4f} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} properly for this shape
1200 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}.
1201 * </p>
1202 * @param scene {@link Scene} to retrieve {@link Scene.PMVMatrixSetup} and the viewport.
1203 * @param pmv a new {@link PMVMatrix4f} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) be setup},
1204 * {@link #applyMatToMv(PMVMatrix4f) shape-transformed} and can be reused by the caller.
1205 * @param pixPerShape float[2] pixel per scaled shape-coordinate unit result storage
1206 * @return given float[2] {@code pixPerShape} for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)} operation, otherwise {@code null}
1207 * @see #getPixelPerShapeUnit(int[], float[])
1208 * @see #getSurfaceSize(Scene, PMVMatrix4f, int[])
1209 * @see #getScaledWidth()
1210 * @see #getScaledHeight()
1211 */
1212 public final float[] getPixelPerShapeUnit(final Scene scene, final PMVMatrix4f pmv, final float[] pixPerShape) {
1213 final int[] shapeSizePx = new int[2];
1214 if( null != getSurfaceSize(scene, pmv, shapeSizePx) ) {
1215 return getPixelPerShapeUnit(shapeSizePx, pixPerShape);
1216 } else {
1217 return null;
1218 }
1219 }
1220
1221 /**
1222 * Map given object coordinate relative to this shape to window coordinates.
1223 * <p>
1224 * The given {@link PMVMatrix4f} has to be setup properly for this object,
1225 * i.e. its {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} for the surrounding scene
1226 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}. See {@link #setPMVMatrix(Scene, PMVMatrix4f)}.
1227 * </p>
1228 * @param pmv well formed {@link PMVMatrix4f}, e.g. could have been setup via {@link Shape#setPMVMatrix(Scene, PMVMatrix4f)}.
1229 * @param viewport the viewport
1230 * @param objPos object position relative to this shape's center
1231 * @param glWinPos int[2] target window position of objPos relative to this shape
1232 * @return given int[2] {@code glWinPos} for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)} operation, otherwise {@code null}
1233 * @see #shapeToWinCoord(com.jogamp.graph.ui.Scene.PMVMatrixSetup, Recti, float[], PMVMatrix4f, int[])
1234 * @see #shapeToWinCoord(Scene, float[], PMVMatrix4f, int[])
1235 */
1236 public final int[/*2*/] shapeToWinCoord(final PMVMatrix4f pmv, final Recti viewport, final Vec3f objPos, final int[/*2*/] glWinPos) {
1237 // System.err.println("Shape::objToWinCoordgetSurfaceSize.VP "+viewport[0]+"/"+viewport[1]+" "+viewport[2]+"x"+viewport[3]);
1238 final Vec3f winCoord = new Vec3f();
1239
1240 if( pmv.mapObjToWin(objPos, viewport, winCoord) ) {
1241 glWinPos[0] = (int)(winCoord.x());
1242 glWinPos[1] = (int)(winCoord.y());
1243 return glWinPos;
1244 }
1245 return null;
1246 }
1247
1248 /**
1249 * Map given object coordinate relative to this shape to window coordinates.
1250 * <p>
1251 * The given {@link PMVMatrix4f} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} properly for this shape
1252 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}.
1253 * </p>
1254 * @param pmvMatrixSetup {@link Scene.PMVMatrixSetup} to {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} given {@link PMVMatrix4f} {@code pmv}.
1255 * @param viewport used viewport for {@link PMVMatrix4f#mapObjToWin(Vec3f, Recti, Vec3f)}
1256 * @param objPos object position relative to this shape's center
1257 * @param pmv a new {@link PMVMatrix4f} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) be setup},
1258 * {@link #applyMatToMv(PMVMatrix4f) shape-transformed} and can be reused by the caller.
1259 * @param glWinPos int[2] target window position of objPos relative to this shape
1260 * @return given int[2] {@code glWinPos} for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)} operation, otherwise {@code null}
1261 * @see #shapeToWinCoord(PMVMatrix4f, Recti, float[], int[])
1262 * @see #shapeToWinCoord(Scene, float[], PMVMatrix4f, int[])
1263 */
1264 public final int[/*2*/] shapeToWinCoord(final Scene.PMVMatrixSetup pmvMatrixSetup, final Recti viewport, final Vec3f objPos, final PMVMatrix4f pmv, final int[/*2*/] glWinPos) {
1265 return this.shapeToWinCoord(setPMVMatrix(pmvMatrixSetup, viewport, pmv), viewport, objPos, glWinPos);
1266 }
1267
1268 /**
1269 * Map given object coordinate relative to this shape to window coordinates.
1270 * <p>
1271 * The given {@link PMVMatrix4f} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} properly for this shape
1272 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}.
1273 * </p>
1274 * @param scene {@link Scene} to retrieve {@link Scene.PMVMatrixSetup} and the viewport.
1275 * @param objPos object position relative to this shape's center
1276 * @param pmv a new {@link PMVMatrix4f} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) be setup},
1277 * {@link #applyMatToMv(PMVMatrix4f) shape-transformed} and can be reused by the caller.
1278 * @param glWinPos int[2] target window position of objPos relative to this shape
1279 * @return given int[2] {@code glWinPos} for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)} operation, otherwise {@code null}
1280 * @see #shapeToWinCoord(PMVMatrix4f, Recti, float[], int[])
1281 * @see #shapeToWinCoord(com.jogamp.graph.ui.Scene.PMVMatrixSetup, Recti, float[], PMVMatrix4f, int[])
1282 */
1283 public final int[/*2*/] shapeToWinCoord(final Scene scene, final Vec3f objPos, final PMVMatrix4f pmv, final int[/*2*/] glWinPos) {
1284 return this.shapeToWinCoord(scene.getPMVMatrixSetup(), scene.getViewport(), objPos, pmv, glWinPos);
1285 }
1286
1287 /**
1288 * Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate.
1289 * <p>
1290 * The given {@link PMVMatrix4f} has to be setup properly for this object,
1291 * i.e. its {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} for the surrounding scene
1292 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}. See {@link #setPMVMatrix(Scene, PMVMatrix4f)}.
1293 * </p>
1294 * @param pmv well formed {@link PMVMatrix4f}, e.g. could have been setup via {@link Shape#setPMVMatrix(Scene, PMVMatrix4f)}.
1295 * @param viewport the Rect4i viewport
1296 * @param glWinX in GL window coordinates, origin bottom-left
1297 * @param glWinY in GL window coordinates, origin bottom-left
1298 * @param objPos target object position of glWinX/glWinY relative to this shape
1299 * @return given {@code objPos} for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)}
1300 * and {@link Matrix4f#mapWinToObj(float, float, float, float, Matrix4f, Recti, Vec3f, Vec3f) gluUnProject(..)}
1301 * operation, otherwise {@code null}
1302 * @see #winToShapeCoord(com.jogamp.graph.ui.Scene.PMVMatrixSetup, Recti, int, int, PMVMatrix4f, float[])
1303 * @see #winToShapeCoord(Scene, int, int, PMVMatrix4f, float[])
1304 */
1305 public final Vec3f winToShapeCoord(final PMVMatrix4f pmv, final Recti viewport, final int glWinX, final int glWinY, final Vec3f objPos) {
1306 final Vec3f ctr = box.getCenter();
1307
1308 if( Matrix4f.mapObjToWin(ctr, pmv.getPMv(), viewport, objPos) ) {
1309 final float winZ = objPos.z();
1310 if( Matrix4f.mapWinToObj(glWinX, glWinY, winZ, pmv.getPMvi(), viewport, objPos) ) {
1311 return objPos;
1312 }
1313 }
1314 return null;
1315 }
1316
1317 /**
1318 * Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate.
1319 * <p>
1320 * The given {@link PMVMatrix4f} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} properly for this shape
1321 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}.
1322 * </p>
1323 * @param pmvMatrixSetup {@link Scene.PMVMatrixSetup} to {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} given {@link PMVMatrix4f} {@code pmv}.
1324 * @param viewport used viewport for {@link PMVMatrix4f#mapWinToObj(float, float, float, Recti, Vec3f)}
1325 * @param glWinX in GL window coordinates, origin bottom-left
1326 * @param glWinY in GL window coordinates, origin bottom-left
1327 * @param pmv a new {@link PMVMatrix4f} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) be setup},
1328 * {@link #applyMatToMv(PMVMatrix4f) shape-transformed} and can be reused by the caller.
1329 * @param objPos target object position of glWinX/glWinY relative to this shape
1330 * @return given {@code objPos} for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)}
1331 * and {@link Matrix4f#mapWinToObj(float, float, float, float, Matrix4f, Recti, Vec3f, Vec3f) gluUnProject(..)}
1332 * operation, otherwise {@code null}
1333 * @see #winToShapeCoord(PMVMatrix4f, Recti, int, int, float[])
1334 * @see #winToShapeCoord(Scene, int, int, PMVMatrix4f, float[])
1335 */
1336 public final Vec3f winToShapeCoord(final Scene.PMVMatrixSetup pmvMatrixSetup, final Recti viewport, final int glWinX, final int glWinY, final PMVMatrix4f pmv, final Vec3f objPos) {
1337 return this.winToShapeCoord(setPMVMatrix(pmvMatrixSetup, viewport, pmv), viewport, glWinX, glWinY, objPos);
1338 }
1339
1340 /**
1341 * Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate.
1342 * <p>
1343 * The given {@link PMVMatrix4f} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) setup} properly for this shape
1344 * including this shape's {@link #applyMatToMv(PMVMatrix4f)}.
1345 * </p>
1346 * @param scene {@link Scene} to retrieve {@link Scene.PMVMatrixSetup} and the viewport.
1347 * @param glWinX in GL window coordinates, origin bottom-left
1348 * @param glWinY in GL window coordinates, origin bottom-left
1349 * @param pmv a new {@link PMVMatrix4f} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix4f, Recti) be setup},
1350 * {@link #applyMatToMv(PMVMatrix4f) shape-transformed} and can be reused by the caller.
1351 * @param objPos target object position of glWinX/glWinY relative to this shape
1352 * @return given {@code objPos} for successful {@link Matrix4f#mapObjToWin(Vec3f, Matrix4f, Recti, Vec3f) gluProject(..)}
1353 * and {@link Matrix4f#mapWinToObj(float, float, float, float, Matrix4f, Recti, Vec3f, Vec3f) gluUnProject(..)}
1354 * operation, otherwise {@code null}
1355 * @see #winToShapeCoord(PMVMatrix4f, Recti, int, int, float[])
1356 * @see #winToShapeCoord(com.jogamp.graph.ui.Scene.PMVMatrixSetup, Recti, int, int, PMVMatrix4f, float[])
1357 */
1358 public final Vec3f winToShapeCoord(final Scene scene, final int glWinX, final int glWinY, final PMVMatrix4f pmv, final Vec3f objPos) {
1359 return this.winToShapeCoord(scene.getPMVMatrixSetup(), scene.getViewport(), glWinX, glWinY, pmv, objPos);
1360 }
1361
1362 /**
1363 * Returns base-color w/o color channel, will be modulated w/ {@link #getPressedColorMod()},
1364 * {@link #getToggleOnColorMod()}, {@link #getToggleOffColorMod()} and {@link #getActiveColorMod()}.
1365 **/
1366 public final Vec4f getColor() { return rgbaColor; }
1367 /** Returns modulation color when {@link #isPressed()}. */
1369 /** Returns modulation color when {@link #isToggleOn()}. */
1371 /** Returns modulation color when not {@link #isToggleOn()}. */
1373 /** Returns modulation color when {@link #isActive()}. */
1374 public final Vec4f getActiveColorMod() { return activeRGBAModulate; }
1375
1376 /**
1377 * Set base color.
1378 * <p>
1379 * Base color w/o color channel, will be modulated w/ pressed- and toggle color
1380 * </p>
1381 * <p>
1382 * Default RGBA value is 0.60f, 0.60f, 0.60f, 1.0f
1383 * </p>
1384 * <p>
1385 * Method issues {@link #markShapeDirty()}.
1386 * </p>
1387 * @see #markShapeDirty()
1388 */
1389 public Shape setColor(final float r, final float g, final float b, final float a) {
1390 this.rgbaColor.set(r, g, b, a);
1392 return this;
1393 }
1394
1395 /**
1396 * Set base color.
1397 * <p>
1398 * Default base-color w/o color channel, will be modulated w/ pressed- and toggle color
1399 * </p>
1400 * <p>
1401 * Default RGBA value is 0.60f, 0.60f, 0.60f, 1.0f
1402 * </p>
1403 * <p>
1404 * Method issues {@link #markShapeDirty()}.
1405 * </p>
1406 * @see #markShapeDirty()
1407 */
1408 public Shape setColor(final Vec4f c) {
1409 this.rgbaColor.set(c);
1411 return this;
1412 }
1413
1414 /**
1415 * Set pressed color, modulating {@link #getColor()} if {@link #isPressed()}.
1416 * <p>
1417 * Default pressed color, modulation -factor w/o color channel, modulated base-color. ~0.65 (due to alpha)
1418 * </p>
1419 * <p>
1420 * Default RGBA value is 0.70f, 0.70f, 0.70f, 0.8f
1421 * </p>
1422 */
1423 public Shape setPressedColorMod(final float r, final float g, final float b, final float a) {
1424 this.pressedRGBAModulate.set(r, g, b, a);
1425 return this;
1426 }
1427
1428 /**
1429 * Set toggle-on color, modulating {@link #getColor()} if {@link #isToggleOn()} and {@link #setToggleable(boolean)}
1430 * <p>
1431 * Default toggle-on color-factor w/o color channel, modulated base-color. 0.60 * 0.83 ~= 0.50
1432 * </p>
1433 * <p>
1434 * Default RGBA value is 0.83f, 0.83f, 0.83f, 1.0f
1435 * </p>
1436 */
1437 public final Shape setToggleOnColorMod(final float r, final float g, final float b, final float a) {
1438 this.toggleOnRGBAModulate.set(r, g, b, a);
1439 return this;
1440 }
1441
1442 /**
1443 * Set toggle-off color, modulating {@link #getColor()} if !{@link #isToggleOn()} and {@link #setToggleable(boolean)}
1444 * <p>
1445 * Default toggle-off color-factor w/o color channel, modulated base-color. 0.60 * 1.00 ~= 0.60
1446 * </p>
1447 * <p>
1448 * Default RGBA value is 1.00f, 1.00f, 1.00f, 1.0f
1449 * </p>
1450 */
1451 public final Shape setToggleOffColorMod(final float r, final float g, final float b, final float a) {
1452 this.toggleOffRGBAModulate.set(r, g, b, a);
1453 return this;
1454 }
1455
1456 /**
1457 * Enable active color, modulation {@link #getColor()} if {@link #isActive()} with passing {@code c != null},
1458 * disable with passing {@code c == null}.
1459 * <p>
1460 * Default active color-factor w/o color channel, modulated base-color. 0.60 * 0.25 ~= 0.15
1461 * </p>
1462 * <p>
1463 * Default is disabled.
1464 * </p>
1465 */
1466 public final Shape setActiveColorMod(final Vec4f c) {
1467 if( null == c ) {
1468 activeRGBAModulateOn = false;
1469 } else {
1470 activeRGBAModulateOn = true;
1471 this.activeRGBAModulate.set(c);
1472 }
1473 return this;
1474 }
1475
1476 public final Vec4f getBorderColor() { return borderColor; }
1477
1478 /**
1479 * Set border color.
1480 * <p>
1481 * Default RGBA value is 0.00f, 0.00f, 0.00f, 1.0f
1482 * </p>
1483 * <p>
1484 * Method issues {@link #markShapeDirty()}.
1485 * </p>
1486 * @see #setBorder(float)
1487 * @see #markShapeDirty()
1488 */
1489 public final Shape setBorderColor(final float r, final float g, final float b, final float a) {
1490 this.borderColor.set(r, g, b, a);
1492 return this;
1493 }
1494
1495 /**
1496 * Set border color.
1497 * <p>
1498 * Default RGBA value is 0.00f, 0.00f, 0.00f, 1.0f
1499 * </p>
1500 * <p>
1501 * Method issues {@link #markShapeDirty()}.
1502 * </p>
1503 * @see #setBorder(float)
1504 * @see #markShapeDirty()
1505 */
1506 public final Shape setBorderColor(final Vec4f c) {
1507 this.borderColor.set(c);
1509 return this;
1510 }
1511
1512 @Override
1513 public final String toString() {
1514 return getClass().getSimpleName()+"["+getSubString()+"]";
1515 }
1516
1517 public String getSubString() {
1518 final String iMatS;
1519 if( iMatDirty ) {
1520 iMatS = "mat-dirty, ";
1521 } else if( iMatIdent ) {
1522 iMatS = "mat-ident, ";
1523 } else {
1524 iMatS = "";
1525 }
1526 final String pivotS;
1527 if( null != rotPivot ) {
1528 pivotS = "pivot["+rotPivot+"], ";
1529 } else {
1530 pivotS = "";
1531 }
1532 final String scaleS;
1533 if( !scale.isEqual( Vec3f.ONE ) ) {
1534 scaleS = "scale["+scale+"], ";
1535 } else {
1536 scaleS = "scale 1, ";
1537 }
1538 final String rotateS;
1539 if( !rotation.isIdentity() ) {
1540 final Vec3f euler = rotation.toEuler(new Vec3f());
1541 rotateS = "rot["+euler+"], ";
1542 } else {
1543 rotateS = "";
1544 }
1545 final String discS = isDiscarded()?", DISCARDED":"";
1546 final String activeS = isActive()?", ACTIVE[adjZ "+getAdjustedZ()+"]":"";
1547 final String ps = hasPadding() ? padding.toString()+", " : "";
1548 final String bs = hasBorder() ? "border[l "+getBorderThickness()+", c "+getBorderColor()+"], " : "";
1549 final String idS = -1 != id ? ", id "+id : "";
1550 final String nameS = "noname" != name ? ", '"+name+"'" : "";
1551 return getDirtyString()+idS+nameS+", visible "+isIO(IO_VISIBLE)+discS+activeS+", toggle "+isIO(IO_TOGGLE)+
1552 ", able[toggle "+isIO(IO_TOGGLEABLE)+", iactive "+isInteractive()+", resize "+isResizable()+", drag "+this.isDraggable()+
1553 "], pos["+position+"], "+pivotS+scaleS+rotateS+iMatS+
1554 ps+bs+"box"+box;
1555 }
1556
1557 //
1558 // Input
1559 //
1560
1561 public final Shape setPressed(final boolean b) {
1562 setIO(IO_DOWN, b);
1564 return this;
1565 }
1566 public final boolean isPressed() { return isIO(IO_DOWN); }
1567
1568 /**
1569 * Set this shape toggleable, default is off.
1570 * @param toggleable
1571 * @see #isInteractive()
1572 */
1573 public final Shape setToggleable(final boolean toggleable) { return setIO(IO_TOGGLEABLE, toggleable); }
1574
1575 /**
1576 * Returns true if this shape is toggable,
1577 * i.e. rendered w/ {@link #setToggleOnColorMod(float, float, float, float)} or {@link #setToggleOffColorMod(float, float, float, float)}.
1578 * @see #isInteractive()
1579 */
1580 public boolean isToggleable() { return isIO(IO_TOGGLEABLE); }
1581
1582 /**
1583 * Set this shape's toggle state, default is off.
1584 * @param v
1585 * @return
1586 */
1587 public final Shape setToggle(final boolean v) {
1588 setIO(IO_TOGGLE, v);
1589 toggleNotify(v);
1590 if( null != onToggleListener ) {
1591 onToggleListener.run(this);
1592 }
1594 return this;
1595 }
1596 public final Shape toggle() {
1597 if( isToggleable() ) {
1598 setIO(IO_TOGGLE, !isToggleOn());
1600 if( null != onToggleListener ) {
1601 onToggleListener.run(this);
1602 }
1604 }
1605 return this;
1606 }
1607 protected void toggleNotify(final boolean on) {}
1608
1609 /** Returns true this shape's toggle state. */
1610 public final boolean isToggleOn() { return isIO(IO_TOGGLE); }
1611
1612 protected final boolean setActive(final boolean v, final float zOffset) {
1613 if( isActivable() ) {
1614 setZOffset(zOffset);
1615 setIO(IO_ACTIVE, v);
1616 if( !v ) {
1617 releaseInteraction();
1618 final Tooltip tt = tooltip;
1619 if( null != tt ) {
1620 tt.stop(false);
1621 }
1622 }
1623 if( DEBUG ) {
1624 System.err.println("XXX "+(v?" Active":"DeActive")+" "+this);
1625 }
1627 return true;
1628 } else {
1629 return false;
1630 }
1631 }
1632 /** Returns true of this shape is active */
1633 public final boolean isActive() { return isIO(IO_ACTIVE); }
1634
1635 /* pp */ void setActiveTopLevel(final boolean v, final float zOffset) {
1636 setZOffset(zOffset);
1637 setIO(IO_ACTIVE, v);
1639 }
1640
1641 public final float getAdjustedZ() {
1642 return position.z() * getScale().z() + zOffset;
1643 }
1644 /* pp */ final void setZOffset(final float v) { zOffset = v; }
1645
1646 /**
1647 * Set's a new {@link Tooltip} for this shape.
1648 * <p>
1649 * The {@link Shape} must be set {@link #setInteractive(boolean) interactive}
1650 * to receive the mouse-over signal, i.e. being picked.
1651 * </p>
1652 */
1653 public Tooltip setToolTip(final Tooltip newTooltip) {
1654 final Tooltip oldTT = this.tooltip;
1655 this.tooltip = null;
1656 if( null != oldTT ) {
1657 oldTT.stop(true);
1658 }
1659 newTooltip.setTool(this);
1660 this.tooltip = newTooltip;
1661 return newTooltip;
1662 }
1663 public void removeToolTip() {
1664 final Tooltip tt = tooltip;
1665 tooltip = null;
1666 if( null != tt ) {
1667 tt.stop(true);
1668 tt.setTool(null);
1669 }
1670 }
1671 private void stopToolTip() {
1672 final Tooltip tt = tooltip;
1673 if( null != tt ) {
1674 tt.stop(true);
1675 }
1676 }
1677 /* pp */ Tooltip startToolTip(final boolean lookupParents) {
1678 Tooltip tt = tooltip;
1679 if( null != tt ) {
1680 tt.start();
1681 return tt;
1682 } else if( lookupParents ) {
1683 Shape p = getParent();
1684 while( null != p ) {
1685 tt = p.startToolTip(false);
1686 if( null != tt ) {
1687 return tt;
1688 } else {
1689 p = p.getParent();
1690 }
1691 }
1692 }
1693 return null;
1694 }
1695 public Tooltip getTooltip() { return tooltip; }
1696
1697 /**
1698 * Set whether this shape is interactive in general,
1699 * i.e. any user interaction like
1700 * - {@link #isToggleable()}
1701 * - {@link #isDraggable()}
1702 * - {@link #isResizable()}
1703 * but excluding programmatic changes.
1704 * @param v new value for {@link #isInteractive()}
1705 * @see #isInteractive()
1706 * @see #isVisible()
1707 * @see #setDraggable(boolean)
1708 * @see #setResizable(boolean)
1709 * @see #setDragAndResizable(boolean)
1710 */
1711 public final Shape setInteractive(final boolean v) { return setIO(IO_INTERACTIVE, v); }
1712 /**
1713 * Returns if this shape allows user interaction in general, see {@link #setInteractive(boolean)}
1714 * @see #setInteractive(boolean)
1715 * @see #isVisible()
1716 */
1717 public final boolean isInteractive() { return isIO(IO_INTERACTIVE); }
1718
1719 /**
1720 * Set whether this shape is allowed to be activated, i.e become {@link #isActive()}.
1721 * <p>
1722 * A non activable shape still allows a shape to be dragged or resized,
1723 * it just can't gain the main focus.
1724 * </p>
1725 */
1726 public final Shape setActivable(final boolean v) { return setIO(IO_ACTIVABLE, v); }
1727
1728 /** Returns if this shape is allowed to be activated, i.e become {@link #isActive()}. */
1729 public final boolean isActivable() { return isIO(IO_ACTIVABLE); }
1730
1731 /**
1732 * Set whether this shape is discarded in last {@link #draw(GL2ES2, RegionRenderer)},
1733 * i.e. culled via frustum or occlusion criteria.
1734 */
1735 public final Shape setDiscarded(final boolean v) { return setIO(IO_DISCARDED, v); }
1736
1737 /** Returns whether this shape is discarded in last {@link #draw(GL2ES2, RegionRenderer)}, i.e. culled via frustum or occlusion criteria.*/
1738 public final boolean isDiscarded() { return isIO(IO_DISCARDED); }
1739
1740 /**
1741 * Set whether this shape is draggable,
1742 * i.e. translated by 1-pointer-click and drag.
1743 * <p>
1744 * Default draggable is true.
1745 * </p>
1746 * @see #isDraggable()
1747 * @see #setInteractive(boolean)
1748 * @see #setResizable(boolean)
1749 * @see #setDragAndResizable(boolean)
1750 */
1751 public final Shape setDraggable(final boolean draggable) { return setIO(IO_DRAGGABLE, draggable); }
1752 /**
1753 * Returns if this shape is draggable, a user interaction.
1754 * @see #setDraggable(boolean)
1755 */
1756 public final boolean isDraggable() { return isIO(IO_DRAGGABLE); }
1757
1758 /**
1759 * Set whether this shape is resizable,
1760 * i.e. zoomed by 1-pointer-click and drag in 1/4th bottom-left and bottom-right corner.
1761 * <p>
1762 * Default resizable is true.
1763 * </p>
1764 * @see #isResizable()
1765 * @see #setInteractive(boolean)
1766 * @see #setDraggable(boolean)
1767 * @see #setDragAndResizable(boolean)
1768 */
1769 public final Shape setResizable(final boolean resizable) { return setIO(IO_RESIZABLE, resizable); }
1770
1771 /**
1772 * Returns if this shape is resizable, a user interaction.
1773 * @see #setResizable(boolean)
1774 */
1775 public final boolean isResizable() { return isIO(IO_RESIZABLE); }
1776
1777 /**
1778 * Returns if aspect-ratio shall be kept at resize, if {@link #isResizable()}.
1779 * @see #setFixedARatioResize(boolean)
1780 */
1781 public final boolean isFixedARatioResize() { return isIO(IO_RESIZE_FIXED_RATIO); }
1782
1783 /**
1784 * Sets whether aspect-ratio shall be kept at resize, if {@link #isResizable()}.
1785 * @see #isResizable()
1786 * @see #isFixedARatioResize()
1787 */
1788 public final Shape setFixedARatioResize(final boolean v) { return setIO(IO_RESIZE_FIXED_RATIO, v); }
1789
1790 /**
1791 * Set whether this shape is draggable and resizable.
1792 * <p>
1793 * Default draggable and resizable is true.
1794 * </p>
1795 * @see #isDraggable()
1796 * @see #isResizable()
1797 * @see #setInteractive(boolean)
1798 * @see #setDraggable(boolean)
1799 * @see #setResizable(boolean)
1800 */
1801 public final Shape setDragAndResizable(final boolean v) {
1802 setDraggable(v);
1803 setResizable(v);
1804 return this;
1805 }
1806
1808 if(l == null) {
1809 return this;
1810 }
1811 @SuppressWarnings("unchecked")
1812 final ArrayList<MouseGestureListener> clonedListeners = (ArrayList<MouseGestureListener>) mouseListeners.clone();
1813 clonedListeners.add(l);
1814 mouseListeners = clonedListeners;
1815 return this;
1816 }
1818 if (l == null) {
1819 return this;
1820 }
1821 @SuppressWarnings("unchecked")
1822 final ArrayList<MouseGestureListener> clonedListeners = (ArrayList<MouseGestureListener>) mouseListeners.clone();
1823 clonedListeners.remove(l);
1824 mouseListeners = clonedListeners;
1825 return this;
1826 }
1827 /**
1828 * Forward {@link MouseGestureListener} events to this {@link Shape} from {@code source} using a {@link ForwardMouseListener}.
1829 * <p>
1830 * This source {@link Shape} must be {@link #setInteractive(boolean)} to receive and forward the events.
1831 * </p>
1832 * <p>
1833 * This receiver {@link Shape} must be {@link #setInteractive(boolean)} to have the events forwarded.
1834 * </p>
1835 * @see #receiveKeyEvents(Shape)
1836 */
1837 public void receiveMouseEvents(final Shape source) {
1839 }
1840
1841 public final Shape addKeyListener(final KeyListener l) {
1842 if(l == null) {
1843 return this;
1844 }
1845 @SuppressWarnings("unchecked")
1846 final ArrayList<KeyListener> clonedListeners = (ArrayList<KeyListener>) keyListeners.clone();
1847 clonedListeners.add(l);
1848 keyListeners = clonedListeners;
1849 return this;
1850 }
1851 public final Shape removeKeyListener(final KeyListener l) {
1852 if (l == null) {
1853 return this;
1854 }
1855 @SuppressWarnings("unchecked")
1856 final ArrayList<KeyListener> clonedListeners = (ArrayList<KeyListener>) keyListeners.clone();
1857 clonedListeners.remove(l);
1858 keyListeners = clonedListeners;
1859 return this;
1860 }
1861 /**
1862 * Forward {@link KeyListener} events to this {@link Shape} from {@code source} using a {@link ForwardKeyListener}.
1863 * <p>
1864 * This source {@link Shape} must be {@link #setInteractive(boolean)} to receive and forward the events.
1865 * </p>
1866 * <p>
1867 * This receiver {@link Shape} must be {@link #setInteractive(boolean)} to have the events forwarded.
1868 * </p>
1869 * @see #receiveMouseEvents(Shape)
1870 */
1871 public void receiveKeyEvents(final Shape source) {
1872 source.addKeyListener(new Shape.ForwardKeyListener(this));
1873 }
1874
1875 /**
1876 * Combining {@link MouseListener} and {@link GestureListener}
1877 */
1878 public static interface MouseGestureListener extends MouseListener, GestureListener {
1879 }
1880
1881 /**
1882 * Convenient adapter combining dummy implementation for {@link MouseListener} and {@link GestureListener}
1883 */
1884 public static abstract class MouseGestureAdapter extends MouseAdapter implements MouseGestureListener {
1885 @Override
1886 public void gestureDetected(final GestureEvent gh) {
1887 }
1888 }
1889
1890 /**
1891 * {@link Shape} event info for propagated {@link NEWTEvent}s
1892 * containing reference of {@link #shape the intended shape} as well as
1893 * the {@link #objPos rotated relative position} to this shape.
1894 * The latter is normalized to bottom-left zero origin, allowing easier usage.
1895 */
1896 public static class EventInfo {
1897 /** The associated {@link Shape} for this event */
1898 public final Shape shape;
1899 /** The relative object coordinate of glWinX/glWinY to the associated {@link Shape}. */
1900 public final Vec3f objPos;
1901 /** The GL window coordinates, origin bottom-left */
1902 public final int[] winPos;
1903 /** The drag delta of the relative object coordinate of glWinX/glWinY to the associated {@link Shape}. */
1904 public final Vec2f objDrag = new Vec2f();
1905 /** The drag delta of GL window coordinates, origin bottom-left */
1906 public final int[] winDrag = { 0, 0 };
1907
1908 /**
1909 * Ctor
1910 * @param glWinX in GL window coordinates, origin bottom-left
1911 * @param glWinY in GL window coordinates, origin bottom-left
1912 * @param shape associated shape
1913 * @param objPos relative object coordinate of glWinX/glWinY to the associated shape.
1914 */
1915 EventInfo(final int glWinX, final int glWinY, final Shape shape, final Vec3f objPos) {
1916 this.winPos = new int[] { glWinX, glWinY };
1917 this.shape = shape;
1918 this.objPos = objPos;
1919 }
1920
1921 @Override
1922 public String toString() {
1923 return "EventInfo[winPos ["+winPos[0]+", "+winPos[1]+"], objPos ["+objPos+"], "+shape+"]";
1924 }
1925 }
1926
1927 private final void releaseInteraction() {
1928 setPressed(false);
1929 setIO(IO_IN_MOVE, false);
1930 setIO(IO_IN_RESIZE_BR, false);
1931 setIO(IO_IN_RESIZE_BL, false);
1932 }
1933
1934 /**
1935 * Dispatch given NEWT mouse event to this shape
1936 * @param e original Newt {@link MouseEvent}
1937 * @param glWinX in GL window coordinates, origin bottom-left
1938 * @param glWinY in GL window coordinates, origin bottom-left
1939 * @param objPos object position of mouse event relative to this shape
1940 * @return true to signal operation complete and to stop traversal, otherwise false
1941 */
1942 /* pp */ final boolean dispatchMouseEvent(final MouseEvent e, final int glWinX, final int glWinY, final Vec3f objPos) {
1943 /**
1944 * Checked at caller!
1945 if( !isInteractive() ) {
1946 return false;
1947 } */
1948 final boolean resizableOrDraggable = isResizable() || isDraggable();
1949 final Shape.EventInfo shapeEvent = new EventInfo(glWinX, glWinY, this, objPos);
1950
1951 boolean ires = false;
1952 final short eventType = e.getEventType();
1953 if( 1 == e.getPointerCount() ) {
1954 switch( eventType ) {
1955 case MouseEvent.EVENT_MOUSE_MOVED:
1956 if( null != onHoverListener ) {
1957 onHoverListener.run(this, objPos, e);
1958 }
1959 ires = true;
1960 break;
1961 case MouseEvent.EVENT_MOUSE_PRESSED:
1962 if( resizableOrDraggable ) {
1963 setIO(IO_DRAG_FIRST, true);
1964 ires = true;
1965 }
1966 setPressed(true);
1967 break;
1968 case MouseEvent.EVENT_MOUSE_RELEASED:
1969 // Release interactions: last pointer has been lifted!
1970 releaseInteraction();
1971 ires = true;
1972 break;
1973 case MouseEvent.EVENT_MOUSE_CLICKED:
1974 if( isToggleable() ) {
1975 toggle();
1976 }
1977 if( null != onClickedListener ) {
1978 onClickedListener.run(this, objPos, e);
1979 }
1980 ires = true;
1981 break;
1982 }
1983 }
1984 if( resizableOrDraggable && MouseEvent.EVENT_MOUSE_DRAGGED == eventType ) {
1985 // adjust for rotation
1986 final Vec3f euler = rotation.toEuler(new Vec3f());
1987 final boolean x_flip, y_flip;
1988 {
1989 final float x_rot = Math.abs(euler.x());
1990 final float y_rot = Math.abs(euler.y());
1991 x_flip = 1f*FloatUtil.HALF_PI <= y_rot && y_rot <= 3f*FloatUtil.HALF_PI;
1992 y_flip = 1f*FloatUtil.HALF_PI <= x_rot && x_rot <= 3f*FloatUtil.HALF_PI;
1993 }
1994 // 1 pointer drag and potential drag-resize
1995 if( isIO(IO_DRAG_FIRST) ) {
1996 objDraggedFirst.set(objPos);
1997 winDraggedLast[0] = glWinX;
1998 winDraggedLast[1] = glWinY;
1999 setIO(IO_DRAG_FIRST, false);
2000
2001 final float ix = x_flip ? box.getWidth() - objPos.x() : objPos.x();
2002 final float iy = y_flip ? box.getHeight() - objPos.y() : objPos.y();
2003 final float minx_br = box.getMaxX() - box.getWidth() * resize_section;
2004 final float miny_br = box.getMinY();
2005 final float maxx_br = box.getMaxX();
2006 final float maxy_br = box.getMinY() + box.getHeight() * resize_section;
2007 if( minx_br <= ix && ix <= maxx_br &&
2008 miny_br <= iy && iy <= maxy_br ) {
2009 if( isResizable() ) {
2010 setIO(IO_IN_RESIZE_BR, true);
2011 }
2012 } else {
2013 final float minx_bl = box.getMinX();
2014 final float miny_bl = box.getMinY();
2015 final float maxx_bl = box.getMinX() + box.getWidth() * resize_section;
2016 final float maxy_bl = box.getMinY() + box.getHeight() * resize_section;
2017 if( minx_bl <= ix && ix <= maxx_bl &&
2018 miny_bl <= iy && iy <= maxy_bl ) {
2019 if( isResizable() ) {
2020 setIO(IO_IN_RESIZE_BL, true);
2021 }
2022 } else {
2023 setIO(IO_IN_MOVE, isDraggable());
2024 }
2025 }
2026 if( DEBUG ) {
2027 System.err.printf("DragFirst: drag %b, resize[br %b, bl %b], obj[%s], flip[x %b, y %b]%n",
2028 isIO(IO_IN_MOVE), isIO(IO_IN_RESIZE_BR), isIO(IO_IN_RESIZE_BL), objPos, x_flip, y_flip);
2029 System.err.printf("DragFirst: %s%n", this);
2030 }
2031 return true; // end signal traversal at 1st drag
2032 }
2033 shapeEvent.objDrag.set( objPos.x() - objDraggedFirst.x(),
2034 objPos.y() - objDraggedFirst.y() );
2035 shapeEvent.objDrag.mul(x_flip ? -1f : 1f, y_flip ? -1f : 1f);
2036
2037 shapeEvent.winDrag[0] = glWinX - winDraggedLast[0];
2038 shapeEvent.winDrag[1] = glWinY - winDraggedLast[1];
2039 winDraggedLast[0] = glWinX;
2040 winDraggedLast[1] = glWinY;
2041 if( 1 == e.getPointerCount() ) {
2042 final float sdx = shapeEvent.objDrag.x() * scale.x(); // apply scale, since operation
2043 final float sdy = shapeEvent.objDrag.y() * scale.y(); // is from a scaled-model-viewpoint
2044 if( isIO(IO_IN_RESIZE_BR) || isIO(IO_IN_RESIZE_BL) ) {
2045 final float bw = box.getWidth();
2046 final float bh = box.getHeight();
2047 final float sdy2, sx, sy;
2048 if( isIO(IO_IN_RESIZE_BR) ) {
2049 sx = scale.x() + sdx/bw; // bottom-right
2050 } else {
2051 sx = scale.x() - sdx/bw; // bottom-left
2052 }
2053 if( isFixedARatioResize() ) {
2054 sy = sx;
2055 sdy2 = bh * ( scale.y() - sy );
2056 } else {
2057 sdy2 = sdy;
2058 sy = scale.y() - sdy2/bh;
2059 }
2060 if( resize_sxy_min <= sx && resize_sxy_min <= sy ) { // avoid scale flip
2061 if( DEBUG ) {
2062 System.err.printf("DragZoom: resize[br %b, bl %b], win[%4d, %4d], , flip[x %b, y %b], obj[%s], dxy +[%s], sdxy +[%.4f, %.4f], sdxy2 +[%.4f, %.4f], scale [%s] -> [%.4f, %.4f]%n",
2063 isIO(IO_IN_RESIZE_BR), isIO(IO_IN_RESIZE_BL), glWinX, glWinY, x_flip, y_flip, objPos,
2064 shapeEvent.objDrag, sdx, sdy, sdx, sdy2,
2065 scale, sx, sy);
2066 }
2067 if( isIO(IO_IN_RESIZE_BR) ) {
2068 moveNotify( 0, sdy2, 0f, e); // bottom-right, sticky left- and top-edge
2069 } else {
2070 moveNotify( sdx, sdy2, 0f, e); // bottom-left, sticky right- and top-edge
2071 }
2072 setScale(sx, sy, scale.z());
2073 }
2074 return true; // end signal traversal with completed drag
2075 } else if( isIO(IO_IN_MOVE) ) {
2076 if( DEBUG ) {
2077 System.err.printf("DragMove: win[%4d, %4d] +[%2d, %2d], , flip[x %b, y %b], obj[%s] +[%s], rot %s%n",
2078 glWinX, glWinY, shapeEvent.winDrag[0], shapeEvent.winDrag[1],
2079 x_flip, y_flip, objPos, shapeEvent.objDrag, euler);
2080 }
2081 moveNotify( sdx, sdy, 0f, e);
2082 return true; // end signal traversal with completed move
2083 }
2084 }
2085 } // resizableOrDraggable && EVENT_MOUSE_DRAGGED
2086 e.setAttachment(shapeEvent);
2087
2088 return dispatchMouseEvent(e) || ires;
2089 }
2090
2091 /**
2092 * Dispatch given NEWT mouse event to this shape
2093 * @param e original Newt {@link MouseEvent}
2094 * @return true to signal operation complete and to stop traversal, otherwise false
2095 */
2096 /* pp */ final boolean dispatchMouseEvent(final MouseEvent e) {
2097 final short eventType = e.getEventType();
2098 for(int i = 0; !e.isConsumed() && i < mouseListeners.size(); i++ ) {
2099 final MouseGestureListener l = mouseListeners.get(i);
2100 switch( eventType ) {
2101 case MouseEvent.EVENT_MOUSE_CLICKED:
2102 l.mouseClicked(e);
2103 break;
2104 case MouseEvent.EVENT_MOUSE_ENTERED:
2105 l.mouseEntered(e);
2106 break;
2107 case MouseEvent.EVENT_MOUSE_EXITED:
2108 l.mouseExited(e);
2109 break;
2110 case MouseEvent.EVENT_MOUSE_PRESSED:
2111 l.mousePressed(e);
2112 break;
2113 case MouseEvent.EVENT_MOUSE_RELEASED:
2114 l.mouseReleased(e);
2115 break;
2116 case MouseEvent.EVENT_MOUSE_MOVED:
2117 l.mouseMoved(e);
2118 break;
2119 case MouseEvent.EVENT_MOUSE_DRAGGED:
2120 l.mouseDragged(e);
2121 break;
2122 case MouseEvent.EVENT_MOUSE_WHEEL_MOVED:
2123 l.mouseWheelMoved(e);
2124 break;
2125 default:
2126 throw new NativeWindowException("Unexpected mouse event type " + e.getEventType());
2127 }
2128 }
2129 return e.isConsumed(); // end signal traversal if consumed
2130 }
2131
2132 /**
2133 * @param e original Newt {@link GestureEvent}
2134 * @param glWinX x-position in OpenGL model space
2135 * @param glWinY y-position in OpenGL model space
2136 * @param pmv well formed PMVMatrix4f for this shape
2137 * @param viewport the viewport
2138 * @param objPos object position of mouse event relative to this shape
2139 */
2140 /* pp */ final void dispatchGestureEvent(final GestureEvent e, final int glWinX, final int glWinY, final PMVMatrix4f pmv, final Recti viewport, final Vec3f objPos) {
2141 if( isInteractive() && isResizable() && e instanceof PinchToZoomGesture.ZoomEvent ) {
2142 final PinchToZoomGesture.ZoomEvent ze = (PinchToZoomGesture.ZoomEvent) e;
2143 final float pixels = ze.getDelta() * ze.getScale(); //
2144 final int winX2 = glWinX + Math.round(pixels);
2145 final Vec3f objPos2 = winToShapeCoord(pmv, viewport, winX2, glWinY, new Vec3f());
2146 if( null == objPos2 ) {
2147 return;
2148 }
2149 final float dx = objPos2.x();
2150 final float dy = objPos2.y();
2151 final float sx = scale.x() + ( dx/box.getWidth() ); // bottom-right
2152 final float sy = scale.y() + ( dy/box.getHeight() );
2153 if( DEBUG ) {
2154 System.err.printf("DragZoom: resize[br %b, bl %b], win %4d/%4d, obj %s, %s + %.3f/%.3f -> %.3f/%.3f%n",
2155 isIO(IO_IN_RESIZE_BR), isIO(IO_IN_RESIZE_BL), glWinX, glWinY, objPos, position, dx, dy, sx, sy);
2156 }
2157 if( resize_sxy_min <= sx && resize_sxy_min <= sy ) { // avoid scale flip
2158 if( DEBUG ) {
2159 System.err.printf("PinchZoom: pixels %f, win %4d/%4d, obj %s, %s + %.3f/%.3f -> %.3f/%.3f%n",
2160 pixels, glWinX, glWinY, objPos, position, dx, dy, sx, sy);
2161 }
2162 // moveNotify(dx, dy, 0f);
2163 setScale(sx, sy, scale.z());
2164 }
2165 return; // FIXME: pass through event? Issue zoom event?
2166 }
2167 final Shape.EventInfo shapeEvent = new EventInfo(glWinX, glWinY, this, objPos);
2168 e.setAttachment(shapeEvent);
2169
2170 dispatchGestureEvent(e);
2171 }
2172
2173 /**
2174 * Dispatch given NEWT mouse event to this shape
2175 * @param e original Newt {@link MouseEvent}
2176 * @return true to signal operation complete and to stop traversal, otherwise false
2177 */
2178 /* pp */ final boolean dispatchGestureEvent(final GestureEvent e) {
2179 for(int i = 0; !e.isConsumed() && i < mouseListeners.size(); i++ ) {
2180 mouseListeners.get(i).gestureDetected(e);
2181 }
2182 return e.isConsumed(); // end signal traversal if consumed
2183 }
2184
2185 /**
2186 * Dispatch given NEWT key event to this shape
2187 * @param e original Newt {@link KeyEvent}
2188 * @return true to signal operation complete and to stop traversal, otherwise false
2189 */
2190 /* pp */ final boolean dispatchKeyEvent(final KeyEvent e) {
2191 /**
2192 * Checked at caller!
2193 if( !isInteractive() ) {
2194 return false;
2195 } */
2196 final short eventType = e.getEventType();
2197 for(int i = 0; !e.isConsumed() && i < keyListeners.size(); i++ ) {
2198 final KeyListener l = keyListeners.get(i);
2199 switch( eventType ) {
2200 case KeyEvent.EVENT_KEY_PRESSED:
2201 l.keyPressed(e);
2202 break;
2203 case KeyEvent.EVENT_KEY_RELEASED:
2204 l.keyReleased(e);
2205 break;
2206 default:
2207 throw new NativeWindowException("Unexpected key event type " + e.getEventType());
2208 }
2209 }
2210 return e.isConsumed(); // end signal traversal if consumed
2211 }
2212
2213 //
2214 //
2215 //
2216
2217 protected abstract void validateImpl(final GL2ES2 gl, final GLProfile glp);
2218
2219 /**
2220 * Actual draw implementation, called by {@link #draw(GL2ES2, RegionRenderer)}
2221 * @param gl
2222 * @param renderer
2223 * @param rgba
2224 */
2225 protected abstract void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final Vec4f rgba);
2226
2227 /**
2228 * Actual draw implementation, called by {@link #drawToSelect(GL2ES2, RegionRenderer)}
2229 * @param gl
2230 * @param renderer
2231 */
2232 protected abstract void drawToSelectImpl0(final GL2ES2 gl, final RegionRenderer renderer);
2233
2234 /** Custom {@link #clear(GL2ES2, RegionRenderer)} task, called 1st. */
2235 protected abstract void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer);
2236
2237 /** Custom {@link #destroy(GL2ES2, RegionRenderer)} task, called 1st. */
2238 protected abstract void destroyImpl0(final GL2ES2 gl, final RegionRenderer renderer);
2239
2240 /**
2241 * Returns true if implementation uses an extra color channel or texture
2242 * which will be modulated with the passed rgba color {@link #drawImpl0(GL2ES2, RegionRenderer, float[])}.
2243 *
2244 * Otherwise the base color will be modulated and passed to {@link #drawImpl0(GL2ES2, RegionRenderer, float[])}.
2245 */
2246 public abstract boolean hasColorChannel();
2247
2248 @SuppressWarnings("unused")
2249 private static int compareAsc0(final float a, final float b) {
2250 if( FloatUtil.isEqual2(a, b) ) {
2251 return 0;
2252 } else if( a < b ){
2253 return -1;
2254 } else {
2255 return 1;
2256 }
2257 }
2258 private static int compareAsc1(final float a, final float b) {
2259 if (a < b) {
2260 return -1; // Neither is NaN, a is smaller
2261 }
2262 if (a > b) {
2263 return 1; // Neither is NaN, a is larger
2264 }
2265 return 0;
2266 }
2267 @SuppressWarnings("unused")
2268 private static int compareDesc0(final float a, final float b) {
2269 if( FloatUtil.isEqual2(a, b) ) {
2270 return 0;
2271 } else if( a < b ){
2272 return 1;
2273 } else {
2274 return -1;
2275 }
2276 }
2277 private static int compareDesc1(final float a, final float b) {
2278 if (a < b) {
2279 return 1; // Neither is NaN, a is smaller
2280 }
2281 if (a > b) {
2282 return -1; // Neither is NaN, a is larger
2283 }
2284 return 0;
2285 }
2286
2287 public static Comparator<Shape> ZAscendingComparator = new Comparator<Shape>() {
2288 @Override
2289 public int compare(final Shape s1, final Shape s2) {
2290 return compareAsc1( s1.getAdjustedZ(), s2.getAdjustedZ() );
2291 } };
2292
2293 public static Comparator<Shape> ZDescendingComparator = new Comparator<Shape>() {
2294 @Override
2295 public int compare(final Shape s1, final Shape s2) {
2296 return compareDesc1( s2.getAdjustedZ(), s1.getAdjustedZ() );
2297 } };
2298
2299 //
2300 //
2301 //
2302}
Group of Shapes, optionally utilizing a Group.Layout.
Definition: Group.java:61
GraphUI Scene.
Definition: Scene.java:102
final PMVMatrixSetup getPMVMatrixSetup()
Return the default or setPMVMatrixSetup(PMVMatrixSetup) PMVMatrixSetup.
Definition: Scene.java:742
final Recti getViewport(final Recti target)
Copies the current int[4] viewport in given target and returns it for chaining.
Definition: Scene.java:768
Shape event info for propagated NEWTEvents containing reference of the intended shape as well as the ...
Definition: Shape.java:1896
final int[] winPos
The GL window coordinates, origin bottom-left.
Definition: Shape.java:1902
final Vec3f objPos
The relative object coordinate of glWinX/glWinY to the associated Shape.
Definition: Shape.java:1900
final Shape shape
The associated Shape for this event.
Definition: Shape.java:1898
final Vec2f objDrag
The drag delta of the relative object coordinate of glWinX/glWinY to the associated Shape.
Definition: Shape.java:1904
final int[] winDrag
The drag delta of GL window coordinates, origin bottom-left.
Definition: Shape.java:1906
Forward KeyListener, to be attached to a key event source forwarded to the receiver set at constructo...
Definition: Shape.java:172
ForwardKeyListener(final Shape receiver)
ForwardKeyListener Constructor
Definition: Shape.java:178
void keyReleased(final KeyEvent e)
A key has been released, excluding auto-repeat modifier keys.
Definition: Shape.java:190
void keyPressed(final KeyEvent e)
A key has been pressed, excluding auto-repeat modifier keys.
Definition: Shape.java:188
Forward MouseGestureListener, to be attached to a mouse event source forwarded to the receiver set at...
Definition: Shape.java:200
void mouseExited(final MouseEvent e)
Only generated for PointerType#Mouse.
Definition: Shape.java:219
void mouseWheelMoved(final MouseEvent e)
Traditional event name originally produced by a mouse pointer type.
Definition: Shape.java:229
void mouseEntered(final MouseEvent e)
Only generated for PointerType#Mouse.
Definition: Shape.java:217
ForwardMouseListener(final Shape receiver)
ForwardMouseListener Constructor
Definition: Shape.java:206
void mouseClicked(final MouseEvent e)
Definition: Shape.java:215
void mousePressed(final MouseEvent e)
Definition: Shape.java:221
void mouseReleased(final MouseEvent e)
Definition: Shape.java:223
void mouseDragged(final MouseEvent e)
Definition: Shape.java:227
void gestureDetected(final GestureEvent e)
GestureHandler has detected the gesture.
Definition: Shape.java:231
Convenient adapter combining dummy implementation for MouseListener and GestureListener.
Definition: Shape.java:1884
void gestureDetected(final GestureEvent gh)
GestureHandler has detected the gesture.
Definition: Shape.java:1886
Generic Shape, potentially using a Graph via GraphShape or other means of representing content.
Definition: Shape.java:87
final int[] shapeToWinCoord(final Scene.PMVMatrixSetup pmvMatrixSetup, final Recti viewport, final Vec3f objPos, final PMVMatrix4f pmv, final int[] glWinPos)
Map given object coordinate relative to this shape to window coordinates.
Definition: Shape.java:1264
final boolean isMatIdentity()
Returns true if getMat() has not been mutated, i.e.
Definition: Shape.java:943
Padding getPadding()
Returns unscaled Padding of this shape, which is included in unscaled getBounds() and also includes t...
Definition: Shape.java:387
Tooltip setToolTip(final Tooltip newTooltip)
Set's a new Tooltip for this shape.
Definition: Shape.java:1653
final boolean isStateDirty()
Returns the rendering dirty state, see markStateDirty().
Definition: Shape.java:705
abstract void drawToSelectImpl0(final GL2ES2 gl, final RegionRenderer renderer)
Actual draw implementation, called by drawToSelect(GL2ES2, RegionRenderer).
final Matrix4f getMat()
Returns the internal Matrix4f reference.
Definition: Shape.java:926
final Shape removeKeyListener(final KeyListener l)
Definition: Shape.java:1851
final boolean isDraggable()
Returns if this shape is draggable, a user interaction.
Definition: Shape.java:1756
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
final Shape setDraggable(final boolean draggable)
Set whether this shape is draggable, i.e.
Definition: Shape.java:1751
void receiveMouseEvents(final Shape source)
Forward MouseGestureListener events to this Shape from source using a ForwardMouseListener.
Definition: Shape.java:1837
final String getName()
Return the optional symbolic name for this shape, defaults to noname.
Definition: Shape.java:341
final Shape addKeyListener(final KeyListener l)
Definition: Shape.java:1841
abstract void destroyImpl0(final GL2ES2 gl, final RegionRenderer renderer)
Custom destroy(GL2ES2, RegionRenderer) task, called 1st.
final Shape move(final float dtx, final float dty, final float dtz)
Move about scaled distance.
Definition: Shape.java:557
final void onHover(final PointerListener l)
Set user callback to be notified when a pointer/mouse is moving over this shape.
Definition: Shape.java:481
Shape()
Create a generic UI Shape.
Definition: Shape.java:320
final Shape setScale(final Vec3f s)
Set scale factor to given scale.
Definition: Shape.java:641
final Shape setInteractive(final boolean v)
Set whether this shape is interactive in general, i.e.
Definition: Shape.java:1711
final Shape addActivationListener(final Listener l)
Add user callback to be notified when shape is activated (pointer-over and/or click) or de-activated ...
Definition: Shape.java:511
final Vec3f winToShapeCoord(final Scene.PMVMatrixSetup pmvMatrixSetup, final Recti viewport, final int glWinX, final int glWinY, final PMVMatrix4f pmv, final Vec3f objPos)
Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate.
Definition: Shape.java:1336
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 Vec4f activeRGBAModulate
Default active color-factor (dark), modulates base-color.
Definition: Shape.java:269
boolean isGroup()
Returns true if this shape denotes a Group, otherwise false.
Definition: Shape.java:344
final boolean isActive()
Returns true of this shape is active.
Definition: Shape.java:1633
final Matrix4f getMat(final Matrix4f out)
Returns a copy of the internal Matrix4f to out.
Definition: Shape.java:937
final int getID()
Return the optional symbolic ID for this shape.
Definition: Shape.java:336
final Shape setDiscarded(final boolean v)
Set whether this shape is discarded in last draw(GL2ES2, RegionRenderer), i.e.
Definition: Shape.java:1735
final Shape toggle()
Definition: Shape.java:1596
final void onDraw(final DrawListener l)
Set a user one-shot initializer callback or custom draw(GL2ES2, RegionRenderer) hook.
Definition: Shape.java:477
final boolean hasBorder()
Returns true if a border has been enabled via setBorder(float, Padding).
Definition: Shape.java:408
final void onClicked(final PointerListener l)
Set user callback to be notified when shape is clicked.
Definition: Shape.java:503
final Shape setPressed(final boolean b)
Definition: Shape.java:1561
final Shape moveTo(final Vec3f t)
Move to scaled position.
Definition: Shape.java:550
final Vec3f winToShapeCoord(final PMVMatrix4f pmv, final Recti viewport, final int glWinX, final int glWinY, final Vec3f objPos)
Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate.
Definition: Shape.java:1305
final Vec3f getScale()
Returns scale Vec3f reference.
Definition: Shape.java:682
final Shape setFixedARatioResize(final boolean v)
Sets whether aspect-ratio shall be kept at resize, if isResizable().
Definition: Shape.java:1788
final Recti getSurfacePort(final PMVMatrix4f pmv, final Recti viewport, final Recti surfacePort)
Retrieve surface (view) port of this shape, i.e.
Definition: Shape.java:1067
boolean activeRGBAModulateOn
Definition: Shape.java:270
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 getAdjustedZ()
Definition: Shape.java:1641
static Comparator< Shape > ZDescendingComparator
Definition: Shape.java:2293
final float getBorderThickness()
Returns the border thickness, see setBorder(float, Padding).
Definition: Shape.java:411
final boolean isResizable()
Returns if this shape is resizable, a user interaction.
Definition: Shape.java:1775
final Shape setScale(final float sx, final float sy, final float sz)
Set scale factor to given scale.
Definition: Shape.java:651
final Vec4f toggleOnRGBAModulate
Default toggle color-factor (darker), modulates base-color.
Definition: Shape.java:265
boolean isShapeDirty()
Returns the shape's dirty state, see markShapeDirty().
Definition: Shape.java:701
static final boolean DEBUG_DRAW
Definition: Shape.java:238
final void markStateDirty()
Marks the rendering state dirty, causing next draw() to notify the Graph region to reselect shader an...
Definition: Shape.java:696
final Shape setResizable(final boolean resizable)
Set whether this shape is resizable, i.e.
Definition: Shape.java:1769
final Shape moveTo(final float tx, final float ty, final float tz)
Move to scaled position.
Definition: Shape.java:543
static Comparator< Shape > ZAscendingComparator
Definition: Shape.java:2287
final Shape removeMouseListener(final MouseGestureListener l)
Definition: Shape.java:1817
void setParent(final Group c)
Definition: Shape.java:322
final float getScaledWidth()
Returns the scaled width of the bounding AABBox for this shape.
Definition: Shape.java:745
final float getScaledHeight()
Returns the scaled height of the bounding AABBox for this shape.
Definition: Shape.java:760
final Shape validate(final GLProfile glp)
Validates the shape's underlying GLRegion w/o a current GL2ES2 object.
Definition: Shape.java:869
final Shape setToggle(final boolean v)
Set this shape's toggle state, default is off.
Definition: Shape.java:1587
abstract void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer)
Custom clear(GL2ES2, RegionRenderer) task, called 1st.
final Vec3f getPosition()
Returns position Vec3f reference, i.e.
Definition: Shape.java:587
final Vec4f toggleOffRGBAModulate
Default toggle color-factor (original), modulates base-color.
Definition: Shape.java:267
final Shape scale(final float sx, final float sy, final float sz)
Multiply current scale factor by given scale.
Definition: Shape.java:671
final Vec3f winToShapeCoord(final Scene scene, final int glWinX, final int glWinY, final PMVMatrix4f pmv, final Vec3f objPos)
Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate.
Definition: Shape.java:1358
final float[] getPixelPerShapeUnit(final int[] shapeSizePx, final float[] pixPerShape)
Retrieve pixel per scaled shape-coordinate unit, i.e.
Definition: Shape.java:1165
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
Shape setPressedColorMod(final float r, final float g, final float b, final float a)
Set pressed color, modulating getColor() if isPressed().
Definition: Shape.java:1423
Shape setColor(final Vec4f c)
Set base color.
Definition: Shape.java:1408
final AABBox getBounds(final GLProfile glp)
Returns the unscaled bounding AABBox for this shape.
Definition: Shape.java:777
final boolean isVisible()
Returns true if this shape is set visible by the user, otherwise false.
Definition: Shape.java:353
final Quaternion getRotation()
Returns Quaternion for rotation.
Definition: Shape.java:595
final Shape move(final Vec3f dt)
Move about scaled distance.
Definition: Shape.java:564
abstract void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final Vec4f rgba)
Actual draw implementation, called by draw(GL2ES2, RegionRenderer).
abstract void validateImpl(final GL2ES2 gl, final GLProfile glp)
void drawToSelect(final GL2ES2 gl, final RegionRenderer renderer)
Experimental selection draw command used by Scene.
Definition: Shape.java:783
final Shape removeActivationListener(final Listener l)
Definition: Shape.java:521
final Vec4f getToggleOffColorMod()
Returns modulation color when not isToggleOn().
Definition: Shape.java:1372
final Shape setDragAndResizable(final boolean v)
Set whether this shape is draggable and resizable.
Definition: Shape.java:1801
Group getParent()
Returns the last parent container Group this shape has been added to or null.
Definition: Shape.java:331
final boolean isToggleOn()
Returns true this shape's toggle state.
Definition: Shape.java:1610
final int[] shapeToWinCoord(final Scene scene, final Vec3f objPos, final PMVMatrix4f pmv, final int[] glWinPos)
Map given object coordinate relative to this shape to window coordinates.
Definition: Shape.java:1283
final Vec4f getColor()
Returns base-color w/o color channel, will be modulated w/ getPressedColorMod(), getToggleOnColorMod(...
Definition: Shape.java:1366
final int[] getSurfaceSize(final Scene.PMVMatrixSetup pmvMatrixSetup, final Recti viewport, final PMVMatrix4f pmv, final int[] surfaceSize)
Retrieve surface (view) size in pixels of this shape.
Definition: Shape.java:1133
final boolean isFixedARatioResize()
Returns if aspect-ratio shall be kept at resize, if isResizable().
Definition: Shape.java:1781
final Vec4f getActiveColorMod()
Returns modulation color when isActive().
Definition: Shape.java:1374
final Shape setToggleOnColorMod(final float r, final float g, final float b, final float a)
Set toggle-on color, modulating getColor() if isToggleOn() and setToggleable(boolean).
Definition: Shape.java:1437
final void dispatchActivationEvent(final Shape s)
Dispatch activation event event to this shape.
Definition: Shape.java:535
final Shape setToggleOffColorMod(final float r, final float g, final float b, final float a)
Set toggle-off color, modulating getColor() if !isToggleOn() and setToggleable(boolean).
Definition: Shape.java:1451
final Shape validate(final GL2ES2 gl)
Validates the shape's underlying GLRegion.
Definition: Shape.java:850
final boolean isDiscarded()
Returns whether this shape is discarded in last draw(GL2ES2, RegionRenderer), i.e.
Definition: Shape.java:1738
void toggleNotify(final boolean on)
Definition: Shape.java:1607
final int[] getSurfaceSize(final PMVMatrix4f pmv, final Recti viewport, final int[] surfaceSize)
Retrieve surface (view) size in pixels of this shape.
Definition: Shape.java:1100
final PMVMatrix4f setPMVMatrix(final Scene.PMVMatrixSetup pmvMatrixSetup, final Recti viewport, final PMVMatrix4f pmv)
Setup the given PMVMatrix4f and apply this shape's transformation.
Definition: Shape.java:1033
final Shape addMouseListener(final MouseGestureListener l)
Definition: Shape.java:1807
final Shape setActivable(final boolean v)
Set whether this shape is allowed to be activated, i.e become isActive().
Definition: Shape.java:1726
abstract boolean hasColorChannel()
Returns true if implementation uses an extra color channel or texture which will be modulated with th...
final void markShapeDirty()
Marks the shape dirty, causing next draw() to recreate the Graph shape and reset the region.
Definition: Shape.java:688
final boolean isPressed()
Definition: Shape.java:1566
final Shape setBorderColor(final Vec4f c)
Set border color.
Definition: Shape.java:1506
final Shape setPaddding(final Padding padding)
Sets the unscaled padding for this shape, which is included in unscaled getBounds() and also includes...
Definition: Shape.java:376
final Shape setRotation(final Quaternion q)
Sets the rotation Quaternion.
Definition: Shape.java:604
final void updateMat()
Updates the internal Matrix4f with local position, rotation and scale.
Definition: Shape.java:971
final void runSynced(final Runnable action)
Perform given Runnable action synchronized.
Definition: Shape.java:414
final void destroy(final GL2ES2 gl, final RegionRenderer renderer)
Destroys all data.
Definition: Shape.java:457
final Vec4f rgbaColor
Default base-color w/o color channel, will be modulated w/ pressed- and toggle color.
Definition: Shape.java:261
final int[] getSurfaceSize(final Scene scene, final PMVMatrix4f pmv, final int[] surfaceSize)
Retrieve surface (view) size in pixels of this shape.
Definition: Shape.java:1151
final void onToggle(final Listener l)
Set user callback to be notified when shape toggle()'ed.
Definition: Shape.java:495
final int[] shapeToWinCoord(final PMVMatrix4f pmv, final Recti viewport, final Vec3f objPos, final int[] glWinPos)
Map given object coordinate relative to this shape to window coordinates.
Definition: Shape.java:1236
final Shape setActiveColorMod(final Vec4f c)
Enable active color, modulation getColor() if isActive() with passing c != null, disable with passing...
Definition: Shape.java:1466
final void applyMatToMv(final PMVMatrix4f pmv)
Applies the internal Matrix4f to the given modelview matrix, i.e.
Definition: Shape.java:908
final Shape scale(final Vec3f s)
Multiply current scale factor by given scale.
Definition: Shape.java:661
final Shape setVisible(final boolean v)
Enable (default) or disable this shape's visibility.
Definition: Shape.java:363
boolean isToggleable()
Returns true if this shape is toggable, i.e.
Definition: Shape.java:1580
final Shape validate(final GL2ES2 gl, final GLProfile glp)
Validate the shape via validate(GL2ES2) if gl is not null, otherwise uses validate(GLProfile).
Definition: Shape.java:886
final Vec4f getToggleOnColorMod()
Returns modulation color when isToggleOn().
Definition: Shape.java:1370
final Shape setRotationPivot(final float px, final float py, final float pz)
Set unscaled rotation origin, aka pivot.
Definition: Shape.java:620
final boolean isInteractive()
Returns if this shape allows user interaction in general, see setInteractive(boolean).
Definition: Shape.java:1717
final float[] getPixelPerShapeUnit(final PMVMatrix4f pmv, final Recti viewport, final float[] pixPerShape)
Retrieve pixel per scaled shape-coordinate unit, i.e.
Definition: Shape.java:1187
final float getScaledDepth()
Definition: Shape.java:764
final Vec4f getPressedColorMod()
Returns modulation color when isPressed().
Definition: Shape.java:1368
final PMVMatrix4f setPMVMatrix(final Scene scene, final PMVMatrix4f pmv)
Setup the given PMVMatrix4f and apply this shape's transformation.
Definition: Shape.java:1051
void receiveKeyEvents(final Shape source)
Forward KeyListener events to this Shape from source using a ForwardKeyListener.
Definition: Shape.java:1871
final boolean isActivable()
Returns if this shape is allowed to be activated, i.e become isActive().
Definition: Shape.java:1729
final void onMove(final MoveListener l)
Set user callback to be notified when shape is move(Vec3f)'ed.
Definition: Shape.java:485
final Shape setBorderColor(final float r, final float g, final float b, final float a)
Set border color.
Definition: Shape.java:1489
final Shape setID(final int id)
Set a symbolic ID for this shape for identification.
Definition: Shape.java:334
final boolean setActive(final boolean v, final float zOffset)
Definition: Shape.java:1612
final Shape setBorder(final float thickness)
Sets the thickness of the border, which is included in getBounds() and is outside of getPadding().
Definition: Shape.java:402
final float[] getPixelPerShapeUnit(final Scene scene, final PMVMatrix4f pmv, final float[] pixPerShape)
Retrieve pixel per scaled shape-coordinate unit, i.e.
Definition: Shape.java:1212
final String toString()
Definition: Shape.java:1513
final Shape setToggleable(final boolean toggleable)
Set this shape toggleable, default is off.
Definition: Shape.java:1573
final Vec3f getRotationPivot()
Return unscaled rotation origin Vec3f reference, aka pivot.
Definition: Shape.java:614
final String getDirtyString()
Definition: Shape.java:709
final Shape setRotationPivot(final Vec3f pivot)
Set unscaled rotation origin, aka pivot.
Definition: Shape.java:630
final Vec4f pressedRGBAModulate
Default pressed color-factor (darker and slightly transparent), modulates base-color.
Definition: Shape.java:263
A HUD tooltip for Shape, see Shape#setToolTip(Tooltip).
Definition: Tooltip.java:44
final void start()
Starts the timer.
Definition: Tooltip.java:112
final boolean stop(final boolean clearForced)
Stops the timer if not enforced via now() or clearForced is true.
Definition: Tooltip.java:98
GraphUI CSS property Padding, unscaled space belonging to the element and included in the element's s...
Definition: Padding.java:38
Basic Float math utility functions.
Definition: FloatUtil.java:83
static boolean isEqual2(final float a, final float b)
Returns true if both values are equal, i.e.
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
static boolean mapObjToWin(final Vec3f obj, final Matrix4f mMv, final Matrix4f mP, final Recti viewport, final Vec3f winPos)
Map object coordinates to window coordinates.
Definition: Matrix4f.java:1696
Matrix4f load(final Matrix4f src)
Load the values of the given matrix src to this matrix.
Definition: Matrix4f.java:186
final Matrix4f loadIdentity()
Set this matrix to identity.
Definition: Matrix4f.java:172
final Matrix4f rotate(final float ang_rad, final float x, final float y, final float z, final Matrix4f tmp)
Rotate this matrix about give axis and angle in radians, i.e.
Definition: Matrix4f.java:1525
final Matrix4f scale(final float x, final float y, final float z, final Matrix4f tmp)
Scale this matrix, i.e.
Definition: Matrix4f.java:1580
final Matrix4f translate(final float x, final float y, final float z, final Matrix4f tmp)
Translate this matrix, i.e.
Definition: Matrix4f.java:1558
static boolean mapWinToObj(final float winx, final float winy, final float winz, final Matrix4f mMv, final Matrix4f mP, final Recti viewport, final Vec3f objPos, final Matrix4f mat4Tmp)
Map window coordinates to object coordinates.
Definition: Matrix4f.java:1778
final Matrix4f setToTranslation(final float x, final float y, final float z)
Set this matrix to translation.
Definition: Matrix4f.java:887
Quaternion implementation supporting Gimbal-Lock free rotations.
Definition: Quaternion.java:45
Vec3f toEuler(final Vec3f result)
Transform this quaternion to Euler rotation angles in radians (pitchX, yawY and rollZ).
final Quaternion set(final Quaternion src)
Set all values of this quaternion using the given src.
final Quaternion setIdentity()
final boolean isIdentity()
Returns true if this quaternion has identity.
Rectangle with x, y, width and height integer components.
Definition: Recti.java:34
void setWidth(final int width)
Definition: Recti.java:99
void setY(final int y)
Definition: Recti.java:98
void setHeight(final int height)
Definition: Recti.java:100
void setX(final int x)
Definition: Recti.java:97
2D Vector based upon two float components.
Definition: Vec2f.java:37
3D Vector based upon three float components.
Definition: Vec3f.java:37
static final Vec3f ONE
Definition: Vec3f.java:38
Vec3f mul(final float val)
Returns this * val; creates new vector.
Definition: Vec3f.java:178
boolean isZero()
Return true if all components are zero, i.e.
Definition: Vec3f.java:276
boolean isEqual(final Vec3f o, final float epsilon)
Equals check using a given FloatUtil#EPSILON value and FloatUtil#isEqual(float, float,...
Definition: Vec3f.java:383
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
Vec4f set(final Vec4f o)
this = o, returns this.
Definition: Vec4f.java:67
Vec4f mul(final float val)
Returns this * val; creates new vector.
Definition: Vec4f.java:170
Axis Aligned Bounding Box.
Definition: AABBox.java:54
final Vec3f getHigh()
Returns the maximum right-top-near (xyz) coordinate.
Definition: AABBox.java:131
final float getWidth()
Definition: AABBox.java:879
final Vec3f getLow()
Returns the minimum left-bottom-far (xyz) coordinate.
Definition: AABBox.java:140
final float getHeight()
Definition: AABBox.java:883
final AABBox reset()
Resets this box to the inverse low/high, allowing the next resize(float, float, float) command to hit...
Definition: AABBox.java:123
final Vec3f getCenter()
Returns computed center of this AABBox of getLow() and getHigh().
Definition: AABBox.java:737
final float getDepth()
Definition: AABBox.java:887
PMVMatrix4f implements the basic computer graphics Matrix4f pack using projection (P),...
final PMVMatrix4f mulMv(final Matrix4f m)
Multiply the modelview matrix: [c] = [c] x [m].
final Matrix4f getPMv()
Returns the pre-multiplied projection x modelview, P x Mv.
final boolean mapObjToWin(final Vec3f objPos, final Recti viewport, final Vec3f winPos)
Map object coordinates to window coordinates.
final Matrix4f getPMvi()
Returns the pre-multiplied inverse projection x modelview, if Matrix4f#invert(Matrix4f) succeeded,...
Pointer event of type PointerType.
Definition: MouseEvent.java:74
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
Interface providing a method to setup PMVMatrix4f's GLMatrixFunc#GL_PROJECTION and GLMatrixFunc#GL_MO...
Definition: Scene.java:706
Shape draw listener action returning a boolean value
Definition: Shape.java:154
boolean run(final Shape shape, GL2ES2 gl, RegionRenderer renderer)
Return true to remove this DrawListener at Shape#draw(GL2ES2, RegionRenderer), otherwise it is being ...
General Shape listener action.
Definition: Shape.java:143
void run(final Shape shape)
Combining MouseListener and GestureListener.
Definition: Shape.java:1878
void run(Shape s, Vec3f origin, Vec3f dest, MouseEvent e)
Move callback.
Shape pointer listener, e.g.
Definition: Shape.java:130
void run(Shape s, final Vec3f pos, MouseEvent e)
Event callback.
General Shape visitor.
Definition: Shape.java:91
boolean visit(Shape s)
Visitor method.
General Shape visitor.
Definition: Shape.java:103
boolean visit(Shape s, final PMVMatrix4f pmv)
Visitor method.
Listener for KeyEvents.
GLProfile getGLProfile()
Returns the GLProfile associated with this GL object.