package org.mt4j; import java.awt.Component; import java.awt.Dimension; import java.awt.DisplayMode; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Properties; import javax.media.opengl.GL; import javax.swing.ImageIcon; import org.mt4j.input.DesktopInputManager; import org.mt4j.util.DesktopPlatformUtil; import org.mt4j.util.PlatformUtil; import org.mt4j.util.MT4jSettings; import org.mt4j.util.SettingsMenu; import org.mt4j.util.animation.ani.AniAnimation; import org.mt4j.util.font.FontManager; import org.mt4j.util.font.fontFactories.BitmapFontFactory; import org.mt4j.util.font.fontFactories.SvgFontFactory; import org.mt4j.util.font.fontFactories.TTFontFactory; import org.mt4j.util.logging.ILogger; import org.mt4j.util.logging.Log4jLogger; import org.mt4j.util.logging.MTLoggerFactory; import org.mt4j.util.math.Tools3D; import org.mt4j.util.modelImporter.ModelImporterFactory; import org.mt4j.util.modelImporter.file3ds.Model3dsFileFactory; import org.mt4j.util.modelImporter.fileObj.ModelObjFileFactory; import org.mt4j.util.opengl.GLCommon; import org.mt4j.util.opengl.GLFBO; import org.mt4j.util.opengl.JoglGL10; import org.mt4j.util.opengl.JoglGL11; import org.mt4j.util.opengl.JoglGL20Plus; import processing.core.PApplet; import processing.opengl.PGraphicsOpenGL; public abstract class MTApplication extends AbstractMTApplication { private static final long serialVersionUID = 1L; static{ //Initialize Loggin facilities - IMPORTANT TO DO THIS ASAP!////// MTLoggerFactory.setLoggerProvider(new Log4jLogger()); //FIXME TEST // MTLoggerFactory.setLoggerProvider(new JavaLogger()); //FIXME TEST logger = MTLoggerFactory.getLogger(AbstractMTApplication.class.getName()); logger.setLevel(ILogger.INFO); } private static boolean settingsLoadedFromFile = false; //cant initialize in constructor, need it before that! protected ImageIcon mt4jIcon; public static String CUSTOM_OPENGL_GRAPHICS = "org.mt4j.util.opengl.CustomPGraphicsOpenGL"; //PApplet.OPENGL // public static String CUSTOM_OPENGL_GRAPHICS = OPENGL; //PApplet.OPENGL public MTApplication(){ super(); } /** * Initializes the processings settings. * Call this method in your main method prior to anything else! */ public static void initialize(){ initialize(new CurrentClassGetter().getClassName()); } public static void initialize(boolean showSettingsMenu){ initialize(new CurrentClassGetter().getClassName(), showSettingsMenu); } public static void initialize(String classToInstantiate){ initialize(classToInstantiate, false); } /** * Initializes the processing's settings. * Call this method in your main method prior to anything else! * We have to provide the fully qualified name to the class that * we are calling this from. (Should be our MTAplication extended class) * This is needed because processing will use the reflection api to instantiate * an instance of the MTApplication class. * <br>E.g.: <code>initialize("myPackage.myMainClass");</code> * * @param classToInstantiate the class to instantiate * @param showSettingsMenu show settings menu */ public static void initialize(String classToInstantiate, boolean showSettingsMenu){ if (showSettingsMenu){ settingsLoadedFromFile = true; SettingsMenu menu = new SettingsMenu(classToInstantiate); menu.setVisible(true); }else{ getSettingsFromFile(); // Launch processing PApplet main() function if (MT4jSettings.getInstance().isFullscreen()){ if (MT4jSettings.getInstance().isFullscreenExclusive()){ PApplet.main(new String[] { "--display=" + MT4jSettings.getInstance().getDisplay(), "--present", "--exclusive", "--bgcolor=#000000", "--hide-stop", classToInstantiate} ); }else{ PApplet.main(new String[] { "--display=" + MT4jSettings.getInstance().getDisplay(), "--present", "--bgcolor=#000000", "--hide-stop", classToInstantiate} ); } }else{ PApplet.main(new String[] { "--display=" + MT4jSettings.getInstance().getDisplay(), classToInstantiate }); } } } protected static void getSettingsFromFile(){ //Load some properties from Settings.txt file Properties properties = new Properties(); try { try { FileInputStream fi = new FileInputStream(MT4jSettings.getInstance().getDefaultSettingsPath() + "Settings.txt"); properties.load(fi); } catch (FileNotFoundException e) { logger.debug("Couldnt load Settings.txt from the File system. Trying to load it as a resource.."); InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("Settings.txt"); if (in != null){ properties.load(in); }else{ logger.debug("Couldnt load Settings.txt as a resource. Using defaults."); throw new FileNotFoundException("Couldnt load Settings.txt as a resource"); } } MT4jSettings.fullscreen = Boolean.parseBoolean(properties.getProperty("Fullscreen", Boolean.valueOf(MT4jSettings.getInstance().isFullscreen()).toString()).trim()); //Use java's fullscreen exclusive mode (real fullscreen) or just use an undecorated window at fullscreen size MT4jSettings.getInstance().fullscreenExclusive = Boolean.parseBoolean(properties.getProperty("FullscreenExclusive", Boolean.valueOf(MT4jSettings.getInstance().isFullscreenExclusive()).toString()).trim()); //Which display to use for fullscreen MT4jSettings.getInstance().display = Integer.parseInt(properties.getProperty("Display", String.valueOf(MT4jSettings.getInstance().getDisplay())).trim()); MT4jSettings.getInstance().windowWidth = Integer.parseInt(properties.getProperty("DisplayWidth", String.valueOf(MT4jSettings.getInstance().getWindowWidth())).trim()); MT4jSettings.getInstance().windowHeight = Integer.parseInt(properties.getProperty("DisplayHeight", String.valueOf(MT4jSettings.getInstance().getWindowHeight())).trim()); //FIXME at fullscreen really use the screen dimension? -> we need to set the native resoultion ourselves! //so we can have a lower fullscreen resolution than the screen dimensions if (MT4jSettings.getInstance().isFullscreen() && !MT4jSettings.getInstance().isFullscreenExclusive()){ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); MT4jSettings.getInstance().windowWidth = screenSize.width; MT4jSettings.getInstance().windowHeight = screenSize.height; } /* //Comment this to not change the window width to the screen width in fullscreen mode else{ } */ MT4jSettings.getInstance().maxFrameRate = Integer.parseInt(properties.getProperty("MaximumFrameRate", String.valueOf(MT4jSettings.getInstance().getMaxFrameRate())).trim()); MT4jSettings.getInstance().renderer = Integer.parseInt(properties.getProperty("Renderer", String.valueOf(MT4jSettings.getInstance().getRendererMode())).trim()); MT4jSettings.getInstance().numSamples = Integer.parseInt(properties.getProperty("OpenGLAntialiasing", String.valueOf(MT4jSettings.getInstance().getNumSamples())).trim()); MT4jSettings.getInstance().vSync = Boolean.parseBoolean(properties.getProperty("Vertical_sync", Boolean.valueOf(MT4jSettings.getInstance().isVerticalSynchronization()).toString()).trim()); //Set frametitle String frameTitle = properties.getProperty("Frametitle", MT4jSettings.getInstance().getFrameTitle().trim()); MT4jSettings.getInstance().frameTitle = frameTitle; } catch (Exception e) { logger.error("Error while loading Settings.txt. Using defaults."); } settingsLoadedFromFile = true; } /** * *********************************************************** * Processings setup. this is called once when the applet is started * Used to define some initial settings * **********************************************************. */ @Override public void setup(){ if (!settingsLoadedFromFile){ //because initialize() method isnt called in the swing integration/example getSettingsFromFile(); } // Applet size - size() must be the first command in setup() method if (MT4jSettings.getInstance().getRendererMode() == MT4jSettings.OPENGL_MODE) this.size(MT4jSettings.getInstance().getWindowWidth(), MT4jSettings.getInstance().getWindowHeight(), CUSTOM_OPENGL_GRAPHICS); else if (MT4jSettings.getInstance().getRendererMode() == MT4jSettings.P3D_MODE) this.size(MT4jSettings.getInstance().getWindowWidth(), MT4jSettings.getInstance().getWindowHeight(), PApplet.P3D); //TOGGLES ALWAYS ON TOP MODE //this.frame.setAlwaysOnTop(true); //Add default font factories ///////////// //Register default font factories FontManager.getInstance().registerFontFactory(".ttf", new TTFontFactory()); FontManager.getInstance().registerFontFactory(".svg", new SvgFontFactory()); BitmapFontFactory bitmapFontFactory = new BitmapFontFactory(); // this.registerFontFactory(".ttf", bitmapFontFactory); // TEST FontManager.getInstance().registerFontFactory("", bitmapFontFactory); FontManager.getInstance().registerFontFactory(".vlw", bitmapFontFactory); FontManager.getInstance().registerFontFactory(".otf", bitmapFontFactory); FontManager.getInstance().registerFontFactory(".bold", bitmapFontFactory); FontManager.getInstance().registerFontFactory(".bolditalic", bitmapFontFactory); FontManager.getInstance().registerFontFactory(".italic", bitmapFontFactory); FontManager.getInstance().registerFontFactory(".plain", bitmapFontFactory); ////////////////////// /////////////////////// //FIXME TEST PlatformUtil.setGraphicsUtilProvider(new DesktopPlatformUtil(this)); /////////////////////// ///////////////////// //Add default 3D model factories for .3ds and for .obj files ModelImporterFactory.registerModelImporterFactory(".3ds", Model3dsFileFactory.class); ModelImporterFactory.registerModelImporterFactory(".obj", ModelObjFileFactory.class); //////////////////// //Check if OS 32/64 Bit String bit = System.getProperty("sun.arch.data.model"); logger.info("Platform: \"" + System.getProperty("os.name") + "\" -> Version: \"" + System.getProperty("os.version") + "\" -> JVM Bit: \"" + bit + "\""); MT4jSettings.getInstance().architecture = bit.contains("64")? MT4jSettings.ARCHITECTURE_64_BIT : MT4jSettings.ARCHITECTURE_32_BIT; //Switch to different resolution in fullscreen exclusive mode if neccessary Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); if (MT4jSettings.getInstance().isFullscreen() && MT4jSettings.getInstance().isFullscreenExclusive() && MT4jSettings.getInstance().getWindowWidth() != screenSize.width && MT4jSettings.getInstance().getWindowHeight() != screenSize.height){ switchResolution(); } /* //Processing Bug? seems to always use 2 samples if (MT4jSettings.getInstance().getNumSamples() <= 0){ hint(DISABLE_OPENGL_2X_SMOOTH); }else if (MT4jSettings.getInstance().getNumSamples() == 2){ //Nothing to set, Processing default anyway }else if (MT4jSettings.getInstance().getNumSamples() == 4){ hint(DISABLE_OPENGL_2X_SMOOTH); hint(ENABLE_OPENGL_4X_SMOOTH); } */ //hint(ENABLE_DEPTH_SORT); // Enable primitive z-sorting of triangles and lines in P3D and OPENGL. This can slow performance considerably, and the algorithm is not yet perfect. //hint(DISABLE_ERROR_REPORT); // Speeds up the OPENGL renderer setting by not checking for errors while running. //hint(ENABLE_ACCURATE_TEXTURES); //Enables better texture accuracy for the P3D renderer. This option will do a better job of dealing with textures in perspective. // Save this applets rendering thread for reference this.renderThread = Thread.currentThread(); //System.out.println("Current Thread: "+ Thread.currentThread()); // Set frame icon image try { //Set the window frame's title frame.setTitle(MT4jSettings.getInstance().getFrameTitle()); this.mt4jIcon = new ImageIcon(Thread.currentThread().getContextClassLoader().getResource(MT4jSettings.getInstance().getDefaultImagesPath() + "MT4j.gif")); this.frame.setIconImage(mt4jIcon.getImage()); }catch (Exception e){ e.printStackTrace(); } logger.info("MT4j window dimensions: \"" + MT4jSettings.getInstance().getWindowWidth() + " X " + MT4jSettings.getInstance().getWindowHeight() + "\""); // //Set background color // pContext.background(MT4jSettings.getInstance().getBackgroundClearColor()); background(150); //Set the framerate frameRate(MT4jSettings.getInstance().getMaxFrameRate()); logger.info("Maximum framerate: \"" + MT4jSettings.getInstance().getMaxFrameRate() + "\""); //FIXME TODO add in settings.txt? hint(AbstractMTApplication.DISABLE_OPENGL_ERROR_REPORT); MT4jSettings.getInstance().programStartTime = System.currentTimeMillis(); //Apply some opengl settings like V-Syncing or multi-Sampling this.applyOpenGLStartSettings(); //Create a new inputsourcePool if (getInputManager() == null){ //only set the default inputManager if none is set yet this.setInputManager(new DesktopInputManager(this, true)); } AniAnimation.init(this); //Initialize Ani animation library /* * Resizable Window test * Problems: * - all textures, shaders etc get destroyed because a new gl context is created * - cursor coordiantes are calculated wrong? we prolly have to update Papplet width/height frame.setResizable(true); frame.addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent e) { if(e.getSource() == frame) { frame.setSize(frame.getWidth(), minHeight); } } } ); */ //Call startup at the end of setup(). Should be overridden in extending classes this.startUp(); } protected void loadGL(){ String version = ((PGraphicsOpenGL)g).gl.glGetString(GL.GL_VERSION); logger.info("OpenGL Version: " + version); int major = Integer.parseInt("" + version.charAt(0)); int minor = Integer.parseInt("" + version.charAt(2)); this.gl11Supported = false; this.gl20Supported = false; if (major >= 2) { // JoglGL20 jogl20 = new JoglGL20(((PGraphicsOpenGL)g).gl); JoglGL20Plus jogl20 = new JoglGL20Plus(((PGraphicsOpenGL)g).gl); iGL20 = jogl20; //FIXME ADDED iGL10 = jogl20; iGL11 = jogl20; iGL11Plus = jogl20; glCommon = iGL20; this.gl20Supported = true; this.gl11Supported = true; this.gl11PlusSupported = true; } else { if (major == 1 && minor < 5) { iGL10 = new JoglGL10(((PGraphicsOpenGL)g).gl); } else { iGL11 = new JoglGL11(((PGraphicsOpenGL)g).gl); iGL10 = iGL11; this.gl11Supported = true; } glCommon = iGL10; } } /** * Apply open gl start settings. */ private void applyOpenGLStartSettings(){ //TODO pa.smooth() / pa.noSmooth() ver�ndert auch line_smooth! //f�r test ob multisampling lines ohne Line_smooth okay rendered m�ssen //sicherheitshalber auch die pa.smoot() etc abgefangen werden und line_smooth immer disabled sein! //TODO check line drawing and abstractvisible at stencil in this context (line_smooth) //TODO // - if multisampling enabled dont do line smoothing at all // - OR: disable multisampling each time before doing line_smoothing! (better but expensive?) // -> info: disabling multisampling isnt possible at runtime.. // - or disable mutisample before drawing with line_smooth! //TOOD dont use lines to smooth some objects then (fonts, etc) if (MT4jSettings.getInstance().isOpenGlMode() ){ ////////////////////////////// this.loadGL(); ////////////////////////// // GL gl = Tools3D.getGL(this); GLCommon gl = getGLCommon(); logger.info("OpenGL Version: \"" + gl.glGetString(GL.GL_VERSION) + "\"" + " - Vendor: \"" + gl.glGetString(GL.GL_VENDOR) + "\"" + " - Renderer: \"" + gl.glGetString(GL.GL_RENDERER) + "\""); // logger.info("Shading language version: \"" + gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION) + "\""); logger.info("Non power of two texture sizes allowed: \"" + Tools3D.supportsNonPowerOfTwoTexture(this) + "\""); logger.info("OpenGL Framebuffer Object Extension available: \"" + GLFBO.isSupported(this) + "\""); //Set VSyncing on -> to avoid tearing //-> check if gfx card settings allow apps to set it! //-> Use with caution! only use with fps rate == monitor Hz! //and fps never drop below Hz! -> else choppy! //-> only works with opengl! Tools3D.setVSyncing(this, MT4jSettings.getInstance().isVerticalSynchronization()); logger.info("Vertical Sync enabled: \"" + MT4jSettings.getInstance().isVerticalSynchronization() + "\""); if ( MT4jSettings.getInstance().isMultiSampling()){ gl.glEnable(GL.GL_MULTISAMPLE); // gl.glDisable(GL.GL_MULTISAMPLE); logger.info("OpenGL multi-sampling enabled."); } gl.glEnable(GL.GL_LINE_SMOOTH); // gl.glDisable(GL.GL_LINE_SMOOTH); } } protected void switchResolution() { logger.debug("Switching resolution.."); try { frame.enableInputMethods(false); frame.setIgnoreRepaint(true); final GraphicsDevice myGraphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); // Get the current display mode final DisplayMode previousDisplayMode= myGraphicsDevice.getDisplayMode(); // final int width = 1280; // final int height = 768; final int width = MT4jSettings.getInstance().getWindowWidth(); final int height = MT4jSettings.getInstance().getWindowHeight(); int bitDepth = 32; int refreshRate = myGraphicsDevice.getDisplayMode().getRefreshRate(); myGraphicsDevice.setFullScreenWindow(this.frame); // Check if display mode changes are supported by the OS if (myGraphicsDevice.isDisplayChangeSupported()) { // Get all available display modes DisplayMode[] displayModes = myGraphicsDevice.getDisplayModes(); DisplayMode multiBitsDepthSupportedDisplayMode = null; DisplayMode refreshRateUnknownDisplayMode = null; DisplayMode multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode = null; DisplayMode matchingDisplayMode = null; DisplayMode currentDisplayMode; // Look for the display mode that matches with our parameters // Look for some display modes that are close to these parameters // and that could be used as substitutes // On some machines, the refresh rate is unknown and/or multi bit // depths are supported. If you try to force a particular refresh // rate or a bit depth, you might find no available display mode // that matches exactly with your parameters for (int i = 0; i < displayModes.length && matchingDisplayMode == null; i++) { currentDisplayMode = displayModes[i]; if (currentDisplayMode.getWidth() == width && currentDisplayMode.getHeight() == height) { if (currentDisplayMode.getBitDepth() == bitDepth) { if (currentDisplayMode.getRefreshRate() == refreshRate) { matchingDisplayMode = currentDisplayMode; } else if (currentDisplayMode.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN) { refreshRateUnknownDisplayMode = currentDisplayMode; } } else if (currentDisplayMode.getBitDepth() == DisplayMode.BIT_DEPTH_MULTI) { if (currentDisplayMode.getRefreshRate() == refreshRate) { multiBitsDepthSupportedDisplayMode = currentDisplayMode; } else if (currentDisplayMode.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN) { multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode = currentDisplayMode; } } } } DisplayMode nextDisplayMode = null; if (matchingDisplayMode != null) { nextDisplayMode = matchingDisplayMode; } else if (multiBitsDepthSupportedDisplayMode != null) { nextDisplayMode = multiBitsDepthSupportedDisplayMode; } else if (refreshRateUnknownDisplayMode != null) { nextDisplayMode = refreshRateUnknownDisplayMode; } else if (multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode != null) { nextDisplayMode = multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode; } else { // isFullScreenSupported = false; logger.error("No matching fullscreen display mode found!"); } if (nextDisplayMode != null){ /* DisplayMode myDisplayMode = new DisplayMode( width, height, myGraphicsDevice.getDisplayMode().getBitDepth(), DisplayMode.REFRESH_RATE_UNKNOWN); myGraphicsDevice.setDisplayMode(myDisplayMode); */ myGraphicsDevice.setDisplayMode(nextDisplayMode); Component[] myComponents = frame.getComponents(); for (int i = 0; i < myComponents.length; i++) { if (myComponents[i] instanceof PApplet) { myComponents[i].setLocation(0, 0); } } frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent e) { // If required, restore the previous display mode myGraphicsDevice.setDisplayMode(previousDisplayMode); // If required, get back to the windowed mode if (myGraphicsDevice.getFullScreenWindow() == frame) { myGraphicsDevice.setFullScreenWindow(null); } } }); } } } catch (Exception e) { e.printStackTrace(); } } // public GL getGL(){ // return ((PGraphicsOpenGL)g).gl; // } // // public GL beginGL(){ // return ((PGraphicsOpenGL)g).beginGL(); // } // // public void endGL(){ // ((PGraphicsOpenGL)g).endGL(); // } }