JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
UISceneDemo02.java
Go to the documentation of this file.
1/**
2 * Copyright 2010-2023 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.opengl.demos.graph.ui;
29
30import java.io.IOException;
31
32import com.jogamp.common.os.Clock;
33import com.jogamp.common.util.IOUtil;
34import com.jogamp.graph.curve.Region;
35import com.jogamp.graph.font.Font;
36import com.jogamp.graph.font.FontFactory;
37import com.jogamp.graph.ui.Scene;
38import com.jogamp.graph.ui.shapes.Label;
39import com.jogamp.math.geom.AABBox;
40import com.jogamp.math.util.PMVMatrix4f;
41import com.jogamp.newt.MonitorDevice;
42import com.jogamp.newt.event.WindowAdapter;
43import com.jogamp.newt.event.WindowEvent;
44import com.jogamp.newt.opengl.GLWindow;
45import com.jogamp.opengl.GL;
46import com.jogamp.opengl.GLCapabilities;
47import com.jogamp.opengl.GLProfile;
48import com.jogamp.opengl.demos.graph.FontSetDemos;
49import com.jogamp.opengl.demos.util.CommandlineOptions;
50import com.jogamp.opengl.demos.util.MiscUtils;
51import com.jogamp.opengl.util.Animator;
52
53/**
54 * Res independent Shape, Scene attached to GLWindow showing simple linear Shape movement.
55 * <p>
56 * This variation of {@link UISceneDemo00} shows a text animation assembling one line of text,
57 * each glyph coming from the right moving to its destination sequentially.
58 * </p>
59 * <p>
60 * Pass '-keep' to main-function to keep running.
61 * Pass '-auto' to main-function to keep running and change speed for each animation cycle
62 * </p>
63 */
64public class UISceneDemo02 {
65 static CommandlineOptions options = new CommandlineOptions(1280, 720, Region.VBAA_RENDERING_BIT);
66 static float req_total_dur_s = 6f; // [s]
67
68 public static void main(final String[] args) throws IOException {
69 int autoSpeed = 0;
70
71 if( 0 != args.length ) {
72 final int[] idx = { 0 };
73 for (idx[0] = 0; idx[0] < args.length; ++idx[0]) {
74 if( options.parse(args, idx) ) {
75 continue;
76 } else if(args[idx[0]].equals("-aspeed")) {
77 autoSpeed = 1;
78 req_total_dur_s = 1f;
79 options.keepRunning = true;
80 }
81 }
82 }
83 System.err.println(options);
84 final GLCapabilities reqCaps = options.getGLCaps();
85 System.out.println("Requested: " + reqCaps);
86
87 //
88 // Resolution independent, no screen size
89 //
90 final Font font = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerif.ttf", FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true);
91 // final Font font = FontFactory.get(IOUtil.getResource("jogamp/graph/font/fonts/ubuntu/Ubuntu-R.ttf", FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true);
92 System.err.println("Font: "+font.getFullFamilyName());
93 final Font fontStatus = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMono.ttf", FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true);
94
95 final Label destText = new Label(options.renderModes, font, "");
96 destText.setColor(0.1f, 0.1f, 0.1f, 1);
97 final Label movingGlyph = new Label(options.renderModes, font, "");
98 movingGlyph.setColor(0.1f, 0.1f, 0.1f, 1);
99
100 final Scene scene = new Scene(options.graphAASamples);
101 scene.setClearParams(new float[] { 1f, 1f, 1f, 1f}, GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
102 scene.addShape(destText);
103 scene.addShape(movingGlyph);
104 scene.setAAQuality(options.graphAAQuality);
105
106 final Animator animator = new Animator(0 /* w/o AWT */);
107 animator.setUpdateFPSFrames(1*60, null); // System.err);
108
109 final GLWindow window = GLWindow.create(reqCaps);
110 window.setSize(options.surface_width, options.surface_height);
111 window.setTitle(UISceneDemo02.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight());
112 window.setVisible(true);
113 window.addGLEventListener(scene);
114 window.addWindowListener(new WindowAdapter() {
115 @Override
116 public void windowResized(final WindowEvent e) {
117 window.setTitle(UISceneDemo02.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight());
118 }
119 @Override
120 public void windowDestroyNotify(final WindowEvent e) {
121 animator.stop();
122 }
123 });
124
125 scene.attachInputListenerTo(window);
126
127 animator.add(window);
128 animator.start();
129
130 //
131 // After initial display we can use screen resolution post initial Scene.reshape(..)
132 // However, in this example we merely use the resolution to
133 // - Compute the animation values with DPI
134 scene.waitUntilDisplayed();
135
136 final GLProfile hasGLP = window.getChosenGLCapabilities().getGLProfile();
137 final AABBox sceneBox = scene.getBounds();
138 System.err.println("SceneBox "+sceneBox);
139
140 if( options.wait_to_start ) {
141 MiscUtils.waitForKey("Start");
142 }
143
144 final Label statusLabel;
145 {
146 final AABBox fbox = fontStatus.getGlyphBounds("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
147 // final float statusLabelScale = (sceneBox.getHeight() / 30f) * fbox.getHeight();
148 final float statusLabelScale = sceneBox.getWidth() / fbox.getWidth();
149 System.err.println("StatusLabel Scale: " + statusLabelScale + " = " + sceneBox.getWidth() + " / " + fbox.getWidth() + ", " + fbox);
150
151 statusLabel = new Label(options.renderModes, fontStatus, "Nothing there yet");
152 statusLabel.setScale(statusLabelScale, statusLabelScale, 1f);
153 statusLabel.setColor(0.1f, 0.1f, 0.1f, 1.0f);
154 statusLabel.moveTo(sceneBox.getMinX(), sceneBox.getMinY() + statusLabelScale * (fontStatus.getMetrics().getLineGap() - fontStatus.getMetrics().getDescent()), 0f);
155 scene.addShape(statusLabel);
156 }
157
158 final String originalText = "GraphUI & JOGL, Resolution Agnostic Curve Rendering @ GPU via OpenGL® on Java™";
159 // String originalText = "JOGL, Java™ Binding for the OpenGL® API";
160
161 //
162 // Compute the metric animation values -> shape obj-velocity
163 //
164 float req_dur_s = 0f;
165 float req_velocity = 0f;
166 final float init_velocity = 2000/1e3f; // [m]/[s]
167
168 final float pixPerMM, dpiV;
169 {
170 final float[] tmp = window.getPixelsPerMM(new float[2]);
171 pixPerMM = tmp[0]; // [px]/[mm]
172 final float[] sDPI = MonitorDevice.perMMToPerInch( tmp );
173 dpiV = sDPI[1];
174 }
175
176 do {
177 final AABBox fbox = font.getGlyphBounds(originalText);
178 final float fontScale = sceneBox.getWidth() / fbox.getWidth();
179 System.err.println("FontScale: "+fontScale+" = "+sceneBox.getWidth()+" / "+fbox.getWidth());
180 destText.setScale(fontScale, fontScale, 1f);
181 movingGlyph.setScale(fontScale, fontScale, 1f);
182
183 destText.moveTo(sceneBox.getMinX(), 0f, 0f);
184
185 final long t0_us = Clock.currentNanos() / 1000; // [us]
186 float exp_total_dur_s = 0f;
187 float total_dist_m = 0f;
188 for(int idx = 0; idx < originalText.length() && window.isNativeValid(); ++idx ) {
189 boolean skipChar = false;
190 final String[] movingChar = { null };
191 do {
192 movingChar[0] = originalText.substring(idx, idx+1);
193 if( Character.isWhitespace(movingChar[0].charAt(0)) ) {
194 destText.setText(destText.getText() + movingChar[0]);
195 ++idx;
196 skipChar = true;
197 } else {
198 skipChar = false;
199 }
200 } while( skipChar && idx < originalText.length() );
201 if( movingChar[0].isEmpty() ) {
202 break; // bail
203 }
204 // sync point
205 destText.validate(hasGLP);
206 movingGlyph.setText(hasGLP, movingChar[0]);
207 final float start_pos = sceneBox.getMaxX() - movingGlyph.getScaledWidth();
208 final float end_pos = sceneBox.getMinX() + ( destText.getText().length() == 0 ? 0 : destText.getScaledWidth() );
209 movingGlyph.moveTo(start_pos, 0f, 0f);
210
211 final PMVMatrix4f pmv = new PMVMatrix4f();
212 final int[] destTextSizePx = destText.getSurfaceSize(scene, pmv, new int[2]); // [px]
213 final int[] movingGlyphSizePx = movingGlyph.getSurfaceSize(scene, pmv, new int[2]); // [px]
214 final float[] movingGlyphPixPerShapeUnit = movingGlyph.getPixelPerShapeUnit(movingGlyphSizePx, new float[2]); // [px]/[shapeUnit]
215
216 final float dist_px = scene.getWidth() - movingGlyphSizePx[0]; // [px]
217 final float dist_m = dist_px/pixPerMM/1e3f; // [m]
218 final float exp_dur_s = dist_m / init_velocity; // [s]
219 total_dist_m += dist_m;
220 if( 0 == idx ) {
221 exp_total_dur_s = ( exp_dur_s * originalText.length() ) / 2f; // Gauss'ian sum estimate
222 req_dur_s = ( req_total_dur_s * 2f ) / originalText.length();
223 req_velocity = dist_m / req_dur_s;
224 // req_dur_s = exp_dur_s;
225 // req_velocity = init_velocity;
226 }
227 final float velocity_px = req_velocity * 1e3f * pixPerMM; // [px]/[s]
228 final float velocity_obj = velocity_px / movingGlyphPixPerShapeUnit[0]; // [shapeUnit]/[s]
229
230 if( 0 == idx ) {
231 System.err.println();
232 System.err.printf("DestText: %d x %d [pixel], %s%n", destTextSizePx[0], destTextSizePx[1], destText.getText());
233 System.err.printf("MovingGl: %d x %d [pixel], %.4f px/su, %s%n", movingGlyphSizePx[0], movingGlyphSizePx[1], movingGlyphPixPerShapeUnit[0], movingGlyph.getText());
234 // System.err.printf("Shape: %s%n", movingGlyph);
235 System.err.println();
236 System.err.printf("Distance: %.0f pixel @ %.3f px/mm, %.3f mm%n", dist_px, pixPerMM, dist_m*1e3f);
237 System.err.printf("Velocity: init %.3f mm/s, req %.3f mm/s, %.3f px/s, %.6f obj/s, duration exp %.3f s, req %.3f s%n",
238 init_velocity*1e3f, req_velocity*1e3f, velocity_px, velocity_obj, exp_dur_s, req_dur_s);
239 // System.err.println();
240 // System.err.printf("Path: start %.4f, end %.4f, pos %.5f%n", start_pos, end_pos, movingGlyph.getPosition()[0]);
241 }
242
243 final long t1_us = Clock.currentNanos() / 1000; // [us]
244 final long[] t2_us = { t1_us };
245 while( movingGlyph.getPosition().x() > end_pos && window.isNativeValid() ) {
246 // Move on GL thread to have vsync for free
247 // Otherwise we would need to employ a sleep(..) w/ manual vsync
248 final long[] t3_us = { 0 };
249 window.invoke(true, (drawable) -> {
250 t3_us[0] = Clock.currentNanos() / 1000;
251 final float dt_s = ( t3_us[0] - t2_us[0] ) / 1e6f;
252 final float dx = -1f * velocity_obj * dt_s; // [shapeUnit]
253 movingGlyph.move(dx, 0f, 0f);
254 final String text = String.format("%s, anim-duration %.1f s",
255 scene.getStatusText(drawable, options.renderModes, dpiV), req_total_dur_s);
256 statusLabel.setText(text);
257 return true;
258 });
259 t2_us[0] = t3_us[0];
260 }
261 if( 0 == idx ) {
262 final float has_dur_s = ( ( Clock.currentNanos() / 1000 ) - t1_us ) / 1e6f; // [us]
263 System.err.printf("Actual char travel-duration %.3f s, %.3f mm/s, delay exp %.3f s, req %.3f%n",
264 has_dur_s, (dist_m/has_dur_s)*1e3f, has_dur_s-exp_dur_s, has_dur_s-req_dur_s);
265 }
266 destText.setText( new StringBuilder(destText.getText()).append(movingGlyph.getText()) );
267 movingGlyph.setText("");
268 }
269 final float has_dur_s = ( ( Clock.currentNanos() / 1000 ) - t0_us ) / 1e6f; // [us]
270 System.err.printf("Text travel-duration %.3f s, dist %.3f mm, %.3f mm/s, %d chars, %.3f s/char; Exp %.3f s, delay %.3f s, Req %.3f s, delay %.3f s%n",
271 has_dur_s, total_dist_m*1e3f, (total_dist_m/has_dur_s)*1e3f, originalText.length(), has_dur_s / originalText.length(),
272 exp_total_dur_s, has_dur_s - exp_total_dur_s,
273 req_total_dur_s, has_dur_s - req_total_dur_s);
274 try { Thread.sleep(1000); } catch (final InterruptedException e1) { }
275 destText.setText("");
276 if( autoSpeed > 0 ) {
277 if( req_total_dur_s > 3f ) {
278 req_total_dur_s -= 3f;
279 } else {
280 req_total_dur_s += 3f;
281 autoSpeed = -1;
282 }
283 } else if( autoSpeed < 0 ) {
284 if( req_total_dur_s < 10f ) {
285 req_total_dur_s += 3f;
286 } else {
287 req_total_dur_s -= 3f;
288 autoSpeed = 1;
289 }
290 }
291 } while ( options.keepRunning && window.isNativeValid() );
292 if( !options.keepRunning ) {
293 window.destroy();
294 }
295 }
296}
Abstract Outline shape representation define the method an OutlineShape(s) is bound and rendered.
Definition: Region.java:62
static final int VBAA_RENDERING_BIT
Rendering-Mode bit for Region.
Definition: Region.java:115
The optional property jogamp.graph.font.ctor allows user to specify the FontConstructor implementatio...
static final FontSet get(final int font)
GraphUI Scene.
Definition: Scene.java:102
void addShape(final Shape s)
Adds a Shape.
Definition: Scene.java:287
final void setClearParams(final float[] clearColor, final int clearMask)
Sets the clear parameter for glClearColor(..) and glClear(..) to be issued at display(GLAutoDrawable)...
Definition: Scene.java:221
int setAAQuality(final int v)
Sets RegionRenderer#setAAQuality(int).
Definition: Scene.java:383
void waitUntilDisplayed()
Blocks until first display(GLAutoDrawable) has completed after construction or dispose(GLAutoDrawable...
Definition: Scene.java:584
int getWidth()
Returns the getViewport()'s width, set after initial reshape(GLAutoDrawable, int, int,...
Definition: Scene.java:774
AABBox getBounds(final PMVMatrix4f pmv, final Shape shape)
Returns AABBox dimension of given Shape from this container's perspective, i.e.
Definition: Scene.java:676
synchronized void attachInputListenerTo(final GLWindow window)
Definition: Scene.java:246
String getStatusText(final GLAutoDrawable glad, final int renderModes, final float dpi)
Return a formatted status string containing avg fps and avg frame duration.
Definition: Scene.java:1381
Shape setColor(final float r, final float g, final float b, final float a)
Set base color.
Definition: Shape.java:1389
final Shape move(final float dtx, final float dty, final float dtz)
Move about scaled distance.
Definition: Shape.java:557
final Shape setScale(final Vec3f s)
Set scale factor to given scale.
Definition: Shape.java:641
final Shape moveTo(final float tx, final float ty, final float tz)
Move to scaled position.
Definition: Shape.java:543
final float getScaledWidth()
Returns the scaled width of the bounding AABBox for this shape.
Definition: Shape.java:745
final Vec3f getPosition()
Returns position Vec3f reference, i.e.
Definition: Shape.java:587
final float[] getPixelPerShapeUnit(final int[] shapeSizePx, final float[] pixPerShape)
Retrieve pixel per scaled shape-coordinate unit, i.e.
Definition: Shape.java:1165
final Shape validate(final GL2ES2 gl)
Validates the shape's underlying GLRegion.
Definition: Shape.java:850
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
A GraphUI text label GraphShape.
Definition: Label.java:50
boolean setText(final CharSequence text)
Set the text to be rendered.
Definition: Label.java:94
CharSequence getText()
Returns the label text.
Definition: Label.java:85
Axis Aligned Bounding Box.
Definition: AABBox.java:54
final float getWidth()
Definition: AABBox.java:879
PMVMatrix4f implements the basic computer graphics Matrix4f pack using projection (P),...
Visual output device, i.e.
static float[] perMMToPerInch(final float[] ppmm)
Converts [1/mm] to [1/inch] in place.
NEWT Window events are provided for notification purposes ONLY.
An implementation of GLAutoDrawable and Window interface, using a delegated Window instance,...
Definition: GLWindow.java:121
final int getSurfaceHeight()
Returns the height of this GLDrawable's surface client area in pixel units.
Definition: GLWindow.java:466
final void setTitle(final String title)
Definition: GLWindow.java:297
final float[] getPixelsPerMM(final float[] ppmmStore)
Returns the pixels per millimeter of this window's NativeSurface according to the main monitor's curr...
Definition: GLWindow.java:520
final int getSurfaceWidth()
Returns the width of this GLDrawable's surface client area in pixel units.
Definition: GLWindow.java:461
final void setSize(final int width, final int height)
Sets the size of the window's client area in window units, excluding decorations.
Definition: GLWindow.java:625
final void setVisible(final boolean visible)
Calls setVisible(true, visible), i.e.
Definition: GLWindow.java:615
final void addWindowListener(final WindowListener l)
Appends the given com.jogamp.newt.event.WindowListener to the end of the list.
Definition: GLWindow.java:882
final void destroy()
Destroys all resources associated with this GLAutoDrawable, inclusive the GLContext.
Definition: GLWindow.java:605
static GLWindow create(final GLCapabilitiesImmutable caps)
Creates a new GLWindow attaching a new Window referencing a new default Screen and default Display wi...
Definition: GLWindow.java:169
Specifies a set of OpenGL capabilities.
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
Res independent Shape, Scene attached to GLWindow showing simple linear Shape movement.
static void main(final String[] args)
int graphAASamples
Sample count for Graph Region AA render-modes: Region#VBAA_RENDERING_BIT or Region#MSAA_RENDERING_BIT...
int graphAAQuality
Pass2 AA-quality rendering for Graph Region AA render-modes: VBAA_RENDERING_BIT.
static void waitForKey(final String preMessage)
Definition: MiscUtils.java:167
final synchronized void add(final GLAutoDrawable drawable)
Adds a drawable to this animator's list of rendering drawables.
final void setUpdateFPSFrames(final int frames, final PrintStream out)
final synchronized boolean start()
Starts this animator, if not running.
Definition: Animator.java:344
final synchronized boolean stop()
Stops this animator.
Definition: Animator.java:368
float getDescent()
Distance from baseline of lowest descender, a negative value.
float getLineGap()
Typographic line gap, a positive value.
Interface wrapper for font implementation.
Definition: Font.java:60
String getFullFamilyName()
Shall return the family and subfamily name, separated a dash.
AABBox getGlyphBounds(final CharSequence string)
Try using getGlyphBounds(CharSequence, AffineTransform, AffineTransform) to reuse AffineTransform ins...
boolean invoke(boolean wait, GLRunnable glRunnable)
Enqueues a one-shot GLRunnable, which will be executed within the next display() call after all regis...
void addGLEventListener(GLEventListener listener)
Adds the given listener to the end of this drawable queue.
GLProfile getGLProfile()
Returns the GL profile you desire or used by the drawable.
GLCapabilitiesImmutable getChosenGLCapabilities()
Fetches the GLCapabilitiesImmutable corresponding to the chosen OpenGL capabilities (pixel format / v...
static final int GL_DEPTH_BUFFER_BIT
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_DEPTH_BUFFER_BIT" wit...
Definition: GL.java:738