JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
MediaButton.java
Go to the documentation of this file.
1/**
2 * Copyright 2014-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.shapes;
29
30import com.jogamp.opengl.GL;
31import com.jogamp.opengl.GL2ES2;
32import com.jogamp.opengl.GLProfile;
33
34import java.util.ArrayList;
35import java.util.List;
36
37import com.jogamp.common.av.AudioSink;
38import com.jogamp.common.util.InterruptSource;
39import com.jogamp.common.util.StringUtil;
40import com.jogamp.graph.curve.Region;
41import com.jogamp.graph.curve.opengl.RegionRenderer;
42import com.jogamp.graph.font.Font;
43import com.jogamp.graph.font.FontFactory;
44import com.jogamp.graph.ui.GraphShape;
45import com.jogamp.graph.ui.layout.Alignment;
46import com.jogamp.math.Vec2f;
47import com.jogamp.math.Vec4f;
48import com.jogamp.math.geom.AABBox;
49import com.jogamp.math.util.PMVMatrix4f;
50import com.jogamp.opengl.util.av.SubTextEvent;
51import com.jogamp.opengl.util.av.SubBitmapEvent;
52import com.jogamp.opengl.util.av.SubtitleEvent;
53import com.jogamp.opengl.util.av.SubtitleEventListener;
54import com.jogamp.opengl.util.texture.ImageSequence;
55import com.jogamp.opengl.util.av.CodecID;
56import com.jogamp.opengl.util.av.GLMediaPlayer;
57import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener;
58import com.jogamp.opengl.util.av.GLMediaPlayer.StreamException;
59
60/**
61 * A GraphUI {@link GLMediaPlayer} based {@link TexSeqButton} {@link GraphShape}.
62 * <p>
63 * GraphUI is GPU based and resolution independent.
64 * </p>
65 * <p>
66 * This button is rendered with a round oval shape.
67 * To render it rectangular, {@link #setCorner(float)} to zero.
68 * </p>
69 * <p>
70 * Default colors (toggle-on is full color):
71 * - non-toggle: 1 * color
72 * - pressed: 0.9 * color
73 * - toggle-off: 0.8 * color
74 * - toggle-on: 1.0 * color
75 * </p>
76 */
77public class MediaButton extends TexSeqButton {
78 private static final boolean DEBUG_SUB = false;
79 private static final boolean DEBUG_SUB_LAYOUT = false;
80 private boolean verbose = false;
81
82 private Font subFont;
83 private Font subFallbackFont;
84 private final Label subLabel;
85 private final float subZOffset;
86 private boolean subEnabled;
87 private float subLineHeightPct;
88 private float subLineDY;
89 private Alignment subAlignment;
90 private final Rectangle subBlend;
91 private final ImageButton subTexImg;
92
93 /** Default text/ASS subtitle line height percentage, {@value}. */
94 public static final float DEFAULT_ASS_SUB_HEIGHT = 0.075f;
95 /** Default text/ASS subtitle y-axis offset to bottom in line-height percentage, {@value}. */
96 public static final float DEFAULT_ASS_SUB_POS = 0.25f;
97 /** Default color for the text/ASS subtitles, defaults to RGBA {@code 1, 1, 1, 1}. */
98 public static final Vec4f DEFAULT_ASS_SUB_COLOR = new Vec4f( 1, 1, 1, 1 );
99 /** Default blending alpha (darkness) for the text/ASS subtitles, defaults to {@value}. */
100 public static final float DEFAULT_ASS_SUB_BLEND = 0.3f;
101 /** Default text/ASS subtitle alignment, defaults to {@link Alignment#CenterHoriz}. */
103
104 private static final float ASS_SUB_USED_WIDTH = 0.90f;
105 private static final float ASS_SUB_BLEND_ADDED_HEIGHT = 0.25f;
106 private static final int ASS_SUB_MAX_SPLIT_LINES = 4;
107
108
109 private SubtitleEvent drawLastSub;
110
111 private final List<SubtitleEvent> subEventQueue = new ArrayList<SubtitleEvent>();
112 private final Object subEventLock = new Object();
113
114 /** Constructs a {@link MediaButton} with {@link FontFactory#getDefaultFont()} for subtitles. */
115 public MediaButton(final int renderModes, final float width, final float height, final GLMediaPlayer mPlayer) {
116 this(renderModes, width, height, mPlayer, null);
117 }
118
119 /**
120 * Constructs a {@link MediaButton} prepared for using subtitles
121 * @param renderModes
122 * @param width
123 * @param height
124 * @param mPlayer
125 * @param subFont text/ASS subtitle font, pass {@code null} for {@link FontFactory#getDefaultFont()}.
126 * {@link FontFactory#getFallbackFont()} is used {@link Font#getBestCoverage(Font, Font, CharSequence) if providing a better coverage} of a Text/ASS subtitle line.
127 * @see #setSubtitleParams(Font, float, float, Alignment)
128 * @see #setSubtitleColor(Vec4f, float)
129 */
130 public MediaButton(final int renderModes, final float width, final float height, final GLMediaPlayer mPlayer, final Font subFont)
131 {
132 super(renderModes & ~Region.AA_RENDERING_MASK, width, height, mPlayer);
133
134 setColor(1.0f, 1.0f, 1.0f, 0.0f);
135 setPressedColorMod(0.9f, 0.9f, 0.9f, 0.7f);
136 setToggleOffColorMod(0.8f, 0.8f, 0.8f, 1.0f);
137 setToggleOnColorMod(1.0f, 1.0f, 1.0f, 1.0f);
138
139 mPlayer.setSubtitleEventListener(subEventListener);
140
142 this.subLabel = new Label(renderModes, this.subFont, "");
143 this.subZOffset = Button.DEFAULT_LABEL_ZOFFSET;
144 this.subLabel.moveTo(0, 0, subZOffset);
145 this.subBlend = new Rectangle(renderModes, 1f, 1f, 0f);
147
148 this.subTexImg = new ImageButton(renderModes, width, height, new ImageSequence(mPlayer.getTextureUnit(), true /* useBuildInTexLookup */));
149 this.subTexImg.setPerp().setToggleable(false).setDragAndResizable(false).setInteractive(false);
150 // this.subTexImg.setBorder(0.001f).setBorderColor(1, 1, 0, 1);
152 this.subTexImg.setARatioAdjustment(false);
153 this.drawLastSub = null;
154 }
155
156 /** Toggle enabling subtitle rendering */
157 public void setSubtitlesEnabled(final boolean v) {
158 subEnabled = v;
159 }
160
161 /**
162 * Sets text/ASS subtitle parameter, enabling subtitle rendering
163 * @param subFont text/ASS subtitle font, pass {@code null} for {@link FontFactory#getDefaultFont()}
164 * {@link FontFactory#getFallbackFont()} is used {@link Font#getBestCoverage(Font, Font, CharSequence) if providing a better coverage} of a Text/ASS subtitle line.
165 * @param subLineHeightPct text/ASS subtitle line height percentage, defaults to {@link #DEFAULT_ASS_SUB_HEIGHT}
166 * @param subLineDY text/ASS y-axis offset to bottom in line-height, defaults to {@link #DEFAULT_ASS_SUB_POS}
167 * @param subAlignment text/ASS subtitle alignment, defaults to {@link #DEFAULT_ASS_SUB_ALIGNMENT}
168 */
169 public void setSubtitleParams(final Font subFont, final float subLineHeightPct, final float subLineDY, final Alignment subAlignment) {
170 if( null != subFont ) {
171 this.subFont = subFont;
172 } else {
173 this.subFont = FontFactory.getDefaultFont();
174 }
175 this.subFallbackFont = FontFactory.getFallbackFont();
176 this.subLineHeightPct = subLineHeightPct;
177 this.subLineDY = subLineDY;
178 this.subAlignment = subAlignment;
179 this.subEnabled = true;
180 }
181 /**
182 * Sets text/ASS subtitle colors
183 * @param color color for the text/ASS, defaults to {@link #DEFAULT_ASS_SUB_COLOR}
184 * @param blend blending alpha (darkness), defaults to {@link #DEFAULT_ASS_SUB_BLEND}
185 */
186 public void setSubtitleColor(final Vec4f color, final float blend) {
187 this.subLabel.setColor( color );
188 this.subBlend.setColor( 0, 0, 0, blend );
189 }
190
191 public final SubtitleEventListener getSubEventListener() { return subEventListener; }
192 private final SubtitleEventListener subEventListener = new SubtitleEventListener() {
193 @Override
194 public void run(final SubtitleEvent e) {
195 synchronized( subEventLock ) {
196 subEventQueue.add(e);
197 if( DEBUG_SUB ) {
198 System.err.println("MediaButton: GOT #"+subEventQueue.size()+": "+e);
199 }
200 }
201 }
202 };
203
204 public MediaButton setVerbose(final boolean v) { verbose = v; return this; }
205
206 /**
207 * Add the default {@link GLMediaEventListener} to {@link #getGLMediaPlayer() this class's GLMediaPlayer}.
208 */
210 getGLMediaPlayer().addEventListener(defGLMediaEventListener);
211 return this;
212 }
213
215
216 public final AudioSink getAudioSink() { return getGLMediaPlayer().getAudioSink(); }
217
218 private final GLMediaEventListener defGLMediaEventListener = new GLMediaEventListener() {
219 @Override
220 public void attributesChanged(final GLMediaPlayer mp, final GLMediaPlayer.EventMask eventMask, final long when) {
221 if( verbose ) {
222 System.err.println("MediaButton AttributesChanges: "+eventMask+", when "+when);
223 System.err.println("MediaButton State: "+mp);
224 }
225 if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Init) ) {
226 clearSubtitleCache();
227 resetGL = true;
228 } else if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Uninit) ||
229 eventMask.isSet(GLMediaPlayer.EventMask.Bit.Play) ||
230 eventMask.isSet(GLMediaPlayer.EventMask.Bit.Seek) ||
231 eventMask.isSet(GLMediaPlayer.EventMask.Bit.SID) ) {
232 clearSubtitleCache();
234 } else if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Pause) ) {
235 clearSubtitleCacheButLast();
237 }
238 if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Size) ) {
239 // FIXME: mPlayer.resetGLState();
240 }
241 if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.EOS) ) {
242 new InterruptSource.Thread() {
243 @Override
244 public void run() {
245 // loop for-ever ..
246 mp.seek(0);
247 mp.resume();
248 } }.start();
249 } else if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Error) ) {
250 final StreamException se = mp.getStreamException();
251 if( null != se ) {
252 se.printStackTrace();
253 }
254 }
255 } };
256
257
258 @Override
259 protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) {
260 ((GLMediaPlayer)texSeq).stop();
261 ((GLMediaPlayer)texSeq).seek(0);
262 clearSubtitleCache();
263 }
264 @Override
265 protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) {
266 ((GLMediaPlayer)texSeq).stop();
267 clearSubtitleCache();
268 subTexImg.destroy(gl, renderer);
269 subLabel.destroy(gl, renderer);
270 subBlend.destroy(gl, renderer);
271 ((GLMediaPlayer)texSeq).destroy(gl);
272 }
273
274 volatile boolean resetGL = true;
275
276 @Override
277 protected void addShapeToRegion(final GLProfile glp, final GL2ES2 gl) {
278 super.addShapeToRegion(glp, gl);
279 }
280
281 @Override
282 protected final void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final Vec4f rgba) {
283 final GLMediaPlayer mPlayer = (GLMediaPlayer)texSeq;
284 if( resetGL ) {
285 resetGL = false;
286 try {
287 clearSubtitleCache();
288 mPlayer.initGL(gl);
289 if( null != region ) {
290 region.markShapeDirty(); // reset texture data
291 }
292 } catch (final Exception e) {
293 e.printStackTrace();
294 }
295 }
296 super.drawImpl0(gl, renderer, rgba);
297 if( subEnabled && GLMediaPlayer.STREAM_ID_NONE != mPlayer.getSID() ) {
298 drawSubtitle(gl, renderer);
299 }
300 if( GLMediaPlayer.State.Playing == mPlayer.getState() ) {
301 markStateDirty(); // keep on going
302 }
303 };
304 private final void clearSubtitleCache() {
305 synchronized( subEventLock ) {
306 final SubtitleEvent lastSub = drawLastSub;
307 drawLastSub = null;
308 if( null != lastSub ) {
309 lastSub.release();
310 }
311 subTexImg.getImageSequence().removeAllFrames();
312 for(final SubtitleEvent e : subEventQueue) {
313 e.release();
314 }
315 subEventQueue.clear();
316 if( DEBUG_SUB ) {
317 System.err.println("MediaButton.clearSubtitleCache: "+subEventQueue.size()+", last "+lastSub);
318 }
319 }
320 }
321 private final void clearSubtitleCacheButLast() {
322 synchronized( subEventLock ) {
323 final SubtitleEvent lastSub = drawLastSub;
324 for(int i=subEventQueue.size()-1; i>=0; --i) {
325 final SubtitleEvent e = subEventQueue.get(i);
326 if( lastSub != e ) {
327 e.release();
328 subEventQueue.remove(i);
329 }
330 }
331 if( DEBUG_SUB ) {
332 System.err.println("MediaButton.clearSubtitleCacheButLast: "+subEventQueue.size()+", last "+lastSub);
333 }
334 }
335 }
336 private final void drawSubtitle(final GL2ES2 gl, final RegionRenderer renderer) {
337 final GLMediaPlayer mPlayer = (GLMediaPlayer)texSeq;
338 final int pts = mPlayer.getPTS().getCurrent();
339
340 // Validate draw_lastSub timeout
341 SubtitleEvent lastSub = drawLastSub;
342 {
343 if( null != lastSub && lastSub.pts_end < pts ) {
344 if( DEBUG_SUB ) {
345 System.err.println("MediaButton: Drop.0: pts "+pts+", "+lastSub);
346 }
347 drawLastSub = null;
348 lastSub.release();
349 lastSub = null;
350 }
351 }
352 // Dequeue and earmark new subtitle in time.
353 // A new subtitle (empty as well) may simply replace an older one,
354 // allowing PGS subtitles to work (infinite end-time)
355 final SubtitleEvent sub;
356 final boolean newSub;
357 {
358 final SubtitleEvent gotSub;
359 synchronized( subEventLock ) {
360 if( subEventQueue.size() > 0 ) {
361 final SubtitleEvent e = subEventQueue.get(0);
362 if( e.pts_start <= pts && pts <= e.pts_end ) {
363 gotSub = e;
364 subEventQueue.remove(0);
365 } else if( e.pts_end < pts ) {
366 gotSub = null;
367 subEventQueue.remove(0);
368 e.release();
369 if( DEBUG_SUB ) {
370 System.err.println("MediaButton: Drop.1: pts "+pts+", "+e);
371 }
372 } else {
373 // subtitle for the future, keep it
374 gotSub = null;
375 }
376 } else {
377 gotSub = null;
378 }
379 }
380 if( null == gotSub ) {
381 sub = lastSub;
382 newSub = false;
383 } else {
384 if( null != lastSub ) {
385 lastSub.release();
386 }
387 lastSub = null;
388 if( SubtitleEvent.Type.Empty == gotSub.type ) {
389 gotSub.release();
390 sub = null;
391 newSub = false;
392 if( DEBUG_SUB ) {
393 System.err.println("MediaButton: Empty: pts "+pts+", "+gotSub);
394 }
395 } else {
396 drawLastSub = gotSub;
397 sub = gotSub;
398 newSub = true;
399 }
400 }
401 }
402 // drop or draw (update label for new subtitle)
403 if( null == sub ) {
404 drawLastSub = null;
405 } else if( SubtitleEvent.Type.Text == sub.type ) {
406 final SubTextEvent assSub = (SubTextEvent)sub;
407 if( newSub ) {
408 final float maxWidth = box.getWidth() * ASS_SUB_USED_WIDTH;
409 subLabel.setFont( Font.getBestCoverage(subFont, subFallbackFont, assSub.text) );
410 subLabel.setText(assSub.text);
411 int lines = assSub.lines;
412 AABBox subBox = subLabel.getBounds(gl.getGLProfile());
413 float subLineHeight = subBox.getHeight() / lines;
414 float lineHeight = box.getHeight() * subLineHeightPct;
415 float s_s = lineHeight / subLineHeight;
416 if( s_s * subBox.getWidth() > maxWidth ) {
417 // Split too wide text into multiple lines (max 4) fitting into box
418 // while trimming it beforehand.
419 if( DEBUG_SUB_LAYOUT ) {
420 System.err.println("XXX split.0 has lines "+lines+", s "+s_s+", width "+(s_s * subBox.getWidth())+" > "+maxWidth+": "+assSub.text);
421 }
422 final String trimmed = StringUtil.trim(assSub.text, StringUtil.WHITESPACE, " ");
423 lines = Math.min(ASS_SUB_MAX_SPLIT_LINES, (int)Math.ceil( s_s * subBox.getWidth() / maxWidth ));
424 final String text = StringUtil.split(trimmed, lines, " ", String.valueOf(StringUtil.LF));
425 lines = StringUtil.getLineCount(text);
426 subLabel.setText(text);
427 subBox = subLabel.getBounds(gl.getGLProfile());
428 subLineHeight = subBox.getHeight() / lines;
429 lineHeight = box.getHeight() * subLineHeightPct;
430 s_s = lineHeight / subLineHeight;
431 if( DEBUG_SUB_LAYOUT ) {
432 System.err.println("XXX split.X to lines "+lines+", s "+s_s+", width "+(s_s * subBox.getWidth())+" <=?= "+maxWidth+": "+text);
433 }
434 if( s_s * subBox.getWidth() > maxWidth ) {
435 // scale down remaining diff
436 s_s = maxWidth / subBox.getWidth();
437 lineHeight *= s_s / ( lineHeight / subLineHeight );
438 if( DEBUG_SUB_LAYOUT ) {
439 System.err.println("XXX scale-down scale "+s_s+", width "+(s_s * subBox.getWidth())+" <= "+maxWidth+": "+text);
440 }
441 }
442 }
443 subLabel.setScale(s_s, s_s, 1);
444
445 final float labelHeight = lineHeight * lines;
446 final float blendHeight = labelHeight + lineHeight * ASS_SUB_BLEND_ADDED_HEIGHT;
447 final Vec2f v_sz = new Vec2f(mPlayer.getWidth(), mPlayer.getHeight());
448 final Vec2f v_sxy = new Vec2f( box.getWidth(), box.getHeight() ).div( v_sz );
449 final float v_s = Math.min( v_sxy.x(), v_sxy.y() );
450 final Vec2f v_ctr = new Vec2f(v_sz).scale(0.5f); // original video size center
451 final Vec2f b_ctr = new Vec2f(box.getCenter()).scale(1/v_s);
452 final float d_bl = ( blendHeight - labelHeight ) * 0.5f;
453 final float v_maxWidth = v_sz.x() * ASS_SUB_USED_WIDTH;
454 final float d_vmw = v_sz.x() - v_maxWidth;
455 final Vec2f s_p0_s;
456 if( subAlignment.isSet( Alignment.Bit.Left) ) {
457 // Alignment.Bit.Left
458 final Vec2f s_p0 = new Vec2f( d_vmw*0.5f,
459 ( subLineHeight * subLineDY * s_s ) / v_s);
460 s_p0_s = s_p0.sub( v_ctr ).add(b_ctr).scale( v_s ).add(0, d_bl);
461 } else {
462 // Alignment.Bit.CenterHoriz
463 final Vec2f s_p0 = new Vec2f( d_vmw*0.5f + ( v_maxWidth - subBox.getWidth()*s_s/v_s )*0.5f,
464 ( subLineHeight * subLineDY * s_s ) / v_s);
465 s_p0_s = s_p0.sub( v_ctr ).add(b_ctr).scale( v_s ).add(0, d_bl);
466 }
467 subLabel.moveTo(s_p0_s.x(), s_p0_s.y(), 2*subZOffset);
468
469 subBlend.setDimension(box.getWidth(), blendHeight, 0f);
470 subBlend.setPosition(0, s_p0_s.y() - d_bl, 1*subZOffset);
471 if( DEBUG_SUB ) {
472 System.err.println("MediaButton: NEXT pts "+pts+", "+sub);
473 }
474 }
475 subBlend.draw(gl, renderer);
476 final PMVMatrix4f pmv = renderer.getMatrix();
477 pmv.pushMv();
478 subLabel.applyMatToMv(pmv);
479 subLabel.draw(gl, renderer);
480 pmv.popMv();
481 } else if( SubtitleEvent.Type.Bitmap == sub.type ) {
482 final SubBitmapEvent texSub = (SubBitmapEvent)sub;
483 if( newSub ) {
484 if( DEBUG_SUB ) {
485 System.err.println("MediaButton: NEXT pts "+pts+", "+sub);
486 }
487 if( null != texSub.texture ) {
488 final ImageSequence imgSeq = subTexImg.getImageSequence();
489 imgSeq.removeAllFrames();
490 imgSeq.addFrame(gl, texSub.texture);
491 final Vec2f v_sz = new Vec2f(mPlayer.getWidth(), mPlayer.getHeight());
492 final Vec2f v_sxy = new Vec2f( box.getWidth(), box.getHeight() ).div( v_sz );
493 final float v_s = Math.min(v_sxy.x(), v_sxy.y());
494 final Vec2f s_sz_s = new Vec2f(texSub.dimension).scale(v_s);
495 subTexImg.setSize(s_sz_s.x(), s_sz_s.y());
496
497 final Vec2f v_ctr;
498 if( CodecID.HDMV_PGS == sub.codec && mPlayer.getWidth() < 1920 && mPlayer.getHeight() == 1080 ) {
499 // PGS subtitles < 1920 width, e.g. 4:3 1440 width but 1080p
500 // usually are positioned to 1920 width screen. FIXME: Elaborate, find metrics
501 v_ctr = new Vec2f(new Vec2f(1920, 1080)).scale(0.5f); // 1080p center
502 } else {
503 v_ctr = new Vec2f(v_sz).scale(0.5f); // original video size center
504 }
505 final Vec2f b_ctr = new Vec2f(box.getCenter()).scale(1/v_s);
506 final Vec2f s_p0 = new Vec2f(texSub.position.x(),
507 v_sz.y() - texSub.position.y() - texSub.dimension.y() ); // y-flip + texSub.position is top-left
508 final Vec2f s_p0_s = s_p0.minus( v_ctr ).add( b_ctr ).scale( v_s );
509 subTexImg.moveTo(s_p0_s.x(), s_p0_s.y(), 2*subZOffset);
510
511 if( DEBUG_SUB_LAYOUT ) {
512 // Keep this to ease later adjustments due to specifications like PGS
513 final Vec2f b_sz = new Vec2f(box.getWidth(), box.getHeight());
514 final float v_ar = v_sz.x()/v_sz.y();
515 final float b_ar = b_sz.x()/b_sz.y();
516 final float s_ar = s_sz_s.x()/s_sz_s.y();
517 final float s_x_centered = ( b_sz.x() - s_sz_s.x() ) * 0.5f;
518 final Vec2f v_ctr_1080p = new Vec2f(new Vec2f(1920, 1080)).scale(0.5f); // 1080p center
519 final Vec2f v_ctr_o = new Vec2f(v_sz).scale(0.5f); // original video size center
520 final Vec2f s_sz = new Vec2f(texSub.dimension);
521 final Vec2f b_ctr_s = new Vec2f(box.getCenter());
522 final Vec2f v_p0_ctr = s_p0.minus(v_ctr); // p0 -> v_sz center
523 final Vec2f s_p1 = b_ctr.plus(v_p0_ctr);
524 System.err.println("XX video "+v_sz+" (ar "+v_ar+"), ( v_ctr "+v_ctr_o+", v_ctr_1080p "+v_ctr_1080p+" ) -> v_ctr "+v_ctr);
525 System.err.println("XX sub s_sz "+s_sz+", s_sz_s "+s_sz_s+" (ar "+s_ar+")");
526 System.err.println("XX box "+b_sz+" (ar "+b_ar+"), b_ctr "+b_ctr+", b_ctr_s "+b_ctr_s);
527 System.err.println("XXX v_s "+v_sxy+" -> "+v_s+": sz "+s_sz_s);
528 System.err.println("XXX p0 "+s_p0+", v_p0_ctr "+v_p0_ctr+", s_p1 "+s_p1+" -> s_p1_s "+s_p0_s+"; sxs_2 "+s_x_centered);
529 }
530 }
531 }
532 final PMVMatrix4f pmv = renderer.getMatrix();
533 pmv.pushMv();
534 subTexImg.applyMatToMv(pmv);
535 subTexImg.draw(gl, renderer);
536 pmv.popMv();
537 }
538 }
539}
Abstract Outline shape representation define the method an OutlineShape(s) is bound and rendered.
Definition: Region.java:62
static final int AA_RENDERING_MASK
2-pass rendering bit-mask including MSAA_RENDERING_BIT and VBAA_RENDERING_BIT.
Definition: Region.java:118
final void markShapeDirty()
Mark this region's shape dirty, i.e.
Definition: Region.java:797
The optional property jogamp.graph.font.ctor allows user to specify the FontConstructor implementatio...
static synchronized Font getFallbackFont()
Returns registered fallback Font, maybe null.
static Font getDefaultFont()
Returns default Font of default FontSet or null if n/a.
Shape setColor(final float r, final float g, final float b, final float a)
Set base color.
Definition: Shape.java:1389
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
void draw(final GL2ES2 gl, final RegionRenderer renderer)
Renders the shape.
Definition: Shape.java:798
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 moveTo(final float tx, final float ty, final float tz)
Move to scaled position.
Definition: Shape.java:543
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
final Shape setDragAndResizable(final boolean v)
Set whether this shape is draggable and resizable.
Definition: Shape.java:1801
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 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 void destroy(final GL2ES2 gl, final RegionRenderer renderer)
Destroys all data.
Definition: Shape.java:457
final void applyMatToMv(final PMVMatrix4f pmv)
Applies the internal Matrix4f to the given modelview matrix, i.e.
Definition: Shape.java:908
final Shape scale(final Vec3f s)
Multiply current scale factor by given scale.
Definition: Shape.java:661
final Shape setToggleable(final boolean toggleable)
Set this shape toggleable, default is off.
Definition: Shape.java:1573
Immutable layout alignment options, including Bit#Fill.
Definition: Alignment.java:35
static final Alignment CenterHoriz
Bit#CenterHoriz alignment constant.
Definition: Alignment.java:41
boolean isSet(final Bit bit)
Definition: Alignment.java:94
BaseButton setPerp()
Sets a perpendicular corner.
BaseButton setSize(final float width, final float height)
A GraphUI text labeled BaseButton GraphShape.
Definition: Button.java:61
static final float DEFAULT_LABEL_ZOFFSET
Default Z-axis offset, using the smallest resolvable Z separation rounded value {@value} at 16-bits d...
Definition: Button.java:79
A GraphUI ImageSequence based TexSeqButton GraphShape.
void draw(final GL2ES2 gl, final RegionRenderer renderer)
Renders the shape.
A GraphUI text label GraphShape.
Definition: Label.java:50
boolean setText(final CharSequence text)
Set the text to be rendered.
Definition: Label.java:94
boolean setFont(final Font font)
Set the Font used to render the text.
Definition: Label.java:146
A GraphUI GLMediaPlayer based TexSeqButton GraphShape.
void setSubtitlesEnabled(final boolean v)
Toggle enabling subtitle rendering.
final SubtitleEventListener getSubEventListener()
void setSubtitleColor(final Vec4f color, final float blend)
Sets text/ASS subtitle colors.
static final Vec4f DEFAULT_ASS_SUB_COLOR
Default color for the text/ASS subtitles, defaults to RGBA 1, 1, 1, 1.
MediaButton(final int renderModes, final float width, final float height, final GLMediaPlayer mPlayer)
Constructs a MediaButton with FontFactory#getDefaultFont() for subtitles.
static final float DEFAULT_ASS_SUB_HEIGHT
Default text/ASS subtitle line height percentage, {@value}.
void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer)
final void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final Vec4f rgba)
Actual draw implementation, called by draw(GL2ES2, RegionRenderer).
final GLMediaPlayer getGLMediaPlayer()
MediaButton addDefaultEventListener()
Add the default GLMediaEventListener to this class's GLMediaPlayer.
static final Alignment DEFAULT_ASS_SUB_ALIGNMENT
Default text/ASS subtitle alignment, defaults to Alignment#CenterHoriz.
void addShapeToRegion(final GLProfile glp, final GL2ES2 gl)
MediaButton setVerbose(final boolean v)
void setSubtitleParams(final Font subFont, final float subLineHeightPct, final float subLineDY, final Alignment subAlignment)
Sets text/ASS subtitle parameter, enabling subtitle rendering.
static final float DEFAULT_ASS_SUB_POS
Default text/ASS subtitle y-axis offset to bottom in line-height percentage, {@value}.
static final float DEFAULT_ASS_SUB_BLEND
Default blending alpha (darkness) for the text/ASS subtitles, defaults to {@value}.
MediaButton(final int renderModes, final float width, final float height, final GLMediaPlayer mPlayer, final Font subFont)
Constructs a MediaButton prepared for using subtitles.
void clearImpl(final GL2ES2 gl, final RegionRenderer renderer)
A GraphUI rectangle GraphShape.
Definition: Rectangle.java:47
void setDimension(final float width, final float height, final float lineWidth)
Definition: Rectangle.java:124
void setPosition(final float minX, final float minY, final float zPos)
Definition: Rectangle.java:118
An abstract GraphUI TextureSequence BaseButton GraphShape.
TexSeqButton setARatioAdjustment(final boolean v)
See TextureSequence#setARatioAdjustment(boolean).
Vec3f scale(final float s)
this = this * s, returns this.
Definition: Vec3f.java:218
4D Vector based upon four float components.
Definition: Vec4f.java:37
final float getWidth()
Definition: AABBox.java:879
final float getHeight()
Definition: AABBox.java:883
final Vec3f getCenter()
Returns computed center of this AABBox of getLow() and getHigh().
Definition: AABBox.java:737
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
abstract void release()
Release the resources, if any, back to the owner.
Simple TextureSequence implementation allowing existing textures or image streams to be used and repl...
void setParams(final int magFilter, final int minFilter, final int wrapS, final int wrapT)
Interface wrapper for font implementation.
Definition: Font.java:60
static final int GL_LINEAR
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_LINEAR" with expressi...
Definition: GL.java:323
static final int GL_CLAMP_TO_EDGE
GL_ES_VERSION_2_0, GL_VERSION_1_2, GL_VERSION_ES_1_0, GL_SGIS_texture_edge_clamp Alias for: GL_CLAMP_...
Definition: GL.java:775
As the contract of GLMediaFrameListener and TexSeqEventListener requests, implementations of GLMediaE...
GLMediaPlayer interface specifies a TextureSequence state machine using a multiplexed audio/video str...
static final int STREAM_ID_NONE
Constant {@value} for mute or not available.
void initGL(GL gl)
Initializes OpenGL related resources.
int getSID()
Return the subtitle stream id, see audio and video Stream IDs.
void addEventListener(GLMediaEventListener l)
Adds a GLMediaEventListener to this player.
StreamException getStreamException()
Returns the StreamException caught in the decoder thread, or null if none occured.
int seek(int msec)
Seeks to the new absolute position.
AudioSink getAudioSink()
If implementation uses a AudioSink, it's instance will be returned.
State resume()
Starts or resumes the StreamWorker decoding thread.
void setSubtitleEventListener(SubtitleEventListener l)
Sets the SubtitleEventListener for this player.
int getTextureUnit()
Return the texture unit used to render the current frame.