1 /*
2  * Copyright (c) 2002-2011 LWJGL Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.lwjgl.opengles;
33 
34 import org.lwjgl.BufferUtils;
35 import org.lwjgl.LWJGLException;
36 import org.lwjgl.LWJGLUtil;
37 import org.lwjgl.opengl.PixelFormatLWJGL;
38 
39 import java.nio.IntBuffer;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.Map;
43 import java.util.Set;
44 
45 import static org.lwjgl.opengles.EGL.*;
46 import static org.lwjgl.opengles.NVCoverageSample.*;
47 import static org.lwjgl.opengles.NVDepthNonlinear.*;
48 import static org.lwjgl.opengles.PixelFormat.Attrib.*;
49 
50 /**
51  * This class describes the configuration settings for an EGL surface. Instances
52  * of this class are used as arguments to Display.create(). The attributes specified
53  * in this class will be used to get EGLConfigs from an EGLDisplay. PixelFormat
54  * is not the best name for this class, but it matches the corresponding class
55  * in the official desktop LWJGL.
56  * <p/>
57  * Instances of this class are immutable. An example of the expected way to set
58  * the PixelFormat property values is the following:
59  * <code>PixelFormat pf = new PixelFormat().withDepth(24).withSamples(4);</code>
60  * <p/>
61  * Attributes that correspond to EGL extensions will be silently ignored if those
62  * extensions are not supported by the EGLDisplay.
63  */
64 public final class PixelFormat implements PixelFormatLWJGL {
65 
66 	public static enum Attrib {
67 		// CORE ATTRIBUTES
68 
69 		RED_SIZE(EGL_RED_SIZE, 0),
70 		GREEN_SIZE(EGL_GREEN_SIZE, 0),
71 		BLUE_SIZE(EGL_BLUE_SIZE, 0),
72 		ALPHA_SIZE(EGL_ALPHA_SIZE, 0),
73 
74 		LUMINANCE_SIZE(EGL_LUMINANCE_SIZE, 0),
75 
76 		DEPTH_SIZE(EGL_DEPTH_SIZE, 0),
77 		STENCIL_SIZE(EGL_STENCIL_SIZE, 0),
78 
79 		MIN_SWAP_INTERVAL(EGL_MIN_SWAP_INTERVAL, EGL_DONT_CARE),
80 		MAX_SWAP_INTERVAL(EGL_MAX_SWAP_INTERVAL, EGL_DONT_CARE),
81 
82 		SAMPLES(EGL_SAMPLES, 0),
83 		SAMPLE_BUFFERS(EGL_SAMPLE_BUFFERS, 0),
84 
85 		TRANSPARENT_TYPE(EGL_TRANSPARENT_TYPE, EGL_NONE),
86 		TRANSPARENT_RED_VALUE(EGL_TRANSPARENT_RED_VALUE, EGL_DONT_CARE),
87 		TRANSPARENT_GREEN_VALUE(EGL_TRANSPARENT_GREEN_VALUE, EGL_DONT_CARE),
88 		TRANSPARENT_BLUE_VALUE(EGL_TRANSPARENT_BLUE_VALUE, EGL_DONT_CARE),
89 
90 		// SURFACE ATTRIBUTES
91 
92 		MULTISAMPLE_RESOLVE(EGL_MULTISAMPLE_RESOLVE, EGL_MULTISAMPLE_RESOLVE_DEFAULT, true),
93 		SWAP_BEHAVIOR(EGL_SWAP_BEHAVIOR, EGL_DONT_CARE, true),
94 
95 		// EXTENSION ATTRIBUTES
96 
97 		COVERAGE_SAMPLES_NV(EGL_COVERAGE_SAMPLES_NV, 0),
98 		COVERAGE_BUFFERS_NV(EGL_COVERAGE_BUFFERS_NV, 0),
99 
100 		DEPTH_ENCODING_NONLINEAR_NV(EGL_DEPTH_ENCODING_NONLINEAR_NV, EGL_DONT_CARE);
101 
102 		private final int eglAttrib;
103 		private final int defaultValue;
104 
105 		private final boolean surfaceAttrib;
106 
Attrib(final int eglAttrib, final int defaultValue)107 		Attrib(final int eglAttrib, final int defaultValue) {
108 			this(eglAttrib, defaultValue, false);
109 		}
110 
Attrib(final int eglAttrib, final int defaultValue, final boolean surfaceAttrib)111 		Attrib(final int eglAttrib, final int defaultValue, final boolean surfaceAttrib) {
112 			this.eglAttrib = eglAttrib;
113 			this.defaultValue = defaultValue;
114 
115 			this.surfaceAttrib = surfaceAttrib;
116 		}
117 
118 		/**
119 		 * Returns the EGL token that corresponds to this attribute.
120 		 *
121 		 * @return the EGL attribute token
122 		 */
getEGLAttrib()123 		public int getEGLAttrib() {
124 			return eglAttrib;
125 		}
126 
127 		/**
128 		 * Returns the default value of this attribute. Attributes
129 		 * with default values will be ignored when choosing the EGLConfig.
130 		 *
131 		 * @return the default value
132 		 */
getDefaultValue()133 		public int getDefaultValue() {
134 			return defaultValue;
135 		}
136 
isSurfaceAttrib()137 		public boolean isSurfaceAttrib() {
138 			return surfaceAttrib;
139 		}
140 
141 	}
142 
143 	private final Map<Attrib, Integer> config = new HashMap<Attrib, Integer>(16);
144 
145 	/**
146 	 * Creates a new PixelFormat with rgbSize = 8, alphaSize = 8 and depthSize = 16.
147 	 *
148 	 * @see #PixelFormat(int, int, int, int, int, int)
149 	 */
PixelFormat()150 	public PixelFormat() {
151 		this(8, 16, 0);
152 	}
153 
154 	/**
155 	 * Creates a new PixelFormat with rgbSize = 8 and the specified
156 	 * alphaSize, depthSize and stencilSize.
157 	 *
158 	 * @param alphaSize   the EGL_ALPHA_SIZE value
159 	 * @param depthSize   the EGL_DEPTH_SIZE value
160 	 * @param stencilSize the EGL_STENCIL_SIZE value
161 	 *
162 	 * @see #PixelFormat(int, int, int, int, int, int)
163 	 */
PixelFormat(int alphaSize, int depthSize, int stencilSize)164 	public PixelFormat(int alphaSize, int depthSize, int stencilSize) {
165 		this(alphaSize, depthSize, stencilSize, 0);
166 	}
167 
168 	/**
169 	 * Creates a new PixelFormat with rgbSize = 8 and the specified
170 	 * alphaSize, depthSize, stencilSize and samples.
171 	 *
172 	 * @param alphaSize   the EGL_ALPHA_SIZE value
173 	 * @param depthSize   the EGL_DEPTH_SIZE value
174 	 * @param stencilSize the EGL_STENCIL_SIZE value
175 	 * @param samples     the EGL_SAMPLE_SIZE value
176 	 *
177 	 * @see #PixelFormat(int, int, int, int, int, int)
178 	 */
PixelFormat(int alphaSize, int depthSize, int stencilSize, int samples)179 	public PixelFormat(int alphaSize, int depthSize, int stencilSize, int samples) {
180 		this(8, alphaSize, 0, depthSize, stencilSize, samples);
181 	}
182 
183 	/**
184 	 * Creates a new PixelFormat with the specified RGB sizes, EGL_ALPHA_SIZE,
185 	 * EGL_LUMINANCE_SIZE, EGL_DEPTH_SIZE, EGL_STENCIL_SIZE, EGL_SAMPLES.
186 	 * All values must be greater than or equal to 0. rgbSize and luminanceSize
187 	 * cannot both be greater than 0. depthSize greater than 24 and stencilSize
188 	 * greater than 8 are not recommended.
189 	 * The corresponding EGL_SAMPLE_BUFFERS value will become 0 if samples is 0,
190 	 * or 1 if samples is greater than 0.
191 	 *
192 	 * @param rgbSize       the RGB sizes
193 	 * @param alphaSize     the EGL_ALPHA_SIZE value
194 	 * @param luminanceSize the EGL_LUMINANCE_SIZE value
195 	 * @param depthSize     the EGL_DEPTH_SIZE value
196 	 * @param stencilSize   the EGL_STENCIL_SIZE value
197 	 * @param samples       the EGL_SAMPLE_SIZE value
198 	 */
PixelFormat(int rgbSize, int alphaSize, int luminanceSize, int depthSize, int stencilSize, int samples)199 	public PixelFormat(int rgbSize, int alphaSize, int luminanceSize, int depthSize, int stencilSize, int samples) {
200 		if ( rgbSize < 0 )
201 			throw new IllegalArgumentException("Invalid RGB size specified: " + rgbSize);
202 
203 		if ( alphaSize < 0 )
204 			throw new IllegalArgumentException("Invalid EGL_ALPHA_SIZE specified: " + alphaSize);
205 
206 		if ( luminanceSize < 0 || (0 < luminanceSize && 0 < rgbSize) )
207 			throw new IllegalArgumentException("Invalid EGL_LUMINANCE_SIZE specified: " + luminanceSize);
208 
209 		if ( depthSize < 0 )
210 			throw new IllegalArgumentException("Invalid EGL_DEPTH_SIZE specified: " + depthSize);
211 
212 		if ( stencilSize < 0 )
213 			throw new IllegalArgumentException("Invalid EGL_STENCIL_SIZE specified: " + stencilSize);
214 
215 		if ( samples < 0 )
216 			throw new IllegalArgumentException("Invalid EGL_SAMPLES specified: " + samples);
217 
218 		if ( 0 < rgbSize ) {
219 			setAttrib(RED_SIZE, rgbSize);
220 			setAttrib(GREEN_SIZE, rgbSize);
221 			setAttrib(BLUE_SIZE, rgbSize);
222 		}
223 		setAttrib(ALPHA_SIZE, alphaSize);
224 
225 		setAttrib(LUMINANCE_SIZE, luminanceSize);
226 
227 		setAttrib(DEPTH_SIZE, depthSize);
228 		setAttrib(STENCIL_SIZE, stencilSize);
229 
230 		setAttrib(SAMPLES, samples);
231 		setAttrib(SAMPLE_BUFFERS, samples == 0 ? 0 : 1);
232 	}
233 
234 	/**
235 	 * Creates a new PixelFormat that is a copy of the specified PixelFormat.
236 	 *
237 	 * @param pf the source PixelFormat
238 	 */
PixelFormat(final PixelFormat pf)239 	private PixelFormat(final PixelFormat pf) {
240 		config.clear();
241 		config.putAll(pf.config);
242 	}
243 
244 	/**
245 	 * Sets the value of an attribute to the current configuration.
246 	 * If the value matches the default attribute value, the
247 	 * attribute will be removed from the configuration.
248 	 *
249 	 * @param attrib the attribute
250 	 * @param value  the new value
251 	 */
setAttrib(final Attrib attrib, final int value)252 	private void setAttrib(final Attrib attrib, final int value) {
253 		if ( attrib.defaultValue == value )
254 			config.remove(attrib);
255 		else
256 			config.put(attrib, value);
257 	}
258 
259 	/**
260 	 * Returns an IntBuffer that can be used to get/choose EGLConfigs.
261 	 * The contents of the IntBuffer will be the sum of the source
262 	 * LWJGL attributes and the user-defined attributes from this
263 	 * PixelFormat's configuration.
264 	 * <p/>
265 	 * The source LWJGL attributes should not contain the EGL_SURFACE_TYPE
266 	 * attirube, or any attributes that are handled by PixelFormat.
267 	 * <p/>
268 	 * Attributes that correspond to EGL extensions will be checked
269 	 * against the extensions supported in the specified EGLDisplay.
270 	 * Attributes that correspond to unsupported extensions will not
271 	 * be included in the final EGLConfig query.
272 	 *
273 	 * @param display      the EGL display from which the EGLConfig is going to be retrieved
274 	 * @param lwjglAttribs the LWJGL attributes
275 	 *
276 	 * @return the IntBuffer
277 	 */
getAttribBuffer(final EGLDisplay display, int surfaceType, final int[] lwjglAttribs)278 	public IntBuffer getAttribBuffer(final EGLDisplay display, int surfaceType, final int[] lwjglAttribs) {
279 		// Create a copy of the configuration attributes
280 		Set<Attrib> keys = new HashSet<Attrib>(config.keySet());
281 
282 		// Handle surface type bits
283 		if ( keys.contains(MULTISAMPLE_RESOLVE) ) {
284 			if ( display.getMajorVersion() == 1 && display.getMinorVersion() < 4 )
285 				keys.remove(MULTISAMPLE_RESOLVE);
286 			else if ( getAttrib(MULTISAMPLE_RESOLVE) == EGL_MULTISAMPLE_RESOLVE_BOX )
287 				surfaceType |= EGL_MULTISAMPLE_RESOLVE_BOX_BIT;
288 		}
289 
290 		if ( keys.contains(SWAP_BEHAVIOR) ) {
291 			if ( display.getMajorVersion() == 1 && display.getMinorVersion() < 4 )
292 				keys.remove(SWAP_BEHAVIOR);
293 			else if ( getAttrib(SWAP_BEHAVIOR) == EGL_BUFFER_PRESERVED )
294 				surfaceType |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
295 		}
296 
297 		// Check NV_coverage_sample
298 		if ( keys.contains(COVERAGE_BUFFERS_NV) && !display.isExtensionSupported("EGL_NV_coverage_sample") ) {
299 			keys.remove(COVERAGE_BUFFERS_NV);
300 			keys.remove(COVERAGE_SAMPLES_NV);
301 		}
302 
303 		// Check NV_depth_nonlinear
304 		if ( keys.contains(DEPTH_ENCODING_NONLINEAR_NV) && !display.isExtensionSupported("EGL_NV_depth_nonlinear") )
305 			keys.remove(DEPTH_ENCODING_NONLINEAR_NV);
306 
307 		// Create IntBuffer and insert the attributes
308 		final IntBuffer attribs = BufferUtils.createIntBuffer(
309 			2                       // SURFACE_TYPE
310 			+ lwjglAttribs.length   // Source LWJGL attributes
311 			+ (keys.size() * 2)     // PixelFormat attributes
312 			+ 1                     // Termination
313 		);
314 
315 		attribs.put(EGL_SURFACE_TYPE).put(surfaceType);
316 		attribs.put(lwjglAttribs);
317 
318 		for ( Attrib key : keys ) {
319 			if ( !key.isSurfaceAttrib() )
320 				attribs.put(key.eglAttrib).put(config.get(key));
321 		}
322 
323 		// Finish the attribute list
324 		attribs.put(EGL_NONE);
325 		attribs.flip();
326 
327 		return attribs;
328 	}
329 
330 	/**
331 	 * Returns true if the requested attribute matches the attribute in the specified EGL config.
332 	 *
333 	 * @param attrib the requested attribute
334 	 * @param config the EGL config
335 	 *
336 	 * @return true if the two attributes match
337 	 *
338 	 * @throws org.lwjgl.LWJGLException if an EGL error occurs
339 	 */
matches(final Attrib attrib, final EGLConfig config)340 	private boolean matches(final Attrib attrib, final EGLConfig config) throws LWJGLException {
341 		return getAttrib(attrib) == config.getAttribute(attrib.getEGLAttrib());
342 	}
343 
344 	/**
345 	 * Returns true if the requested attribute matches the attribute in the specified EGL config.
346 	 * If the requested attribute is equal to 1, then it will match with any EGL config attribute
347 	 * that is greater than 0.
348 	 *
349 	 * @param attrib the requested attribute
350 	 * @param config the EGL config
351 	 *
352 	 * @return true if the two attributes match
353 	 *
354 	 * @throws org.lwjgl.LWJGLException if an EGL error occurs
355 	 */
matchesNonZero(final Attrib attrib, final EGLConfig config)356 	private boolean matchesNonZero(final Attrib attrib, final EGLConfig config) throws LWJGLException {
357 		final int reqValue = getAttrib(attrib);
358 		final int cfgValue = config.getAttribute(attrib.getEGLAttrib());
359 
360 		return reqValue == cfgValue || (reqValue == 1 && cfgValue > 0);
361 	}
362 
363 	/**
364 	 * Returns the EGL config from the specified array that best matches this PixelFormat.
365 	 *
366 	 * @param configs the EGL configs
367 	 *
368 	 * @return the best match
369 	 */
getBestMatch(final EGLConfig[] configs)370 	public EGLConfig getBestMatch(final EGLConfig[] configs) throws LWJGLException {
371 		if ( configs == null || configs.length == 0 )
372 			throw new IllegalArgumentException("No EGLConfigs specified.");
373 
374 		if ( configs.length == 1 )
375 			return configs[0];
376 
377 		/*System.out.println("\nASKED FOR:");
378 		for ( Attrib attrib : config.keySet() ) {
379 			System.out.println("EGL_" + attrib.name() + ": " + getAttrib(attrib));
380 		}
381 
382 		for ( EGLConfig config : configs ) {
383 			if ( config == null )
384 				continue;
385 
386 			System.out.println("\n----");
387 			System.out.println(config);
388 		}*/
389 
390 		for ( EGLConfig config : configs ) {
391 			if ( config == null )
392 				continue;
393 
394 			if ( !(matches(ALPHA_SIZE, config) && matchesNonZero(DEPTH_SIZE, config) && matchesNonZero(STENCIL_SIZE, config)) )
395 				continue;
396 
397 			final int luminance = getAttrib(LUMINANCE_SIZE);
398 			if ( 0 < luminance && !matches(LUMINANCE_SIZE, config) )
399 				continue;
400 
401 			if ( luminance == 0 && !(matches(RED_SIZE, config) && matches(GREEN_SIZE, config) && matches(BLUE_SIZE, config)) )
402 				continue;
403 
404 			if ( !(matches(SAMPLE_BUFFERS, config) && matches(SAMPLES, config)) )
405 				continue;
406 
407 			// TODO: Add more? NV's Tegra SDK checks a hardcoded 5 value for COVERAGE_SAMPLES_NV (nv_main.c, line: 1823)
408 
409 			return config;
410 		}
411 
412 		// No match found, use the one recommended by the EGL implementation.
413 		LWJGLUtil.log("Could not find an exact EGLConfig match for the PixelFormat requested, using first returned.");
414 		return configs[0];
415 	}
416 
417 	/**
418 	 * Applies this PixelFormat's surface attributes to the specified EGL surface.
419 	 *
420 	 * @param surface the EGL surface
421 	 */
setSurfaceAttribs(final EGLSurface surface)422 	public void setSurfaceAttribs(final EGLSurface surface) throws LWJGLException {
423 		setSurfaceAttrib(surface, SWAP_BEHAVIOR);
424 		setSurfaceAttrib(surface, MULTISAMPLE_RESOLVE);
425 	}
426 
setSurfaceAttrib(final EGLSurface surface, final Attrib attrib)427 	private void setSurfaceAttrib(final EGLSurface surface, final Attrib attrib) throws LWJGLException {
428 		final int value = getAttrib(attrib);
429 		if ( value != attrib.getDefaultValue() )
430 			surface.setAttribute(attrib.getEGLAttrib(), value);
431 	}
432 
433 	/**
434 	 * Returns the value of the specified attribute.
435 	 *
436 	 * @param attrib the attribute to retrieve
437 	 *
438 	 * @return the attribute's value
439 	 */
getAttrib(final Attrib attrib)440 	public int getAttrib(final Attrib attrib) {
441 		final Integer value = config.get(attrib);
442 		if ( value == null )
443 			return attrib.defaultValue;
444 
445 		return value;
446 	}
447 
448 	/* -----------------------------------------
449 					CORE ATTRIBUTES
450 	----------------------------------------- */
451 
452 	/**
453 	 * Returns a new PixelFormat with the specified RGB sizes.
454 	 *
455 	 * @param rgb the new EGL_RED_SIZE, EGL_GREEN_SIZE and EGL_BLUE_SIZE
456 	 *
457 	 * @return the new PixelFormat
458 	 *
459 	 * @see #withRGBSize(int, int, int)
460 	 */
withRGBSize(final int rgb)461 	public PixelFormat withRGBSize(final int rgb) {
462 		return withRGBSize(rgb, rgb, rgb);
463 	}
464 
465 	/**
466 	 * Returns a new PixelFormat with the specified EGL_RED_SIZE, EGL_GREEN_SIZE and EGL_BLUE_SIZE.
467 	 * All 3 values must be greater than or equal to 0. If any of the 3 values is greater than 0,
468 	 * the luminanceSize will be set to 0.
469 	 *
470 	 * @param r the new EGL_RED_SIZE
471 	 * @param g the new EGL_GREEN_SIZE
472 	 * @param b the new EGL_BLUE_SIZE
473 	 *
474 	 * @return the new PixelFormat
475 	 */
withRGBSize(final int r, final int g, final int b)476 	public PixelFormat withRGBSize(final int r, final int g, final int b) {
477 		if ( r < 0 || g < 0 || b < 0 )
478 			throw new IllegalArgumentException("Invalid RGB sizes specified: " + r + ", " + g + ", " + b);
479 
480 		final PixelFormat pf = new PixelFormat(this);
481 		pf.setAttrib(RED_SIZE, r);
482 		pf.setAttrib(GREEN_SIZE, g);
483 		pf.setAttrib(BLUE_SIZE, b);
484 		if ( 0 < r || 0 < g || 0 < b )
485 			pf.setAttrib(LUMINANCE_SIZE, 0);
486 		return pf;
487 	}
488 
489 	/**
490 	 * Returns a new PixelFormat with the specified EGL_ALPHA_SIZE.
491 	 * The alphaSize value must be greater than or equal to 0.
492 	 *
493 	 * @param alphaSize the new EGL_ALPHA_SIZE
494 	 *
495 	 * @return the new PixelFormat
496 	 */
withAlphaSize(final int alphaSize)497 	public PixelFormat withAlphaSize(final int alphaSize) {
498 		if ( alphaSize < 0 )
499 			throw new IllegalArgumentException("Invalid EGL_ALPHA_SIZE specified: " + alphaSize);
500 
501 		final PixelFormat pf = new PixelFormat(this);
502 		pf.setAttrib(ALPHA_SIZE, alphaSize);
503 		return pf;
504 	}
505 
506 	/**
507 	 * Returns a new PixelFormat with the specified EGL_LUMINANCE_SIZE.
508 	 * The luminanceSize value must be greater than or equal to 0. If
509 	 * luminanceSize is greater than 0, the RGB sizes will be set to 0.
510 	 *
511 	 * @param luminanceSize the new EGL_LUMINANCE_SIZE
512 	 *
513 	 * @return the new PixelFormat
514 	 */
withLuminanceSize(final int luminanceSize)515 	public PixelFormat withLuminanceSize(final int luminanceSize) {
516 		if ( luminanceSize < 0 )
517 			throw new IllegalArgumentException("Invalid EGL_LUMINANCE_SIZE specified: " + luminanceSize);
518 
519 		final PixelFormat pf = new PixelFormat(this);
520 		pf.setAttrib(LUMINANCE_SIZE, luminanceSize);
521 		if ( 0 < luminanceSize ) {
522 			pf.setAttrib(RED_SIZE, 0);
523 			pf.setAttrib(GREEN_SIZE, 0);
524 			pf.setAttrib(BLUE_SIZE, 0);
525 		}
526 		return pf;
527 	}
528 
529 	/**
530 	 * Returns a new PixelFormat with the specified EGL_DEPTH_SIZE.
531 	 * The depthSize value must be greater than or equal to 0.
532 	 * Values greater than 24 are not recommended.
533 	 *
534 	 * @param depthSize the new EGL_DEPTH_SIZE
535 	 *
536 	 * @return the new PixelFormat
537 	 */
withDepthSize(final int depthSize)538 	public PixelFormat withDepthSize(final int depthSize) {
539 		if ( depthSize < 0 )
540 			throw new IllegalArgumentException("Invalid EGL_DEPTH_SIZE specified: " + depthSize);
541 
542 		final PixelFormat pf = new PixelFormat(this);
543 		pf.setAttrib(DEPTH_SIZE, depthSize);
544 		return pf;
545 	}
546 
547 	/**
548 	 * Returns a new PixelFormat with the specified EGL_STENCIL_SIZE.
549 	 * The stencilSize value must be greater than or equal to 0.
550 	 * Values greater than 8 are not recommended.
551 	 *
552 	 * @param stencilSize the new EGL_STENCIL_SIZE
553 	 *
554 	 * @return the new PixelFormat
555 	 */
withStencilSize(final int stencilSize)556 	public PixelFormat withStencilSize(final int stencilSize) {
557 		if ( stencilSize < 0 )
558 			throw new IllegalArgumentException("Invalid EGL_STENCIL_SIZE specified: " + stencilSize);
559 
560 		final PixelFormat pf = new PixelFormat(this);
561 		pf.setAttrib(STENCIL_SIZE, stencilSize);
562 		return pf;
563 	}
564 
565 	/**
566 	 * Returns a new PixelFormat with the specified EGL_MIN_SWAP_INTERVAL.
567 	 * The minSwapInterval value must be between 0 and this PixelFormat's EGL_MAX_SWAP_INTERVAL.
568 	 *
569 	 * @param minSwapInterval the new EGL_MIN_SWAP_INTERVAL value
570 	 *
571 	 * @return the new PixelFormat
572 	 */
withMinSwapInterval(final int minSwapInterval)573 	public PixelFormat withMinSwapInterval(final int minSwapInterval) {
574 		final int maxSwapInterval = getAttrib(MAX_SWAP_INTERVAL);
575 		if ( minSwapInterval != EGL_DONT_CARE && (minSwapInterval < 0 || (maxSwapInterval != EGL_DONT_CARE && maxSwapInterval < minSwapInterval)) )
576 			throw new IllegalArgumentException("Invalid EGL_MIN_SWAP_INTERVAL specified: " + minSwapInterval);
577 
578 		final PixelFormat pf = new PixelFormat(this);
579 		pf.setAttrib(MIN_SWAP_INTERVAL, minSwapInterval);
580 		return pf;
581 	}
582 
583 	/**
584 	 * Returns a new PixelFormat with the specified EGL_MAX_SWAP_INTERVAL.
585 	 * The maxSwapInterval value must be greater than or equal to this PixelFormat's EGL_MIN_SWAP_INTERVAL.
586 	 *
587 	 * @param maxSwapInterval the new EGL_MAX_SWAP_INTERVAL value
588 	 *
589 	 * @return the new PixelFormat
590 	 */
withMaxSwapInterval(final int maxSwapInterval)591 	public PixelFormat withMaxSwapInterval(final int maxSwapInterval) {
592 		if ( maxSwapInterval < getAttrib(MIN_SWAP_INTERVAL) )
593 			throw new IllegalArgumentException("Invalid EGL_MAX_SWAP_INTERVAL specified: " + maxSwapInterval);
594 
595 		final PixelFormat pf = new PixelFormat(this);
596 		pf.setAttrib(MAX_SWAP_INTERVAL, maxSwapInterval);
597 		return pf;
598 	}
599 
600 	/**
601 	 * Returns a new PixelFormat with the specified number of EGL_SAMPLES.
602 	 * The samples value must be either 0 or greater than or equal to 2. The related
603 	 * EGL_SAMPLE_BUFFERS value will become 0 if samples is 0, or 1 if samples
604 	 * is greater than or equal to 2.
605 	 *
606 	 * @param samples the new EGL_SAMPLES value
607 	 *
608 	 * @return the new PixelFormat
609 	 */
withSamples(final int samples)610 	public PixelFormat withSamples(final int samples) {
611 		if ( samples != 0 && samples < 2 )
612 			throw new IllegalArgumentException("Invalid number of EGL_SAMPLES specified: " + samples);
613 
614 		final PixelFormat pf = new PixelFormat(this);
615 		pf.setAttrib(SAMPLES, samples);
616 		pf.setAttrib(SAMPLE_BUFFERS, samples == 0 ? 0 : 1);
617 		return pf;
618 	}
619 
maxValue(final int bits)620 	private static int maxValue(final int bits) {
621 		return (2 << bits) - 1;
622 	}
623 
624 	/**
625 	 * Returns a new PixelFormat with the specified EGL_TRANSPARENT_TYPE and
626 	 * the specified transparent RGB values. The transparentType must be
627 	 * either EGL_NONE or EGL_TRANSPARENT_RGB. When it is EGL_NONE, the RGB
628 	 * values are set to zero and ignored. When it is EGL_TRANSPARENT_RGB,
629 	 * the RGB values must be between 0 and 2^rgbSize - 1.
630 	 *
631 	 * @param transparentType the new EGL_TRANSPARENT_TYPE value
632 	 * @param r               the new EGL_TRANSPARENT_RED_VALUE
633 	 * @param g               the new EGL_TRANSPARENT_GREEN_VALUE
634 	 * @param b               the new EGL_TRANSPARENT_BLUE_VALUE
635 	 *
636 	 * @return the new PixelFormat
637 	 */
withTransparentType(final int transparentType, int r, int g, int b)638 	public PixelFormat withTransparentType(final int transparentType, int r, int g, int b) {
639 		if ( transparentType == EGL_TRANSPARENT_RGB ) {
640 			final int redSize = getAttrib(RED_SIZE);
641 			final int greenSize = getAttrib(GREEN_SIZE);
642 			final int blueSize = getAttrib(BLUE_SIZE);
643 			if ( r < 0 || (0 < redSize && maxValue(redSize) < r) )
644 				throw new IllegalArgumentException("Invalid EGL_TRANSPARENT_RED_VALUE specified: " + r);
645 
646 			if ( r < 0 || (0 < greenSize && maxValue(greenSize) < g) )
647 				throw new IllegalArgumentException("Invalid EGL_TRANSPARENT_GREEN_VALUE specified: " + g);
648 
649 			if ( r < 0 || (0 < blueSize && maxValue(blueSize) < b) )
650 				throw new IllegalArgumentException("Invalid EGL_TRANSPARENT_BLUE_VALUE specified: " + b);
651 		} else if ( transparentType != EGL_NONE )
652 			throw new IllegalArgumentException("Invalid EGL_TRANSPARENT_TYPE specified: " + transparentType);
653 		else
654 			r = g = b = EGL_DONT_CARE;
655 
656 		final PixelFormat pf = new PixelFormat(this);
657 
658 		pf.setAttrib(TRANSPARENT_TYPE, transparentType);
659 
660 		pf.setAttrib(TRANSPARENT_RED_VALUE, r);
661 		pf.setAttrib(TRANSPARENT_GREEN_VALUE, g);
662 		pf.setAttrib(TRANSPARENT_BLUE_VALUE, b);
663 
664 		return pf;
665 	}
666 
667 	/* -----------------------------------------
668 				SURFACE ATTRIBUTES
669 	----------------------------------------- */
670 
671 	/**
672 	 * Returns a new PixelFormat with the specified EGL_MULTISAMPLE_RESOLVE value.
673 	 * Valid values for multisampleResolve are EGL_MULTISAMPLE_RESOLVE_DEFAULT
674 	 * and EGL_MULTISAMPLE_RESOLVE_BOX.
675 	 * <p/>
676 	 * An IllegalStateException will be thrown if EGL_SAMPLES has not been previously defined
677 	 * to be greater than or equal to 2.
678 	 *
679 	 * @param multisampleResolve the new EGL_MULTISAMPLE_RESOLVE value
680 	 *
681 	 * @return the new PixelFormat
682 	 */
withMultisampleResolve(final int multisampleResolve)683 	public PixelFormat withMultisampleResolve(final int multisampleResolve) {
684 		if ( multisampleResolve != EGL_MULTISAMPLE_RESOLVE_DEFAULT && multisampleResolve != EGL_MULTISAMPLE_RESOLVE_BOX )
685 			throw new IllegalArgumentException("Invalid EGL_MULTISAMPLE_RESOLVE value specified: " + multisampleResolve);
686 
687 		if ( getAttrib(SAMPLE_BUFFERS) == 0 )
688 			throw new IllegalStateException("An EGL_MULTISAMPLE_RESOLVE value cannot be specified unless EGL_SAMPLE_BUFFERS is 1.");
689 
690 		final PixelFormat pf = new PixelFormat(this);
691 		pf.setAttrib(MULTISAMPLE_RESOLVE, multisampleResolve);
692 		return pf;
693 	}
694 
695 	/**
696 	 * Returns a new PixelFormat with the specified EGL_SWAP_BEHAVIOR value.
697 	 * Valid values for swapBehavior are EGL_DONT_CARE, EGL_BUFFER_PRESERVED
698 	 * and EGL_BUFFER_DESTROYED.
699 	 *
700 	 * @param swapBehavior the new EGL_SWAP_BEHAVIOR value
701 	 *
702 	 * @return the new PixelFormat
703 	 */
withSwapBehavior(final int swapBehavior)704 	public PixelFormat withSwapBehavior(final int swapBehavior) {
705 		switch ( swapBehavior ) {
706 			case EGL_DONT_CARE:
707 			case EGL_BUFFER_PRESERVED:
708 			case EGL_BUFFER_DESTROYED:
709 				break;
710 			default:
711 				throw new IllegalArgumentException("Invalid EGL_SWAP_BEHAVIOR value specified: " + swapBehavior);
712 		}
713 
714 		final PixelFormat pf = new PixelFormat(this);
715 		pf.setAttrib(SWAP_BEHAVIOR, swapBehavior);
716 		return pf;
717 	}
718 
719 	/* -----------------------------------------
720 				EXTENSION ATTRIBUTES
721 	----------------------------------------- */
722 
723 	/**
724 	 * Returns a new PixelFormat with the specified number of EGL_COVERAGE_SAMPLES_NV.
725 	 * The samples value must be greater than or equal to 0. The related
726 	 * EGL_COVERAGE_BUFFERS_NV value will become 0 if samples is 0, or 1 if samples
727 	 * is greater than 0.
728 	 *
729 	 * @param samples the new EGL_SAMPLES value
730 	 *
731 	 * @return the new PixelFormat
732 	 */
withCoverageSamplesNV(final int samples)733 	public PixelFormat withCoverageSamplesNV(final int samples) {
734 		if ( samples < 0 )
735 			throw new IllegalArgumentException("Invalid number of EGL_COVERAGE_SAMPLES_NV specified: " + samples);
736 
737 		final PixelFormat pf = new PixelFormat(this);
738 		pf.setAttrib(COVERAGE_SAMPLES_NV, samples);
739 		pf.setAttrib(COVERAGE_BUFFERS_NV, samples == 0 ? 0 : 1);
740 		return pf;
741 	}
742 
743 	/**
744 	 * Returns a new PixelFormat with the specified EGL_DEPTH_ENCODING_NONLINEAR_NV.
745 	 * Valid values for depthEncoding are EGL_DONT_CARE, EGL_DEPTH_ENCODING_NONE_NV
746 	 * and EGL_DEPTH_ENCODING_NONLINEAR_NV.
747 	 *
748 	 * @param depthEncoding the new EGL_DEPTH_ENCODING_NONLINEAR_NV value
749 	 *
750 	 * @return the new PixelFormat
751 	 */
withDepthEncodingNonlinearNV(final int depthEncoding)752 	public PixelFormat withDepthEncodingNonlinearNV(final int depthEncoding) {
753 		switch ( depthEncoding ) {
754 			case EGL_DONT_CARE:
755 			case EGL_DEPTH_ENCODING_NONE_NV:
756 			case EGL_DEPTH_ENCODING_NONLINEAR_NV:
757 				break;
758 			default:
759 				throw new IllegalArgumentException("Invalid EGL_DEPTH_ENCODING_NONLINEAR_NV value specified: " + depthEncoding);
760 		}
761 
762 		final PixelFormat pf = new PixelFormat(this);
763 		pf.setAttrib(DEPTH_ENCODING_NONLINEAR_NV, depthEncoding);
764 		return pf;
765 	}
766 
767 }