/** Return true if we support high-quality avatars */ public static boolean supportsHighQualityAvatars() { String shaderCheck = System.getProperty("avatar.shaderCheck"); boolean shaderPass = true; // Check to see if the system supports OpenGL 2.0. If not, then // always use the low-detail avatar character RenderManager rm = ClientContextJME.getWorldManager().getRenderManager(); if (shaderCheck != null && shaderCheck.equals("true")) { shaderPass = rm.getContextCaps().GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB >= 512; } // Issue 1114: make sure the system is telling the truth about what // it supports by trying a mock shader program boolean uniformsPass = shaderPass && ShaderTest.getInstance().testShaders(); logger.warning( "Checking avatar detail level. OpenGL20: " + rm.supportsOpenGL20() + " ShaderCheck: " + shaderPass + " UniformsCheck: " + uniformsPass); // OWL issue #110 -- ignore the value of supportsOpenGL20() here. This // is known to report false negatives on at least one graphics card. // Our shader test should do an adequate job determining whether a // graphics card supports the OpenGL 2.0 features we use. // Update: fixed version of supportsOpenGL20 should properly detect // version. return rm.supportsOpenGL20() && shaderPass && uniformsPass; }
/** * Load and return the avatar. To make this the current avatar changeAvatar() must be called * * @param avatarConfigURL * @return */ private WlAvatarCharacter loadAvatarInternal(AvatarConfigInfo avatarConfigInfo) throws MalformedURLException, IOException { WlAvatarCharacter ret = null; PMatrix origin = new PMatrix(); CellTransform transform = cell.getLocalTransform(); origin.setTranslation(transform.getTranslation(null)); origin.setRotation(transform.getRotation(null)); // Create the character String avatarDetail = System.getProperty("avatar.detail", "high"); // check if we support high-quality avatars if (!supportsHighQualityAvatars()) { logger.warning("Forcing low detail."); avatarDetail = "low"; } // Check to see if there is no avatar configuration info and/or if we // have the avatar details set to "low". If so, then use the default AvatarLoaderRegistry registry = AvatarLoaderRegistry.getAvatarLoaderRegistry(); if (avatarConfigInfo == null || avatarDetail.equalsIgnoreCase("low")) { // Find the "default" factory to generate an avatar. Ask it to // loader the avatar. If it does not exist (it should), simply // log an error andr return. AvatarLoaderFactorySPI factory = registry.getDefaultAvatarLoaderFactory(); if (factory == null) { logger.warning("No default avatar factory is registered."); return null; } // We need to rewrite the AvatarConfigInfo object here a bit, // otherwise, the loader may still loader the wrong avatar. If // we set the URL in the AvatarConfigInfo to null, that should do // the trick. (Note that since we manually obtained the // AvatarLoaderFactorySPI, we don't need to update the factory // class name in the AvatarConfigInfo object, but we do anyway). String defaultClassName = factory.getClass().getName(); AvatarConfigInfo defaultInfo = new AvatarConfigInfo(null, defaultClassName); // Go ahead and load the default avatar ret = factory.getAvatarLoader().getAvatarCharacter(cell, username, defaultInfo); } else { // If the avatar has a non-null configuration information, then // ask the loader factory to generate a new loader for this avatar String className = avatarConfigInfo.getLoaderFactoryClassName(); if (className == null) { logger.warning( "No class name given for avatar configuration" + " with url " + avatarConfigInfo.getAvatarConfigURL()); return null; } // Find the avatar factory, if it does not exist, return an error AvatarLoaderFactorySPI factory = registry.getAvatarLoaderFactory(className); if (factory == null) { logger.warning( "No avatar loader factory for the class name " + className + " with url " + avatarConfigInfo.getAvatarConfigURL()); return null; } // Ask the avatar loader to create and return an avatar character ret = factory.getAvatarLoader().getAvatarCharacter(cell, username, avatarConfigInfo); } ret.getModelInst().getTransform().getLocalMatrix(true).set(origin); // XXX NPC HACK XXX // TODO - remove hardcoded npc support // if (username.equals("npc") && avatarConfigURL != null) { // String u = avatarConfigURL.getFile(); // username = u.substring(u.lastIndexOf('/') + 1, u.lastIndexOf('.')); // } // Sets the Z-buffer state on the external kids root Node external = ret.getJScene().getExternalKidsRoot(); setZBufferState(external); // JSCENE HAS NOT CHILDREN, so this does nothing // ret.getJScene().updateGeometricState(0, true); // GraphicsUtils.printGraphBounds(ret.getJScene()); // JScene jscene = avatar.getJScene(); // jscene.renderToggle(); // both renderers // jscene.renderToggle(); // jme renderer only // jscene.setRenderPRendererMesh(true); // Force pRenderer to be instantiated // jscene.toggleRenderPRendererMesh(); // turn off mesh // jscene.toggleRenderBoundingVolume(); // turn off bounds return ret; }