package gl4java.drawable; import java.awt.*; import java.lang.reflect.*; import java.util.*; import sun.awt.*; import gl4java.*; import java.security.*; public class Win32SunJDK13GLDrawableFactory extends SunJDK13GLDrawableFactory { // Use reflection to get access to internal methods in sun.awt.* private static Method getMaxConfigsMethod; private static Method getDefaultPixIDMethod; static { try { getMaxConfigsMethod = (Method) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { return sun.awt.Win32GraphicsDevice.class. getDeclaredMethod("getMaxConfigs", new Class[] { Integer.TYPE }); } catch (Exception e) { e.printStackTrace(); throw new InternalError(e.toString()); } }}); getMaxConfigsMethod.setAccessible(true); getDefaultPixIDMethod = (Method) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { return sun.awt.Win32GraphicsDevice.class. getDeclaredMethod("getDefaultPixID", new Class[] { Integer.TYPE }); } catch (Exception e) { e.printStackTrace(); throw new InternalError(e.toString()); } }}); getDefaultPixIDMethod.setAccessible(true); } catch (Exception e) { e.printStackTrace(); throw new InternalError(e.toString()); } } public Win32SunJDK13GLDrawableFactory() { // describeAllGraphicsConfigurations(); } public GraphicsConfiguration getGraphicsConfiguration(GLCapabilities capabilities, GraphicsDevice device) { // On Windows, ChoosePixelFormat does not work as desired; it // shoehorns the given pixel format descriptor into what a // particular window can render. Instead we enumerate all possible // pixel formats for a given GraphicsDevice and try to find one // matching the given capabilities. To do this we provide // accessors which query the OpenGL-related properties of a // GraphicsConfiguration. FIXME: should implement better selection // algorithm; this one does not choose the most minimal. Win32GraphicsConfig[] configs = getAllGraphicsConfigurations((Win32GraphicsDevice) device); int maxDepth = 0; int maxColor = 0; int maxStencil = 0; int maxAccum = 0; for (int i = 0; i < configs.length; i++) { Win32GraphicsConfig config = configs[i]; if( ! getConfigSupportsOpenGL(config) ) continue; if(getConfigDepthBits(config)>maxDepth) maxDepth=getConfigDepthBits(config); if(getConfigColorBits(config)>maxColor) maxColor=getConfigColorBits(config); if(getConfigStencilBits(config)>maxStencil) maxStencil=getConfigStencilBits(config); if(getConfigAccumBits(config)>maxAccum) maxAccum=getConfigAccumBits(config); } if(maxDepth>24) maxDepth=24; /** fall down to overall's maximum **/ if(capabilities.getDepthBits()>maxDepth) capabilities.setDepthBits(maxDepth); if(capabilities.getStencilBits()>maxStencil) capabilities.setStencilBits(maxStencil); if(getCapsColorBits(capabilities)>maxColor) { capabilities.setRedBits(maxColor/3); capabilities.setGreenBits(maxColor/3+maxColor%3); capabilities.setBlueBits(maxColor/3); } if(getCapsAccumBits(capabilities)>maxAccum) { capabilities.setAccumRedBits(maxAccum/3); capabilities.setAccumGreenBits(maxAccum/3+maxAccum%3); capabilities.setAccumBlueBits(maxAccum/3); } Win32GraphicsConfig config = configsSupportsCapabilities(configs, capabilities, maxDepth); if(config!=null) return config; /* lets .. fall down .. individual .. */ /* general normals .. */ boolean tryit = false; if(capabilities.getDepthBits()>24) { capabilities.setDepthBits(24); tryit=true; } else if(capabilities.getDepthBits()>16) { capabilities.setDepthBits(16); tryit=true; } if(getCapsColorBits(capabilities)>24) { capabilities.setRedBits(8); capabilities.setGreenBits(8); capabilities.setBlueBits(8); tryit=true; } if(capabilities.getAlphaBits()>8) { capabilities.setAlphaBits(8); tryit=true; } if(tryit) config = configsSupportsCapabilities(configs, capabilities, maxDepth); if(config!=null) return config; tryit=false; /* no stereo .. */ if(capabilities.getStereo()) { capabilities.setStereo(false); tryit=true; } if(tryit) config = configsSupportsCapabilities(configs, capabilities, maxDepth); if(config!=null) return config; tryit=false; /* stencil<=16 .. */ if(capabilities.getStencilBits()>16) { capabilities.setStencilBits(16); tryit=true; } if(tryit) config = configsSupportsCapabilities(configs, capabilities, maxDepth); if(config!=null) return config; tryit=false; /* accum rgb each <=16.. */ if(getCapsAccumBits(capabilities)>48) { capabilities.setAccumRedBits(16); capabilities.setAccumGreenBits(16); capabilities.setAccumBlueBits(16); tryit=true; } if(tryit) config = configsSupportsCapabilities(configs, capabilities, maxDepth); if(config!=null) return config; tryit=false; /* stencil<=8 .. */ if(capabilities.getStencilBits()>8) { capabilities.setStencilBits(8); tryit=true; } if(tryit) config = configsSupportsCapabilities(configs, capabilities, maxDepth); if(config!=null) return config; tryit=false; /* accum rgb each <=8.. */ if(getCapsAccumBits(capabilities)>24) { capabilities.setAccumRedBits(8); capabilities.setAccumGreenBits(8); capabilities.setAccumBlueBits(8); tryit=true; } if(tryit) config = configsSupportsCapabilities(configs, capabilities, maxDepth); if(config!=null) return config; tryit=false; /* stencil=0 .. */ if(capabilities.getStencilBits()>0) { capabilities.setStencilBits(0); tryit=true; } if(tryit) config = configsSupportsCapabilities(configs, capabilities, maxDepth); if(config!=null) return config; tryit=false; /* alpha=0 */ if(capabilities.getAlphaBits()>0) { capabilities.setAlphaBits(0); tryit=true; } if(tryit) config = configsSupportsCapabilities(configs, capabilities, maxDepth); if(config!=null) return config; tryit=false; return null; } //---------------------------------------------------------------------- // Internals only below this point // private Win32GraphicsConfig configsSupportsCapabilities(Win32GraphicsConfig[] configs, GLCapabilities glCaps, int maxDepth) { if(GLContext.gljNativeDebug) { System.out.println("---------------"); System.out.println("---------------"); System.out.println("---------------"); System.out.println("->check caps: "+glCaps); System.out.println("---------------"); } for (int i = 0; i < configs.length; i++) { if (configSupportsCapabilities(configs[i], glCaps, maxDepth)) { glCaps.setNativeVisualID( (long) configs[i].getVisual() ); return configs[i]; } } return null; } private Win32GraphicsConfig[] getAllGraphicsConfigurations(Win32GraphicsDevice device) { try { int max = ((Integer) getMaxConfigsMethod.invoke(device, new Object[] { new Integer(device.getScreen()) })).intValue(); int defaultPixID = ((Integer) getDefaultPixIDMethod.invoke(device, new Object[] { new Integer(device.getScreen()) })).intValue(); java.util.List l = new ArrayList(max); if (defaultPixID == 0) { // From Win32GraphicsDevice: workaround for failing GDI calls l.add(Win32GraphicsConfig.getConfig(device, defaultPixID)); } else { for (int i = 1; i <= max; i++) { l.add(Win32GraphicsConfig.getConfig(device, i)); } } Win32GraphicsConfig[] configs = new Win32GraphicsConfig[l.size()]; l.toArray(configs); return configs; } catch (Exception e) { e.printStackTrace(); throw new InternalError(e.toString()); } } private boolean configSupportsCapabilities(Win32GraphicsConfig config, GLCapabilities caps, int maxDepth) { boolean res = ( getConfigSupportsOpenGL(config) && getConfigDoubleBuffered(config) == caps.getDoubleBuffered() && caps.getTrueColor() == getConfigTrueColor(config) && caps.getDepthBits() <= getConfigDepthBits(config) && maxDepth >= getConfigDepthBits(config) && caps.getStencilBits() <= getConfigStencilBits(config) && (caps.getStereo() ? getConfigStereo(config):true) && getCapsColorBits(caps) <= getConfigColorBits(config) /* && caps.getAlphaBits() <= getConfigAlphaBits(config) N.A. */ && getCapsAccumBits(caps) <= getConfigAccumBits(config)); if(GLContext.gljNativeDebug) { System.out.println("->against config: "); describeGraphicsConfiguration(config); System.out.println("---------------"); System.out.println("result: "+res); System.out.println("---------------"); } return res; } private static int getCapsColorBits(GLCapabilities caps) { return caps.getRedBits() + caps.getGreenBits() + caps.getBlueBits(); } private static int getCapsAccumBits(GLCapabilities caps) { return caps.getAccumRedBits() + caps.getAccumGreenBits() + caps.getAccumBlueBits(); } private static boolean getConfigSupportsOpenGL(Win32GraphicsConfig config) { return getVisualSupportsOpenGL(getScreen(config), config.getVisual()); } private static boolean getConfigDoubleBuffered(Win32GraphicsConfig config) { return getVisualDoubleBuffered(getScreen(config), config.getVisual()); } private static boolean getConfigTrueColor(Win32GraphicsConfig config) { return getVisualTrueColor(getScreen(config), config.getVisual()); } private static boolean getConfigStereo(Win32GraphicsConfig config) { return getVisualStereo(getScreen(config), config.getVisual()); } private static int getConfigDepthBits(Win32GraphicsConfig config) { return getVisualDepthBits(getScreen(config), config.getVisual()); } private static int getConfigStencilBits(Win32GraphicsConfig config) { return getVisualStencilBits(getScreen(config), config.getVisual()); } private static int getConfigColorShiftBits(Win32GraphicsConfig config) { return getVisualColorShiftBits(getScreen(config), config.getVisual()); } private static int getConfigColorBits(Win32GraphicsConfig config) { return getVisualColorBits(getScreen(config), config.getVisual()); } private static int getConfigAlphaBits(Win32GraphicsConfig config) { return getVisualAlphaBits(getScreen(config), config.getVisual()); } private static int getConfigAccumBits(Win32GraphicsConfig config) { return getVisualAccumBits(getScreen(config), config.getVisual()); } private static int getScreen(Win32GraphicsConfig config) { return ((Win32GraphicsDevice) config.getDevice()).getScreen(); } // Native support routines that are not in GraphicsConfiguration or // Win32GraphicsConfig. These are only necessary on Windows because // X11's glXChooseVisual can implement getGraphicsConfiguration // directly. private static native boolean getVisualSupportsOpenGL (int screen, int pixelFormatIdx); private static native boolean getVisualDoubleBuffered (int screen, int pixelFormatIdx); private static native boolean getVisualTrueColor (int screen, int pixelFormatIdx); private static native boolean getVisualStereo (int screen, int pixelFormatIdx); private static native int getVisualDepthBits (int screen, int pixelFormatIdx); private static native int getVisualStencilBits (int screen, int pixelFormatIdx); private static native int getVisualColorShiftBits (int screen, int pixelFormatIdx); private static native int getVisualColorBits (int screen, int pixelFormatIdx); private static native int getVisualAlphaBits (int screen, int pixelFormatIdx); private static native int getVisualAccumBits (int screen, int pixelFormatIdx); // Debugging only private void describeAllGraphicsConfigurations() { Win32GraphicsConfig[] configs = getAllGraphicsConfigurations( (Win32GraphicsDevice) GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice() ); System.err.println(configs.length + " graphics configurations found"); for (int i = 0; i < configs.length; i++) { System.err.println(i + "."); Win32GraphicsConfig config = configs[i]; describeGraphicsConfiguration(config); System.err.println(); } } private void describeGraphicsConfiguration(Win32GraphicsConfig config) { boolean supportsOpenGL = getConfigSupportsOpenGL(config); System.err.println(" SupportsOpenGL: " + supportsOpenGL); if (supportsOpenGL) { System.err.print(" DoubleBuffered: " + getConfigDoubleBuffered(config)); System.err.print(" TrueColor: " + getConfigTrueColor(config)); System.err.println(" Stereo: " + getConfigStereo(config)); System.err.print(" DepthBits: " + getConfigDepthBits(config)); System.err.println(" StencilBits: " + getConfigStencilBits(config)); System.err.print(" ColorBits: " + getConfigColorBits(config)); System.err.print(" AlphaBits: " + getConfigAlphaBits(config)); System.err.println(" AccumBits: " + getConfigAccumBits(config)); } } }