JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
TestTextRendererNEWT10.java
Go to the documentation of this file.
1/**
2 * Copyright 2011-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.test.junit.graph;
29
30import java.io.File;
31import java.io.IOException;
32import java.net.URL;
33import java.util.Locale;
34
35import com.jogamp.opengl.GL;
36import com.jogamp.opengl.GL2ES2;
37import com.jogamp.opengl.GLAnimatorControl;
38import com.jogamp.opengl.GLAutoDrawable;
39import com.jogamp.opengl.GLCapabilities;
40import com.jogamp.opengl.GLCapabilitiesImmutable;
41import com.jogamp.opengl.GLException;
42import com.jogamp.opengl.GLProfile;
43import com.jogamp.opengl.GLRunnable;
44
45import org.junit.Assert;
46import org.junit.FixMethodOrder;
47import org.junit.Test;
48import org.junit.runners.MethodSorters;
49
50import com.jogamp.common.os.Platform;
51import com.jogamp.graph.curve.Region;
52import com.jogamp.graph.curve.opengl.GLRegion;
53import com.jogamp.graph.curve.opengl.RegionRenderer;
54import com.jogamp.graph.font.Font;
55import com.jogamp.graph.font.FontFactory;
56import com.jogamp.graph.font.FontScale;
57import com.jogamp.junit.util.JunitTracer;
58import com.jogamp.newt.Window;
59import com.jogamp.newt.opengl.GLWindow;
60import com.jogamp.opengl.test.junit.util.MiscUtils;
61import com.jogamp.opengl.test.junit.util.UITestCase;
62import com.jogamp.opengl.util.Animator;
63import com.jogamp.opengl.util.GLReadBufferUtil;
64
65
66/**
67 * TestTextRendererNEWT10 Variant
68 * - Using listener derived from rudimentary TextRendererGLELBase, w/o much functionality but scaling ..
69 * - Type Rendering via TextRegionUtil, multiple
70 */
71@FixMethodOrder(MethodSorters.NAME_ASCENDING)
72public class TestTextRendererNEWT10 extends UITestCase {
73 static final boolean DEBUG = false;
74 static final boolean TRACE = false;
75 static long Duration = 2000; // ms
76 static int win_width = 1024;
77 static int win_height = 640;
78 static boolean WaitStartEnd = false;
79 static boolean TextAnim = false;
80 static int SceneMSAASamples = 0;
81 static int GraphVBAASamples = 0;
82 static int GraphMSAASamples = 0;
83 static boolean ManualTest = false;
84 static int SwapInterval = 1;
85
86 static String fontFileName = null;
87 static URL fontURL = null;
88 static int fontSet = 0;
89 static int fontFamily = 0;
90 static int fontStylebits = 0;
91 static float fontSizeFixed = 14f;
92
93 static int atoi(final String a) {
94 try {
95 return Integer.parseInt(a);
96 } catch (final Exception ex) { throw new RuntimeException(ex); }
97 }
98
99 public static void main(final String args[]) throws IOException {
100 ManualTest = args.length > 0;
101 for(int i=0; i<args.length; i++) {
102 if(args[i].equals("-time")) {
103 i++;
104 Duration = atoi(args[i]);
105 } else if(args[i].equals("-width")) {
106 i++;
107 win_width = atoi(args[i]);
108 } else if(args[i].equals("-height")) {
109 i++;
110 win_height = atoi(args[i]);
111 } else if(args[i].equals("-fontURL")) {
112 i++;
113 fontURL = new URL(args[i]);
114 } else if(args[i].equals("-fontFile")) {
115 i++;
116 fontFileName = args[i];
117 } else if(args[i].equals("-fontSet")) {
118 i++;
119 fontSet = atoi(args[i]);
120 } else if(args[i].equals("-fontFamily")) {
121 i++;
122 fontFamily = atoi(args[i]);
123 } else if(args[i].equals("-fontStyle")) {
124 i++;
125 fontStylebits = atoi(args[i]);
126 } else if(args[i].equals("-fontSize")) {
127 i++;
128 fontSizeFixed = atoi(args[i]);
129 } else if(args[i].equals("-smsaa")) {
130 i++;
131 SceneMSAASamples = atoi(args[i]);
132 } else if(args[i].equals("-gmsaa")) {
133 i++;
134 GraphMSAASamples = atoi(args[i]);
135 } else if(args[i].equals("-gvbaa")) {
136 i++;
137 GraphVBAASamples = atoi(args[i]);
138 } else if(args[i].equals("-textAnim")) {
139 TextAnim = true;
140 } else if(args[i].equals("-vsync")) {
141 i++;
142 SwapInterval = MiscUtils.atoi(args[i], SwapInterval);
143 } else if(args[i].equals("-wait")) {
144 WaitStartEnd = true;
145 }
146 }
147 System.err.println("Font [set "+fontSet+", family "+fontFamily+", style "+fontStylebits+", size "+fontSizeFixed+"], fontFileName "+fontFileName);
148 System.err.println("Scene MSAA Samples "+SceneMSAASamples);
149 System.err.println("Graph MSAA Samples "+GraphMSAASamples);
150 System.err.println("Graph VBAA Samples "+GraphVBAASamples);
151 System.err.println("swapInterval "+SwapInterval);
152 final String tstname = TestTextRendererNEWT10.class.getName();
153 org.junit.runner.JUnitCore.main(tstname);
154 }
155
156 static void sleep() {
157 sleep(Duration);
158 }
159 static void sleep(final long d) {
160 try {
161 System.err.println("** new frame ** (sleep: "+d+"ms)");
162 Thread.sleep(d);
163 } catch (final InterruptedException ie) {}
164 }
165
166 static void destroyWindow(final GLWindow window) {
167 if(null!=window) {
168 window.destroy();
169 }
170 }
171
172 static GLWindow createWindow(final String title, final GLCapabilitiesImmutable caps, final int width, final int height) {
173 Assert.assertNotNull(caps);
174
175 final GLWindow window = GLWindow.create(caps);
176 window.setSize(width, height);
177 window.setPosition(10, 10);
178 window.setTitle(title);
179 Assert.assertNotNull(window);
180 window.setVisible(true);
181
182 return window;
183 }
184
185 @Test
186 public void test00Manual() throws InterruptedException {
187 if( ManualTest ) {
188 testImpl(SceneMSAASamples, GraphMSAASamples, GraphVBAASamples);
189 }
190 }
191 @Test
192 public void test00SceneNoAA() throws InterruptedException {
193 if( !ManualTest ) {
194 testImpl(0, 0, 0);
195 }
196 }
197 @Test
198 public void test01SceneMSAA04() throws InterruptedException {
199 if( !ManualTest ) {
200 testImpl(4, 0, 0);
201 }
202 }
203 @Test
204 public void test02GraphMSAA04() throws InterruptedException {
205 if( !ManualTest ) {
206 testImpl(0, 4, 0);
207 }
208 }
209 @Test
210 public void test03GraphVBAA04() throws InterruptedException {
211 if( !ManualTest ) {
212 testImpl(0, 0, 4);
213 }
214 }
215
216 public void testImpl(final int sceneMSAASamples, final int graphMSAASamples, final int graphVBAASamples) throws InterruptedException {
218 final GLCapabilities caps = new GLCapabilities(glp);
219 caps.setAlphaBits(4);
220 if( 0 < sceneMSAASamples ) {
221 caps.setSampleBuffers(true);
222 caps.setNumSamples(sceneMSAASamples);
223 }
224 System.err.println("Requested: "+caps+", graph[msaaSamples "+graphMSAASamples+", vbaaSamples "+graphVBAASamples+"]");
225
226 final GLWindow window = createWindow("text-gvbaa"+graphVBAASamples+"-gmsaa"+graphMSAASamples+"-smsaa"+sceneMSAASamples, caps, win_width, win_height);
227
228 window.display();
229 System.err.println("Chosen: "+window.getChosenGLCapabilities());
230 if( WaitStartEnd ) {
231 JunitTracer.waitForKey("Start");
232 }
233
234 final int renderModes, sampleCount;
235 if( graphVBAASamples > 0 ) {
236 renderModes = Region.VBAA_RENDERING_BIT;
237 sampleCount = graphVBAASamples;
238 } else if ( graphMSAASamples > 0 ) {
239 renderModes = Region.MSAA_RENDERING_BIT;
240 sampleCount = graphMSAASamples;
241 } else {
242 renderModes = 0;
243 sampleCount = 0;
244 }
245 final TextRendererGLEL textGLListener = new TextRendererGLEL(glp, renderModes, sampleCount);
246 System.err.println(textGLListener.getFontInfo());
247
248 window.addGLEventListener(textGLListener);
249
250 final Animator anim = new Animator(0 /* w/o AWT */);
251 anim.add(window);
252 anim.start();
253 anim.setUpdateFPSFrames(60, null);
254 sleep();
255 window.invoke(true, new GLRunnable() {
256 @Override
257 public boolean run(final GLAutoDrawable drawable) {
258 try {
259 textGLListener.printScreen(renderModes, drawable, "./", "TestTextRendererNEWT00-snap"+screenshot_num, false);
260 screenshot_num++;
261 } catch (final Exception e) {
262 e.printStackTrace();
263 }
264 return true;
265 }
266 });
267 anim.stop();
268 if( WaitStartEnd ) {
269 JunitTracer.waitForKey("Stop");
270 }
271 destroyWindow(window);
272 }
273 int screenshot_num = 0;
274
275 static final String textX2 =
276 "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec sapien tellus. \n"+
277 "Ut purus odio, rhoncus sit amet commodo eget, ullamcorper vel urna. Mauris ultricies \n"+
278 "quam iaculis urna cursus ornare. Nullam ut felis a ante ultrices ultricies nec a elit. \n"+
279 "In hac habitasse platea dictumst. Vivamus et mi a quam lacinia pharetra at venenatis est.\n"+
280 "Morbi quis bibendum nibh. Donec lectus orci, sagittis in consequat nec, volutpat nec nisi.\n"+
281 "Donec ut dolor et nulla tristique varius. In nulla magna, fermentum id tempus quis, semper \n"+
282 "in lorem. Maecenas in ipsum ac justo scelerisque sollicitudin. Quisque sit amet neque lorem,\n" +
283 "-------Press H to change text---------\n";
284
285 private static final class TextRendererGLEL extends TextRendererGLELBase {
286 private final GLReadBufferUtil screenshot;
287 private final GLRegion regionFPS, regionFPSAnim;
288 final Font font;
289 final float fontSizeMin, fontSizeMax;
290 private long t0;
291 float fontSizeAnim, fontSizeDelta;
292 float dpiV, ppmmV;
293
294 TextRendererGLEL(final GLProfile glp, final int renderModes, final int sampleCount) {
295 super(renderModes, new int[] { sampleCount });
296 setRendererCallbacks(RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable);
297
298 regionFPS = GLRegion.create(glp, renderModes, null, 0, 0);
299 regionFPSAnim = GLRegion.create(glp, renderModes, null, 0, 0);
300 if( null != fontURL ) {
301 Font _font = null;
302 try {
303 _font = FontFactory.get(fontURL.openStream(), true);
304 } catch (final IOException e) {
305 e.printStackTrace();
306 }
307 font = _font;
308 } else if( null != fontFileName ) {
309 Font _font = null;
310 try {
311 _font = FontFactory.get(getClass(), fontFileName, false);
312 } catch (final IOException e) {
313 e.printStackTrace();
314 }
315 font = _font;
316 } else {
317 font = getFont(fontSet, fontFamily, fontStylebits);
318 }
319
320 staticRGBAColor[0] = 0.1f;
321 staticRGBAColor[1] = 0.1f;
322 staticRGBAColor[2] = 0.1f;
323 staticRGBAColor[3] = 1.0f;
324
325 this.screenshot = new GLReadBufferUtil(false, false);
326 // fontSizeMin = Math.max(8, fontSizeFixed-5);
327 fontSizeMin = fontSizeFixed;
328 fontSizeMax = fontSizeFixed+8;
329 fontSizeAnim = fontSizeFixed;
330 fontSizeDelta = 0.01f;
331 }
332
333 @Override
334 public void init(final GLAutoDrawable drawable) {
335 super.init(drawable);
336 final GL2ES2 gl = drawable.getGL().getGL2ES2();
337 gl.setSwapInterval(SwapInterval);
338 gl.glEnable(GL.GL_DEPTH_TEST);
339 t0 = Platform.currentTimeMillis();
340
341 final Window win = (Window)drawable.getUpstreamWidget();
342 final float[] pixelsPerMM = win.getPixelsPerMM(new float[2]);
343 final float[] dotsPerInch = FontScale.ppmmToPPI(pixelsPerMM, new float[2]);
344 dpiV = dotsPerInch[1];
345 ppmmV = pixelsPerMM[1];
346 System.err.println(getFontInfo());
347 System.err.println("fontSize "+fontSizeFixed+", dotsPerMM "+pixelsPerMM[0]+"x"+pixelsPerMM[1]+", dpi "+dotsPerInch[0]+"x"+dotsPerInch[1]+", pixelSize "+FontScale.toPixels(fontSizeFixed, dotsPerInch[1] /* dpi display */));
348 }
349
350 @Override
351 public void dispose(final GLAutoDrawable drawable) {
352 final GL2ES2 gl = drawable.getGL().getGL2ES2();
353 screenshot.dispose(gl);
354 regionFPS.destroy(gl);
355 regionFPSAnim.destroy(gl);
356 super.dispose(drawable);
357 }
358
359 public void printScreen(final int renderModes, final GLAutoDrawable drawable, final String dir, final String objName, final boolean exportAlpha) throws GLException, IOException {
360 final String modeS = Region.getRenderModeString(renderModes);
361 final String bname = String.format((Locale)null, "%s-msaa%02d-fontsz%02.1f-%03dx%03d-%s%04d", objName,
362 drawable.getChosenGLCapabilities().getNumSamples(),
363 fontSizeFixed, drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), modeS, vbaaSampleCount[0]);
364 final String filename = dir + bname +".png";
365 if(screenshot.readPixels(drawable.getGL(), false)) {
366 screenshot.write(new File(filename));
367 }
368 }
369
370 String getFontInfo() {
371 final float pixelSize = FontScale.toPixels(fontSizeFixed, dpiV);
372 final float mmSize = pixelSize / ppmmV;
373 final int unitsPerEM = font.getMetrics().getUnitsPerEM();
374 return String.format("Resolution dpiV %.2f, %.2f px/mm%nFont %s, unitsPerEM %d, size %.2f pt %.2f px %2f mm%n",
375 dpiV, ppmmV,
376 font.getFullFamilyName(),unitsPerEM, fontSizeFixed, pixelSize, mmSize);
377 }
378
379 @Override
380 public void display(final GLAutoDrawable drawable) {
381 final GL2ES2 gl = drawable.getGL().getGL2ES2();
382
383 gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
384 gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
385
386 final GLAnimatorControl anim = drawable.getAnimator();
387 final float lfps = null != anim ? anim.getLastFPS() : 0f;
388 final float tfps = null != anim ? anim.getTotalFPS() : 0f;
389
390 // Note: MODELVIEW is from [ 0 .. height ]
391
392 final long t1 = Platform.currentTimeMillis();
393
394 // final float fontSize = TestTextRendererNEWT00.fontSize;
395
396 fontSizeAnim += fontSizeDelta;
397 if( fontSizeMin >= fontSizeAnim || fontSizeAnim >= fontSizeMax ) {
398 fontSizeDelta *= -1f;
399 }
400
401 final float pixelSize = FontScale.toPixels(fontSizeFixed, dpiV);
402 final float pixelSizeAnim = FontScale.toPixels(fontSizeAnim, dpiV);
403
404 final String modeS = Region.getRenderModeString(renderModes);
405
406 if( false ) {
407 // renderString(drawable, font, pixelSize, "I - / H P 7 0", 0, 0, 0, 0, -1000f, true);
408 // renderString(drawable, font, pixelSize, "A M > } ] ", 0, 0, 0, 0, -1000f, true);
409 // renderString(drawable, font, pixelSize, "M", 0, 0, 0, 0, -1000f, true);
410 // renderString(drawable, font, pixelSize, "0 6 9 a b O Q A M > } ] ", 0, 0, 0, 0, -1000f, true);
411 // renderString(drawable, font, pixelSize, "012345678901234567890123456789", 0, 0, 0, -1000, true);
412 // renderString(drawable, font, pixelSize, textX2, 0, 0, 0, 0, -1000f, true);
413 // renderString(drawable, font, pixelSize, text1, 0, 0, 0, -1000f, regionFPS); // no-cache
414 final String text1 = lfps+" / "+tfps+" fps, vsync "+gl.getSwapInterval()+", elapsed "+(t1-t0)/1000.0+
415 " s, fontSize "+fontSizeFixed+", msaa "+drawable.getChosenGLCapabilities().getNumSamples()+
416 ", "+modeS+"-samples "+vbaaSampleCount[0];
417 renderString(drawable, font, pixelSize, text1, 0, 0, 0, 0, -1000, regionFPS.clear(gl)); // no-cache
418 } else {
419 final String text1 = String.format("%03.1f/%03.1f fps, vsync %d, elapsed %4.1f s, fontSize %2.2f, msaa %d, %s-samples %d",
420 lfps, tfps, gl.getSwapInterval(), (t1-t0)/1000.0, fontSizeFixed,
421 drawable.getChosenGLCapabilities().getNumSamples(), modeS, vbaaSampleCount[0]);
422 renderString(drawable, font, pixelSize, getFontInfo(), 0, 0, 0, 0, -1000, true);
423 renderString(drawable, font, pixelSize, "012345678901234567890123456789", 0, 0, 0, -1000, true);
424 renderString(drawable, font, pixelSize, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 0, 0, 0, -1000, true);
425 renderString(drawable, font, pixelSize, "Hello World", 0, 0, 0, -1000, true);
426 renderString(drawable, font, pixelSize, "4567890123456", 4, 0, 0, -1000, true);
427 renderString(drawable, font, pixelSize, "I like JogAmp", 4, 0, 0, -1000, true);
428 renderString(drawable, font, pixelSize, "Hello World", 0, 0, 0, -1000, true);
429 renderString(drawable, font, pixelSize, textX2, 0, 0, 0, -1000, true);
430 renderString(drawable, font, pixelSize, text1, 0, 0, 0, -1000, regionFPS.clear(gl)); // no-cache
431 if( TextAnim ) {
432 renderString(drawable, font, pixelSizeAnim, text1, 0, 0, 0, -1000, regionFPSAnim.clear(gl)); // no-cache
433 }
434 }
435 } };
436
437}
Abstract Outline shape representation define the method an OutlineShape(s) is bound and rendered.
Definition: Region.java:62
static final int MSAA_RENDERING_BIT
Rendering-Mode bit for Region.
Definition: Region.java:95
static final int VBAA_RENDERING_BIT
Rendering-Mode bit for Region.
Definition: Region.java:115
A GLRegion is the OGL binding of one or more OutlineShapes Defined by its vertices and generated tria...
Definition: GLRegion.java:70
final GLRegion clear(final GL2ES2 gl)
Clears all buffers, i.e.
Definition: GLRegion.java:436
final void destroy(final GL2ES2 gl)
Delete and clear the associated OGL objects.
Definition: GLRegion.java:460
static GLRegion create(final GLProfile glp, int renderModes, final TextureSequence colorTexSeq, final int pass2TexUnit, final int initialVerticesCount, final int initialIndicesCount)
Create a GLRegion using the passed render mode.
Definition: GLRegion.java:109
void setAlphaBits(final int alphaBits)
Sets the number of bits requested for the color buffer's alpha component.
An implementation of GLAutoDrawable and Window interface, using a delegated Window instance,...
Definition: GLWindow.java:121
Specifies a set of OpenGL capabilities.
void setNumSamples(final int numSamples)
If sample buffers are enabled, indicates the number of buffers to be allocated.
void setSampleBuffers(final boolean enable)
Defaults to false.
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
static final String GL2ES2
The intersection of the desktop GL3, GL2 and embedded ES2 profile.
Definition: GLProfile.java:594
static GLProfile get(final AbstractGraphicsDevice device, String profile)
Returns a GLProfile object.
void testImpl(final int sceneMSAASamples, final int graphMSAASamples, final int graphVBAASamples)
static int atoi(final String str, final int def)
Definition: MiscUtils.java:57
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
Utility to read out the current FB to TextureData, optionally writing the data back to a texture obje...
void write(final File dest)
Write the TextureData filled by readPixels(GLAutoDrawable, boolean) to file.
boolean readPixels(final GL gl, final boolean mustFlipVertically)
Read the drawable's pixels to TextureData and Texture, if requested at construction.
int getUnitsPerEM()
Returns the font's units per EM from the 'head' table.
Interface wrapper for font implementation.
Definition: Font.java:60
String getFullFamilyName()
Shall return the family and subfamily name, separated a dash.
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
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.
GLCapabilitiesImmutable getChosenGLCapabilities()
Fetches the GLCapabilitiesImmutable corresponding to the chosen OpenGL capabilities (pixel format / v...