Merge branch 'master' into PBRisComing
Conflicts: jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
This commit is contained in:
commit
e1d0e06c59
File diff suppressed because it is too large
Load Diff
@ -195,19 +195,6 @@ public class AndroidHarnessFragment extends Fragment implements
|
||||
*/
|
||||
protected String exitDialogMessage = "Use your home key to bring this app into the background or exit to terminate it.";
|
||||
|
||||
/**
|
||||
* Set the screen window mode. If screenFullSize is true, then the
|
||||
* notification bar and title bar are removed and the screen covers the
|
||||
* entire display. If screenFullSize is false, then the notification bar
|
||||
* remains visible if screenShowTitle is true while screenFullScreen is
|
||||
* false, then the title bar is also displayed under the notification bar.
|
||||
*/
|
||||
protected boolean screenFullScreen = true;
|
||||
/**
|
||||
* if screenShowTitle is true while screenFullScreen is false, then the
|
||||
* title bar is also displayed under the notification bar
|
||||
*/
|
||||
protected boolean screenShowTitle = true;
|
||||
/**
|
||||
* Splash Screen picture Resource ID. If a Splash Screen is desired, set
|
||||
* splashPicID to the value of the Resource ID (i.e. R.drawable.picname). If
|
||||
|
@ -74,7 +74,7 @@ public class VideoRecorderAppState extends AbstractAppState {
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread th = new Thread(r);
|
||||
th.setName("jME Video Processing Thread");
|
||||
th.setName("jME3 Video Processor");
|
||||
th.setDaemon(true);
|
||||
return th;
|
||||
}
|
||||
|
@ -1,265 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.input.android;
|
||||
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import com.jme3.input.RawInputListener;
|
||||
import com.jme3.input.TouchInput;
|
||||
import com.jme3.input.event.InputEvent;
|
||||
import com.jme3.input.event.KeyInputEvent;
|
||||
import com.jme3.input.event.MouseButtonEvent;
|
||||
import com.jme3.input.event.MouseMotionEvent;
|
||||
import com.jme3.input.event.TouchEvent;
|
||||
import com.jme3.system.AppSettings;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* <code>AndroidInput</code> is the main class that connects the Android system
|
||||
* inputs to jME. It serves as the manager that gathers inputs from the various
|
||||
* Android input methods and provides them to jME's <code>InputManager</code>.
|
||||
*
|
||||
* @author iwgeric
|
||||
*/
|
||||
public class AndroidInputHandler implements TouchInput {
|
||||
private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName());
|
||||
|
||||
// Custom settings
|
||||
private boolean mouseEventsEnabled = true;
|
||||
private boolean mouseEventsInvertX = false;
|
||||
private boolean mouseEventsInvertY = false;
|
||||
private boolean keyboardEventsEnabled = false;
|
||||
private boolean joystickEventsEnabled = false;
|
||||
private boolean dontSendHistory = false;
|
||||
|
||||
|
||||
// Internal
|
||||
private GLSurfaceView view;
|
||||
private AndroidTouchHandler touchHandler;
|
||||
private AndroidKeyHandler keyHandler;
|
||||
private AndroidGestureHandler gestureHandler;
|
||||
private boolean initialized = false;
|
||||
private RawInputListener listener = null;
|
||||
private ConcurrentLinkedQueue<InputEvent> inputEventQueue = new ConcurrentLinkedQueue<InputEvent>();
|
||||
private final static int MAX_TOUCH_EVENTS = 1024;
|
||||
private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS);
|
||||
private float scaleX = 1f;
|
||||
private float scaleY = 1f;
|
||||
|
||||
|
||||
public AndroidInputHandler() {
|
||||
int buildVersion = Build.VERSION.SDK_INT;
|
||||
logger.log(Level.INFO, "Android Build Version: {0}", buildVersion);
|
||||
if (buildVersion >= 14) {
|
||||
// add support for onHover and GenericMotionEvent (ie. gamepads)
|
||||
gestureHandler = new AndroidGestureHandler(this);
|
||||
touchHandler = new AndroidTouchHandler14(this, gestureHandler);
|
||||
keyHandler = new AndroidKeyHandler(this);
|
||||
} else if (buildVersion >= 8){
|
||||
gestureHandler = new AndroidGestureHandler(this);
|
||||
touchHandler = new AndroidTouchHandler(this, gestureHandler);
|
||||
keyHandler = new AndroidKeyHandler(this);
|
||||
}
|
||||
}
|
||||
|
||||
public AndroidInputHandler(AndroidTouchHandler touchInput,
|
||||
AndroidKeyHandler keyInput, AndroidGestureHandler gestureHandler) {
|
||||
this.touchHandler = touchInput;
|
||||
this.keyHandler = keyInput;
|
||||
this.gestureHandler = gestureHandler;
|
||||
}
|
||||
|
||||
public void setView(View view) {
|
||||
if (touchHandler != null) {
|
||||
touchHandler.setView(view);
|
||||
}
|
||||
if (keyHandler != null) {
|
||||
keyHandler.setView(view);
|
||||
}
|
||||
if (gestureHandler != null) {
|
||||
gestureHandler.setView(view);
|
||||
}
|
||||
this.view = (GLSurfaceView)view;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
public float invertX(float origX) {
|
||||
return getJmeX(view.getWidth()) - origX;
|
||||
}
|
||||
|
||||
public float invertY(float origY) {
|
||||
return getJmeY(view.getHeight()) - origY;
|
||||
}
|
||||
|
||||
public float getJmeX(float origX) {
|
||||
return origX * scaleX;
|
||||
}
|
||||
|
||||
public float getJmeY(float origY) {
|
||||
return origY * scaleY;
|
||||
}
|
||||
|
||||
public void loadSettings(AppSettings settings) {
|
||||
keyboardEventsEnabled = settings.isEmulateKeyboard();
|
||||
mouseEventsEnabled = settings.isEmulateMouse();
|
||||
mouseEventsInvertX = settings.isEmulateMouseFlipX();
|
||||
mouseEventsInvertY = settings.isEmulateMouseFlipY();
|
||||
joystickEventsEnabled = settings.useJoysticks();
|
||||
|
||||
// view width and height are 0 until the view is displayed on the screen
|
||||
if (view.getWidth() != 0 && view.getHeight() != 0) {
|
||||
scaleX = (float)settings.getWidth() / (float)view.getWidth();
|
||||
scaleY = (float)settings.getHeight() / (float)view.getHeight();
|
||||
}
|
||||
logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}",
|
||||
new Object[]{scaleX, scaleY});
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
// JME3 Input interface
|
||||
@Override
|
||||
public void initialize() {
|
||||
touchEventPool.initialize();
|
||||
if (touchHandler != null) {
|
||||
touchHandler.initialize();
|
||||
}
|
||||
if (keyHandler != null) {
|
||||
keyHandler.initialize();
|
||||
}
|
||||
if (gestureHandler != null) {
|
||||
gestureHandler.initialize();
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
initialized = false;
|
||||
|
||||
touchEventPool.destroy();
|
||||
if (touchHandler != null) {
|
||||
touchHandler.destroy();
|
||||
}
|
||||
if (keyHandler != null) {
|
||||
keyHandler.destroy();
|
||||
}
|
||||
if (gestureHandler != null) {
|
||||
gestureHandler.destroy();
|
||||
}
|
||||
|
||||
setView(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputListener(RawInputListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getInputTimeNanos() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (listener != null) {
|
||||
InputEvent inputEvent;
|
||||
|
||||
while ((inputEvent = inputEventQueue.poll()) != null) {
|
||||
if (inputEvent instanceof TouchEvent) {
|
||||
listener.onTouchEvent((TouchEvent)inputEvent);
|
||||
} else if (inputEvent instanceof MouseButtonEvent) {
|
||||
listener.onMouseButtonEvent((MouseButtonEvent)inputEvent);
|
||||
} else if (inputEvent instanceof MouseMotionEvent) {
|
||||
listener.onMouseMotionEvent((MouseMotionEvent)inputEvent);
|
||||
} else if (inputEvent instanceof KeyInputEvent) {
|
||||
listener.onKeyEvent((KeyInputEvent)inputEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
public TouchEvent getFreeTouchEvent() {
|
||||
return touchEventPool.getNextFreeEvent();
|
||||
}
|
||||
|
||||
public void addEvent(InputEvent event) {
|
||||
inputEventQueue.add(event);
|
||||
if (event instanceof TouchEvent) {
|
||||
touchEventPool.storeEvent((TouchEvent)event);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSimulateMouse(boolean simulate) {
|
||||
this.mouseEventsEnabled = simulate;
|
||||
}
|
||||
|
||||
public boolean isSimulateMouse() {
|
||||
return mouseEventsEnabled;
|
||||
}
|
||||
|
||||
public boolean isMouseEventsInvertX() {
|
||||
return mouseEventsInvertX;
|
||||
}
|
||||
|
||||
public boolean isMouseEventsInvertY() {
|
||||
return mouseEventsInvertY;
|
||||
}
|
||||
|
||||
public void setSimulateKeyboard(boolean simulate) {
|
||||
this.keyboardEventsEnabled = simulate;
|
||||
}
|
||||
|
||||
public boolean isSimulateKeyboard() {
|
||||
return keyboardEventsEnabled;
|
||||
}
|
||||
|
||||
public void setOmitHistoricEvents(boolean dontSendHistory) {
|
||||
this.dontSendHistory = dontSendHistory;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.input.android;
|
||||
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import com.jme3.input.RawInputListener;
|
||||
import com.jme3.input.TouchInput;
|
||||
import com.jme3.input.event.InputEvent;
|
||||
import com.jme3.input.event.KeyInputEvent;
|
||||
import com.jme3.input.event.MouseButtonEvent;
|
||||
import com.jme3.input.event.MouseMotionEvent;
|
||||
import com.jme3.input.event.TouchEvent;
|
||||
import com.jme3.system.AppSettings;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* <code>AndroidInput</code> is the main class that connects the Android system
|
||||
* inputs to jME. It serves as the manager that gathers inputs from the various
|
||||
* Android input methods and provides them to jME's <code>InputManager</code>.
|
||||
*
|
||||
* @author iwgeric
|
||||
*/
|
||||
public class AndroidInputHandler implements TouchInput {
|
||||
private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName());
|
||||
|
||||
// Custom settings
|
||||
private boolean mouseEventsEnabled = true;
|
||||
private boolean mouseEventsInvertX = false;
|
||||
private boolean mouseEventsInvertY = false;
|
||||
private boolean keyboardEventsEnabled = false;
|
||||
private boolean dontSendHistory = false;
|
||||
|
||||
|
||||
// Internal
|
||||
private GLSurfaceView view;
|
||||
private AndroidTouchHandler touchHandler;
|
||||
private AndroidKeyHandler keyHandler;
|
||||
private AndroidGestureHandler gestureHandler;
|
||||
private boolean initialized = false;
|
||||
private RawInputListener listener = null;
|
||||
private ConcurrentLinkedQueue<InputEvent> inputEventQueue = new ConcurrentLinkedQueue<InputEvent>();
|
||||
private final static int MAX_TOUCH_EVENTS = 1024;
|
||||
private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS);
|
||||
private float scaleX = 1f;
|
||||
private float scaleY = 1f;
|
||||
|
||||
|
||||
public AndroidInputHandler() {
|
||||
int buildVersion = Build.VERSION.SDK_INT;
|
||||
logger.log(Level.INFO, "Android Build Version: {0}", buildVersion);
|
||||
if (buildVersion >= 14) {
|
||||
// add support for onHover and GenericMotionEvent (ie. gamepads)
|
||||
gestureHandler = new AndroidGestureHandler(this);
|
||||
touchHandler = new AndroidTouchHandler14(this, gestureHandler);
|
||||
keyHandler = new AndroidKeyHandler(this);
|
||||
} else if (buildVersion >= 8){
|
||||
gestureHandler = new AndroidGestureHandler(this);
|
||||
touchHandler = new AndroidTouchHandler(this, gestureHandler);
|
||||
keyHandler = new AndroidKeyHandler(this);
|
||||
}
|
||||
}
|
||||
|
||||
public AndroidInputHandler(AndroidTouchHandler touchInput,
|
||||
AndroidKeyHandler keyInput, AndroidGestureHandler gestureHandler) {
|
||||
this.touchHandler = touchInput;
|
||||
this.keyHandler = keyInput;
|
||||
this.gestureHandler = gestureHandler;
|
||||
}
|
||||
|
||||
public void setView(View view) {
|
||||
if (touchHandler != null) {
|
||||
touchHandler.setView(view);
|
||||
}
|
||||
if (keyHandler != null) {
|
||||
keyHandler.setView(view);
|
||||
}
|
||||
if (gestureHandler != null) {
|
||||
gestureHandler.setView(view);
|
||||
}
|
||||
this.view = (GLSurfaceView)view;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
public float invertX(float origX) {
|
||||
return getJmeX(view.getWidth()) - origX;
|
||||
}
|
||||
|
||||
public float invertY(float origY) {
|
||||
return getJmeY(view.getHeight()) - origY;
|
||||
}
|
||||
|
||||
public float getJmeX(float origX) {
|
||||
return origX * scaleX;
|
||||
}
|
||||
|
||||
public float getJmeY(float origY) {
|
||||
return origY * scaleY;
|
||||
}
|
||||
|
||||
public void loadSettings(AppSettings settings) {
|
||||
keyboardEventsEnabled = settings.isEmulateKeyboard();
|
||||
mouseEventsEnabled = settings.isEmulateMouse();
|
||||
mouseEventsInvertX = settings.isEmulateMouseFlipX();
|
||||
mouseEventsInvertY = settings.isEmulateMouseFlipY();
|
||||
|
||||
// view width and height are 0 until the view is displayed on the screen
|
||||
if (view.getWidth() != 0 && view.getHeight() != 0) {
|
||||
scaleX = (float)settings.getWidth() / (float)view.getWidth();
|
||||
scaleY = (float)settings.getHeight() / (float)view.getHeight();
|
||||
}
|
||||
logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}",
|
||||
new Object[]{scaleX, scaleY});
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
// JME3 Input interface
|
||||
@Override
|
||||
public void initialize() {
|
||||
touchEventPool.initialize();
|
||||
if (touchHandler != null) {
|
||||
touchHandler.initialize();
|
||||
}
|
||||
if (keyHandler != null) {
|
||||
keyHandler.initialize();
|
||||
}
|
||||
if (gestureHandler != null) {
|
||||
gestureHandler.initialize();
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
initialized = false;
|
||||
|
||||
touchEventPool.destroy();
|
||||
if (touchHandler != null) {
|
||||
touchHandler.destroy();
|
||||
}
|
||||
if (keyHandler != null) {
|
||||
keyHandler.destroy();
|
||||
}
|
||||
if (gestureHandler != null) {
|
||||
gestureHandler.destroy();
|
||||
}
|
||||
|
||||
setView(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputListener(RawInputListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getInputTimeNanos() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (listener != null) {
|
||||
InputEvent inputEvent;
|
||||
|
||||
while ((inputEvent = inputEventQueue.poll()) != null) {
|
||||
if (inputEvent instanceof TouchEvent) {
|
||||
listener.onTouchEvent((TouchEvent)inputEvent);
|
||||
} else if (inputEvent instanceof MouseButtonEvent) {
|
||||
listener.onMouseButtonEvent((MouseButtonEvent)inputEvent);
|
||||
} else if (inputEvent instanceof MouseMotionEvent) {
|
||||
listener.onMouseMotionEvent((MouseMotionEvent)inputEvent);
|
||||
} else if (inputEvent instanceof KeyInputEvent) {
|
||||
listener.onKeyEvent((KeyInputEvent)inputEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
public TouchEvent getFreeTouchEvent() {
|
||||
return touchEventPool.getNextFreeEvent();
|
||||
}
|
||||
|
||||
public void addEvent(InputEvent event) {
|
||||
inputEventQueue.add(event);
|
||||
if (event instanceof TouchEvent) {
|
||||
touchEventPool.storeEvent((TouchEvent)event);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSimulateMouse(boolean simulate) {
|
||||
this.mouseEventsEnabled = simulate;
|
||||
}
|
||||
|
||||
public boolean isSimulateMouse() {
|
||||
return mouseEventsEnabled;
|
||||
}
|
||||
|
||||
public boolean isMouseEventsInvertX() {
|
||||
return mouseEventsInvertX;
|
||||
}
|
||||
|
||||
public boolean isMouseEventsInvertY() {
|
||||
return mouseEventsInvertY;
|
||||
}
|
||||
|
||||
public void setSimulateKeyboard(boolean simulate) {
|
||||
this.keyboardEventsEnabled = simulate;
|
||||
}
|
||||
|
||||
public boolean isSimulateKeyboard() {
|
||||
return keyboardEventsEnabled;
|
||||
}
|
||||
|
||||
public void setOmitHistoricEvents(boolean dontSendHistory) {
|
||||
this.dontSendHistory = dontSendHistory;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2015 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.input.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Build;
|
||||
import android.os.Vibrator;
|
||||
import android.view.View;
|
||||
import com.jme3.input.InputManager;
|
||||
import com.jme3.input.JoyInput;
|
||||
import com.jme3.input.Joystick;
|
||||
import com.jme3.input.RawInputListener;
|
||||
import com.jme3.input.event.InputEvent;
|
||||
import com.jme3.input.event.JoyAxisEvent;
|
||||
import com.jme3.input.event.JoyButtonEvent;
|
||||
import com.jme3.system.AppSettings;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Main class that manages various joystick devices. Joysticks can be many forms
|
||||
* including a simulated joystick to communicate the device orientation as well
|
||||
* as physical gamepads. </br>
|
||||
* This class manages all the joysticks and feeds the inputs from each back
|
||||
* to jME's InputManager.
|
||||
*
|
||||
* This handler also supports the joystick.rumble(rumbleAmount) method. In this
|
||||
* case, when joystick.rumble(rumbleAmount) is called, the Android device will vibrate
|
||||
* if the device has a built in vibrate motor.
|
||||
*
|
||||
* Because Andorid does not allow for the user to define the intensity of the
|
||||
* vibration, the rumble amount (ie strength) is converted into vibration pulses
|
||||
* The stronger the strength amount, the shorter the delay between pulses. If
|
||||
* amount is 1, then the vibration stays on the whole time. If amount is 0.5,
|
||||
* the vibration will a pulse of equal parts vibration and delay.
|
||||
* To turn off vibration, set rumble amount to 0.
|
||||
*
|
||||
* MainActivity needs the following line to enable Joysticks on Android platforms
|
||||
* joystickEventsEnabled = true;
|
||||
* This is done to allow for battery conservation when sensor data or gamepads
|
||||
* are not required by the application.
|
||||
*
|
||||
* To use the joystick rumble feature, the following line needs to be
|
||||
* added to the Android Manifest File
|
||||
* <uses-permission android:name="android.permission.VIBRATE"/>
|
||||
*
|
||||
* @author iwgeric
|
||||
*/
|
||||
public class AndroidJoyInputHandler implements JoyInput {
|
||||
private static final Logger logger = Logger.getLogger(AndroidJoyInputHandler.class.getName());
|
||||
|
||||
private List<Joystick> joystickList = new ArrayList<Joystick>();
|
||||
// private boolean dontSendHistory = false;
|
||||
|
||||
|
||||
// Internal
|
||||
private GLSurfaceView view;
|
||||
private boolean initialized = false;
|
||||
private RawInputListener listener = null;
|
||||
private ConcurrentLinkedQueue<InputEvent> eventQueue = new ConcurrentLinkedQueue<InputEvent>();
|
||||
private AndroidSensorJoyInput sensorJoyInput;
|
||||
private Vibrator vibrator = null;
|
||||
private boolean vibratorActive = false;
|
||||
private long maxRumbleTime = 250; // 250ms
|
||||
|
||||
public AndroidJoyInputHandler() {
|
||||
int buildVersion = Build.VERSION.SDK_INT;
|
||||
logger.log(Level.INFO, "Android Build Version: {0}", buildVersion);
|
||||
// if (buildVersion >= 14) {
|
||||
// touchHandler = new AndroidTouchHandler14(this);
|
||||
// } else if (buildVersion >= 8){
|
||||
// touchHandler = new AndroidTouchHandler(this);
|
||||
// }
|
||||
sensorJoyInput = new AndroidSensorJoyInput(this);
|
||||
}
|
||||
|
||||
public void setView(GLSurfaceView view) {
|
||||
// if (touchHandler != null) {
|
||||
// touchHandler.setView(view);
|
||||
// }
|
||||
if (sensorJoyInput != null) {
|
||||
sensorJoyInput.setView(view);
|
||||
}
|
||||
this.view = (GLSurfaceView)view;
|
||||
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
public void loadSettings(AppSettings settings) {
|
||||
// sensorEventsEnabled = settings.useSensors();
|
||||
}
|
||||
|
||||
public void addEvent(InputEvent event) {
|
||||
eventQueue.add(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the joystick device listeners to save battery life if they are not needed.
|
||||
* Used to pause when the activity pauses
|
||||
*/
|
||||
public void pauseJoysticks() {
|
||||
if (sensorJoyInput != null) {
|
||||
sensorJoyInput.pauseSensors();
|
||||
}
|
||||
if (vibrator != null && vibratorActive) {
|
||||
vibrator.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the joystick device listeners.
|
||||
* Used to resume when the activity comes to the top of the stack
|
||||
*/
|
||||
public void resumeJoysticks() {
|
||||
if (sensorJoyInput != null) {
|
||||
sensorJoyInput.resumeSensors();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
// if (sensorJoyInput != null) {
|
||||
// sensorJoyInput.initialize();
|
||||
// }
|
||||
// Get instance of Vibrator from current Context
|
||||
vibrator = (Vibrator) view.getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (vibrator == null) {
|
||||
logger.log(Level.FINE, "Vibrator Service not found.");
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
initialized = false;
|
||||
|
||||
if (sensorJoyInput != null) {
|
||||
sensorJoyInput.destroy();
|
||||
}
|
||||
|
||||
setView(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputListener(RawInputListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getInputTimeNanos() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJoyRumble(int joyId, float amount) {
|
||||
// convert amount to pulses since Android doesn't allow intensity
|
||||
if (vibrator != null) {
|
||||
final long rumbleOnDur = (long)(amount * maxRumbleTime); // ms to pulse vibration on
|
||||
final long rumbleOffDur = maxRumbleTime - rumbleOnDur; // ms to delay between pulses
|
||||
final long[] rumblePattern = {
|
||||
0, // start immediately
|
||||
rumbleOnDur, // time to leave vibration on
|
||||
rumbleOffDur // time to delay between vibrations
|
||||
};
|
||||
final int rumbleRepeatFrom = 0; // index into rumble pattern to repeat from
|
||||
|
||||
logger.log(Level.FINE, "Rumble amount: {0}, rumbleOnDur: {1}, rumbleOffDur: {2}",
|
||||
new Object[]{amount, rumbleOnDur, rumbleOffDur});
|
||||
|
||||
if (rumbleOnDur > 0) {
|
||||
vibrator.vibrate(rumblePattern, rumbleRepeatFrom);
|
||||
vibratorActive = true;
|
||||
} else {
|
||||
vibrator.cancel();
|
||||
vibratorActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joystick[] loadJoysticks(InputManager inputManager) {
|
||||
joystickList.add(sensorJoyInput.loadJoystick(joystickList.size(), inputManager));
|
||||
|
||||
|
||||
return joystickList.toArray( new Joystick[joystickList.size()] );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if (sensorJoyInput != null) {
|
||||
sensorJoyInput.update();
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
InputEvent inputEvent;
|
||||
|
||||
while ((inputEvent = eventQueue.poll()) != null) {
|
||||
if (inputEvent instanceof JoyAxisEvent) {
|
||||
listener.onJoyAxisEvent((JoyAxisEvent)inputEvent);
|
||||
} else if (inputEvent instanceof JoyButtonEvent) {
|
||||
listener.onJoyButtonEvent((JoyButtonEvent)inputEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -37,7 +37,7 @@ import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Vibrator;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
import com.jme3.input.AbstractJoystick;
|
||||
@ -47,10 +47,8 @@ import com.jme3.input.JoyInput;
|
||||
import com.jme3.input.Joystick;
|
||||
import com.jme3.input.JoystickAxis;
|
||||
import com.jme3.input.SensorJoystickAxis;
|
||||
import com.jme3.input.RawInputListener;
|
||||
import com.jme3.input.event.JoyAxisEvent;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.system.android.JmeAndroidSystem;
|
||||
import com.jme3.util.IntMap;
|
||||
import com.jme3.util.IntMap.Entry;
|
||||
import java.util.ArrayList;
|
||||
@ -63,7 +61,7 @@ import java.util.logging.Logger;
|
||||
* A single joystick is configured and includes data for all configured sensors
|
||||
* as seperate axes of the joystick.
|
||||
*
|
||||
* Each axis is named accounting to the static strings in SensorJoystickAxis.
|
||||
* Each axis is named according to the static strings in SensorJoystickAxis.
|
||||
* Refer to the strings defined in SensorJoystickAxis for a list of supported
|
||||
* sensors and their axis data. Each sensor type defined in SensorJoystickAxis
|
||||
* will be attempted to be configured. If the device does not support a particular
|
||||
@ -72,46 +70,21 @@ import java.util.logging.Logger;
|
||||
* The joystick.getXAxis and getYAxis methods of the joystick are configured to
|
||||
* return the device orientation values in the device's X and Y directions.
|
||||
*
|
||||
* This joystick also supports the joystick.rumble(rumbleAmount) method. In this
|
||||
* case, when joystick.rumble(rumbleAmount) is called, the Android device will vibrate
|
||||
* if the device has a built in vibrate motor.
|
||||
*
|
||||
* Because Andorid does not allow for the user to define the intensity of the
|
||||
* vibration, the rumble amount (ie strength) is converted into vibration pulses
|
||||
* The stronger the strength amount, the shorter the delay between pulses. If
|
||||
* amount is 1, then the vibration stays on the whole time. If amount is 0.5,
|
||||
* the vibration will a pulse of equal parts vibration and delay.
|
||||
* To turn off vibration, set rumble amount to 0.
|
||||
*
|
||||
* MainActivity needs the following line to enable Joysticks on Android platforms
|
||||
* joystickEventsEnabled = true;
|
||||
* This is done to allow for battery conservation when sensor data is not required
|
||||
* by the application.
|
||||
*
|
||||
* To use the joystick rumble feature, the following line needs to be
|
||||
* added to the Android Manifest File
|
||||
* <uses-permission android:name="android.permission.VIBRATE"/>
|
||||
*
|
||||
* @author iwgeric
|
||||
*/
|
||||
public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
public class AndroidSensorJoyInput implements SensorEventListener {
|
||||
private final static Logger logger = Logger.getLogger(AndroidSensorJoyInput.class.getName());
|
||||
|
||||
private Context context = null;
|
||||
private InputManager inputManager = null;
|
||||
private AndroidJoyInputHandler joyHandler;
|
||||
private SensorManager sensorManager = null;
|
||||
private WindowManager windowManager = null;
|
||||
private Vibrator vibrator = null;
|
||||
private boolean vibratorActive = false;
|
||||
private long maxRumbleTime = 250; // 250ms
|
||||
private RawInputListener listener = null;
|
||||
private IntMap<SensorData> sensors = new IntMap<SensorData>();
|
||||
private AndroidJoystick[] joysticks;
|
||||
private int lastRotation = 0;
|
||||
private boolean initialized = false;
|
||||
private boolean loaded = false;
|
||||
|
||||
private final ArrayList<JoyAxisEvent> eventQueue = new ArrayList<JoyAxisEvent>();
|
||||
public AndroidSensorJoyInput(AndroidJoyInputHandler joyHandler) {
|
||||
this.joyHandler = joyHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class to enclose data for each sensor.
|
||||
@ -120,7 +93,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
int androidSensorType = -1;
|
||||
int androidSensorSpeed = SensorManager.SENSOR_DELAY_GAME;
|
||||
Sensor sensor = null;
|
||||
int sensorAccuracy = 0;
|
||||
int sensorAccuracy = -1;
|
||||
float[] lastValues;
|
||||
final Object valuesLock = new Object();
|
||||
ArrayList<AndroidJoystickAxis> axes = new ArrayList<AndroidJoystickAxis>();
|
||||
@ -134,16 +107,19 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
|
||||
}
|
||||
|
||||
private void initSensorManager() {
|
||||
this.context = JmeAndroidSystem.getView().getContext();
|
||||
// Get instance of the WindowManager from the current Context
|
||||
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
// Get instance of the SensorManager from the current Context
|
||||
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
// Get instance of Vibrator from current Context
|
||||
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (vibrator == null) {
|
||||
logger.log(Level.FINE, "Vibrator Service not found.");
|
||||
public void setView(GLSurfaceView view) {
|
||||
pauseSensors();
|
||||
if (sensorManager != null) {
|
||||
sensorManager.unregisterListener(this);
|
||||
}
|
||||
if (view == null) {
|
||||
windowManager = null;
|
||||
sensorManager = null;
|
||||
} else {
|
||||
// Get instance of the WindowManager from the current Context
|
||||
windowManager = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
|
||||
// Get instance of the SensorManager from the current Context
|
||||
sensorManager = (SensorManager) view.getContext().getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,9 +198,6 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
unRegisterListener(entry.getKey());
|
||||
}
|
||||
}
|
||||
if (vibrator != null && vibratorActive) {
|
||||
vibrator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -400,10 +373,8 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
if (!sensorData.haveData) {
|
||||
sensorData.haveData = true;
|
||||
} else {
|
||||
synchronized (eventQueue){
|
||||
if (axis.isChanged()) {
|
||||
eventQueue.add(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
|
||||
}
|
||||
if (axis.isChanged()) {
|
||||
joyHandler.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -428,47 +399,14 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
|
||||
// Start of JoyInput methods
|
||||
|
||||
public void setJoyRumble(int joyId, float amount) {
|
||||
// convert amount to pulses since Android doesn't allow intensity
|
||||
if (vibrator != null) {
|
||||
final long rumbleOnDur = (long)(amount * maxRumbleTime); // ms to pulse vibration on
|
||||
final long rumbleOffDur = maxRumbleTime - rumbleOnDur; // ms to delay between pulses
|
||||
final long[] rumblePattern = {
|
||||
0, // start immediately
|
||||
rumbleOnDur, // time to leave vibration on
|
||||
rumbleOffDur // time to delay between vibrations
|
||||
};
|
||||
final int rumbleRepeatFrom = 0; // index into rumble pattern to repeat from
|
||||
|
||||
logger.log(Level.FINE, "Rumble amount: {0}, rumbleOnDur: {1}, rumbleOffDur: {2}",
|
||||
new Object[]{amount, rumbleOnDur, rumbleOffDur});
|
||||
|
||||
if (rumbleOnDur > 0) {
|
||||
vibrator.vibrate(rumblePattern, rumbleRepeatFrom);
|
||||
vibratorActive = true;
|
||||
} else {
|
||||
vibrator.cancel();
|
||||
vibratorActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Joystick[] loadJoysticks(InputManager inputManager) {
|
||||
this.inputManager = inputManager;
|
||||
|
||||
initSensorManager();
|
||||
|
||||
public Joystick loadJoystick(int joyId, InputManager inputManager) {
|
||||
SensorData sensorData;
|
||||
List<Joystick> list = new ArrayList<Joystick>();
|
||||
AndroidJoystick joystick;
|
||||
AndroidJoystickAxis axis;
|
||||
|
||||
joystick = new AndroidJoystick(inputManager,
|
||||
this,
|
||||
list.size(),
|
||||
AndroidJoystick joystick = new AndroidJoystick(inputManager,
|
||||
joyHandler,
|
||||
joyId,
|
||||
"AndroidSensorsJoystick");
|
||||
list.add(joystick);
|
||||
|
||||
List<Sensor> availSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
|
||||
for (Sensor sensor: availSensors) {
|
||||
@ -555,14 +493,8 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
// }
|
||||
|
||||
|
||||
joysticks = list.toArray( new AndroidJoystick[list.size()] );
|
||||
loaded = true;
|
||||
return joysticks;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
initialized = true;
|
||||
loaded = false;
|
||||
return joystick;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
@ -570,15 +502,6 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
return;
|
||||
}
|
||||
updateOrientation();
|
||||
synchronized (eventQueue){
|
||||
// flush events to listener
|
||||
if (listener != null && eventQueue.size() > 0) {
|
||||
for (int i = 0; i < eventQueue.size(); i++){
|
||||
listener.onJoyAxisEvent(eventQueue.get(i));
|
||||
}
|
||||
eventQueue.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
@ -588,39 +511,27 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
sensorManager.unregisterListener(this);
|
||||
}
|
||||
sensors.clear();
|
||||
eventQueue.clear();
|
||||
initialized = false;
|
||||
loaded = false;
|
||||
joysticks = null;
|
||||
sensorManager = null;
|
||||
vibrator = null;
|
||||
context = null;
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
public void setInputListener(RawInputListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public long getInputTimeNanos() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
// End of JoyInput methods
|
||||
|
||||
// Start of Android SensorEventListener methods
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent se) {
|
||||
if (!initialized || !loaded) {
|
||||
if (!loaded) {
|
||||
return;
|
||||
}
|
||||
logger.log(Level.FINE, "onSensorChanged for {0}: accuracy: {1}, values: {2}",
|
||||
new Object[]{se.sensor.getName(), se.accuracy, se.values});
|
||||
|
||||
int sensorType = se.sensor.getType();
|
||||
|
||||
SensorData sensorData = sensors.get(sensorType);
|
||||
if (sensorData != null) {
|
||||
logger.log(Level.FINE, "sensorData name: {0}, enabled: {1}, unreliable: {2}",
|
||||
new Object[]{sensorData.sensor.getName(), sensorData.enabled, sensorData.sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE});
|
||||
}
|
||||
if (sensorData != null && sensorData.sensor.equals(se.sensor) && sensorData.enabled) {
|
||||
|
||||
if (sensorData.sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
|
||||
@ -641,10 +552,11 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
if (!sensorData.haveData) {
|
||||
sensorData.haveData = true;
|
||||
} else {
|
||||
synchronized (eventQueue){
|
||||
if (axis.isChanged()) {
|
||||
eventQueue.add(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
|
||||
}
|
||||
if (axis.isChanged()) {
|
||||
JoyAxisEvent event = new JoyAxisEvent(axis, axis.getJoystickAxisValue());
|
||||
logger.log(Level.INFO, "adding JoyAxisEvent: {0}", event);
|
||||
joyHandler.addEvent(event);
|
||||
// joyHandler.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -658,6 +570,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int i) {
|
||||
int sensorType = sensor.getType();
|
||||
SensorData sensorData = sensors.get(sensorType);
|
||||
@ -697,7 +610,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
AndroidJoystickAxis axis;
|
||||
|
||||
axis = new AndroidJoystickAxis(
|
||||
inputManager, // InputManager (InputManager)
|
||||
getInputManager(), // InputManager (InputManager)
|
||||
this, // parent Joystick (Joystick)
|
||||
axisNum, // Axis Index (int)
|
||||
axisName, // Axis Name (String)
|
||||
@ -758,10 +671,12 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
this.maxRawValue = maxRawValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxRawValue() {
|
||||
return maxRawValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRawValue(float maxRawValue) {
|
||||
this.maxRawValue = maxRawValue;
|
||||
}
|
||||
@ -787,6 +702,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calibrateCenter() {
|
||||
zeroRawValue = lastRawValue;
|
||||
logger.log(Level.FINE, "Calibrating axis {0} to {1}",
|
||||
|
@ -1850,21 +1850,6 @@ public class OGLESShaderRenderer implements Renderer {
|
||||
TextureUtil.uploadSubTexture(pixels, convertTextureType(tex.getType()), 0, x, y);
|
||||
}
|
||||
|
||||
public void clearTextureUnits() {
|
||||
IDList textureList = context.textureIndexList;
|
||||
Image[] textures = context.boundTextures;
|
||||
for (int i = 0; i < textureList.oldLen; i++) {
|
||||
int idx = textureList.oldList[i];
|
||||
// if (context.boundTextureUnit != idx){
|
||||
// glActiveTexture(GL_TEXTURE0 + idx);
|
||||
// context.boundTextureUnit = idx;
|
||||
// }
|
||||
// glDisable(convertTextureType(textures[idx].getType()));
|
||||
textures[idx] = null;
|
||||
}
|
||||
context.textureIndexList.copyNewToOld();
|
||||
}
|
||||
|
||||
public void deleteImage(Image image) {
|
||||
int texId = image.getId();
|
||||
if (texId != -1) {
|
||||
@ -2339,7 +2324,6 @@ public class OGLESShaderRenderer implements Renderer {
|
||||
RendererUtil.checkGLError();
|
||||
}
|
||||
clearVertexAttribs();
|
||||
clearTextureUnits();
|
||||
}
|
||||
|
||||
private void renderMeshDefault(Mesh mesh, int lod, int count) {
|
||||
@ -2378,7 +2362,6 @@ public class OGLESShaderRenderer implements Renderer {
|
||||
RendererUtil.checkGLError();
|
||||
}
|
||||
clearVertexAttribs();
|
||||
clearTextureUnits();
|
||||
}
|
||||
|
||||
public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) {
|
||||
|
@ -46,17 +46,15 @@ import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import com.jme3.input.*;
|
||||
import com.jme3.input.android.AndroidSensorJoyInput;
|
||||
import com.jme3.input.android.AndroidInputHandler;
|
||||
import com.jme3.input.android.AndroidJoyInputHandler;
|
||||
import com.jme3.input.controls.SoftTextDialogInputListener;
|
||||
import com.jme3.input.dummy.DummyKeyInput;
|
||||
import com.jme3.input.dummy.DummyMouseInput;
|
||||
import com.jme3.renderer.android.AndroidGL;
|
||||
import com.jme3.renderer.opengl.GL;
|
||||
import com.jme3.renderer.opengl.GLDebugES;
|
||||
import com.jme3.renderer.opengl.GLExt;
|
||||
import com.jme3.renderer.opengl.GLRenderer;
|
||||
import com.jme3.renderer.opengl.GLTracer;
|
||||
import com.jme3.system.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
@ -77,9 +75,9 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
|
||||
protected SystemListener listener;
|
||||
protected boolean autoFlush = true;
|
||||
protected AndroidInputHandler androidInput;
|
||||
protected AndroidJoyInputHandler androidJoyInput = null;
|
||||
protected long minFrameDuration = 0; // No FPS cap
|
||||
protected long lastUpdateTime = 0;
|
||||
protected JoyInput androidSensorJoyInput = null;
|
||||
|
||||
public OGLESContext() {
|
||||
}
|
||||
@ -119,6 +117,12 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
|
||||
androidInput.setView(view);
|
||||
androidInput.loadSettings(settings);
|
||||
|
||||
if (androidJoyInput == null) {
|
||||
androidJoyInput = new AndroidJoyInputHandler();
|
||||
}
|
||||
androidJoyInput.setView(view);
|
||||
androidJoyInput.loadSettings(settings);
|
||||
|
||||
// setEGLContextClientVersion must be set before calling setRenderer
|
||||
// this means it cannot be set in AndroidConfigChooser (too late)
|
||||
view.setEGLContextClientVersion(2);
|
||||
@ -231,6 +235,9 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
|
||||
if (androidInput != null) {
|
||||
androidInput.loadSettings(settings);
|
||||
}
|
||||
if (androidJoyInput != null) {
|
||||
androidJoyInput.loadSettings(settings);
|
||||
}
|
||||
|
||||
if (settings.getFrameRate() > 0) {
|
||||
minFrameDuration = (long)(1000d / (double)settings.getFrameRate()); // ms
|
||||
@ -267,10 +274,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
|
||||
|
||||
@Override
|
||||
public JoyInput getJoyInput() {
|
||||
if (androidSensorJoyInput == null) {
|
||||
androidSensorJoyInput = new AndroidSensorJoyInput();
|
||||
}
|
||||
return androidSensorJoyInput;
|
||||
return androidJoyInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -7,21 +7,19 @@ import com.jme3.app.AndroidHarness;
|
||||
public class DemoAndroidHarness extends AndroidHarness
|
||||
{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
// Set the application class to run
|
||||
// First Extract the bundle from intent
|
||||
Bundle bundle = getIntent().getExtras();
|
||||
|
||||
//Next extract the values using the key as
|
||||
appClass = bundle.getString("APPCLASSNAME");
|
||||
|
||||
appClass = bundle.getString("APPCLASSNAME");
|
||||
|
||||
exitDialogTitle = "Close Demo?";
|
||||
exitDialogMessage = "Press Yes";
|
||||
|
||||
screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,36 +32,19 @@
|
||||
package com.jme3.asset;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
import com.jme3.animation.Animation;
|
||||
import com.jme3.bounding.BoundingVolume;
|
||||
import com.jme3.collision.Collidable;
|
||||
import com.jme3.collision.CollisionResults;
|
||||
import com.jme3.collision.UnsupportedCollisionException;
|
||||
import com.jme3.export.InputCapsule;
|
||||
import com.jme3.export.JmeExporter;
|
||||
import com.jme3.export.JmeImporter;
|
||||
import com.jme3.export.OutputCapsule;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.material.RenderState.FaceCullMode;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.post.Filter;
|
||||
import com.jme3.scene.CameraNode;
|
||||
import com.jme3.scene.LightNode;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.SceneGraphVisitor;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.texture.Texture;
|
||||
|
||||
/**
|
||||
* Blender key. Contains path of the blender file and its loading properties.
|
||||
* @author Marcin Roguski (Kaelthas)
|
||||
*/
|
||||
public class BlenderKey extends ModelKey {
|
||||
|
||||
protected static final int DEFAULT_FPS = 25;
|
||||
/**
|
||||
* FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time
|
||||
@ -72,7 +55,7 @@ public class BlenderKey extends ModelKey {
|
||||
* This variable is a bitwise flag of FeatureToLoad interface values; By default everything is being loaded.
|
||||
*/
|
||||
protected int featuresToLoad = FeaturesToLoad.ALL;
|
||||
/** This variable determines if assets that are not linked to the objects should be loaded. */
|
||||
/** The variable that tells if content of the file (along with data unlinked to any feature on the scene) should be stored as 'user data' in the result spatial. */
|
||||
protected boolean loadUnlinkedAssets;
|
||||
/** The root path for all the assets. */
|
||||
protected String assetRootPath;
|
||||
@ -268,6 +251,7 @@ public class BlenderKey extends ModelKey {
|
||||
* @param featuresToLoad
|
||||
* bitwise flag of FeaturesToLoad interface values
|
||||
*/
|
||||
@Deprecated
|
||||
public void includeInLoading(int featuresToLoad) {
|
||||
this.featuresToLoad |= featuresToLoad;
|
||||
}
|
||||
@ -277,10 +261,12 @@ public class BlenderKey extends ModelKey {
|
||||
* @param featuresNotToLoad
|
||||
* bitwise flag of FeaturesToLoad interface values
|
||||
*/
|
||||
@Deprecated
|
||||
public void excludeFromLoading(int featuresNotToLoad) {
|
||||
featuresToLoad &= ~featuresNotToLoad;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean shouldLoad(int featureToLoad) {
|
||||
return (featuresToLoad & featureToLoad) != 0;
|
||||
}
|
||||
@ -290,6 +276,7 @@ public class BlenderKey extends ModelKey {
|
||||
* the blender file loader.
|
||||
* @return features that will be loaded by the blender file loader
|
||||
*/
|
||||
@Deprecated
|
||||
public int getFeaturesToLoad() {
|
||||
return featuresToLoad;
|
||||
}
|
||||
@ -317,15 +304,6 @@ public class BlenderKey extends ModelKey {
|
||||
this.loadUnlinkedAssets = loadUnlinkedAssets;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates an object where loading results will be stores. Only those features will be allowed to store
|
||||
* that were specified by features-to-load flag.
|
||||
* @return an object to store loading results
|
||||
*/
|
||||
public LoadingResults prepareLoadingResults() {
|
||||
return new LoadingResults(featuresToLoad);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the fix up axis state. If set to true then Y is up axis. Otherwise the up i Z axis. By default Y
|
||||
* is up axis.
|
||||
@ -699,8 +677,11 @@ public class BlenderKey extends ModelKey {
|
||||
|
||||
/**
|
||||
* This interface describes the features of the scene that are to be loaded.
|
||||
* @deprecated this interface is deprecated and is not used anymore; to ensure the loading models consistency
|
||||
* everything must be loaded because in blender one feature might depend on another
|
||||
* @author Marcin Roguski (Kaelthas)
|
||||
*/
|
||||
@Deprecated
|
||||
public static interface FeaturesToLoad {
|
||||
|
||||
int SCENES = 0x0000FFFF;
|
||||
@ -745,281 +726,4 @@ public class BlenderKey extends ModelKey {
|
||||
*/
|
||||
ALL_NAMES_MATCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class holds the loading results according to the given loading flag.
|
||||
* @author Marcin Roguski (Kaelthas)
|
||||
*/
|
||||
public static class LoadingResults extends Spatial {
|
||||
|
||||
/** Bitwise mask of features that are to be loaded. */
|
||||
private final int featuresToLoad;
|
||||
/** The scenes from the file. */
|
||||
private List<Node> scenes;
|
||||
/** Objects from all scenes. */
|
||||
private List<Node> objects;
|
||||
/** Materials from all objects. */
|
||||
private List<Material> materials;
|
||||
/** Textures from all objects. */
|
||||
private List<Texture> textures;
|
||||
/** Animations of all objects. */
|
||||
private List<Animation> animations;
|
||||
/** All cameras from the file. */
|
||||
private List<CameraNode> cameras;
|
||||
/** All lights from the file. */
|
||||
private List<LightNode> lights;
|
||||
/** Loaded sky. */
|
||||
private Spatial sky;
|
||||
/** Scene filters (ie. FOG). */
|
||||
private List<Filter> filters;
|
||||
/**
|
||||
* The background color of the render loaded from the horizon color of the world. If no world is used than the gray color
|
||||
* is set to default (as in blender editor.
|
||||
*/
|
||||
private ColorRGBA backgroundColor = ColorRGBA.Gray;
|
||||
|
||||
/**
|
||||
* Private constructor prevents users to create an instance of this class from outside the
|
||||
* @param featuresToLoad
|
||||
* bitwise mask of features that are to be loaded
|
||||
* @see FeaturesToLoad FeaturesToLoad
|
||||
*/
|
||||
private LoadingResults(int featuresToLoad) {
|
||||
this.featuresToLoad = featuresToLoad;
|
||||
if ((featuresToLoad & FeaturesToLoad.SCENES) != 0) {
|
||||
scenes = new ArrayList<Node>();
|
||||
}
|
||||
if ((featuresToLoad & FeaturesToLoad.OBJECTS) != 0) {
|
||||
objects = new ArrayList<Node>();
|
||||
if ((featuresToLoad & FeaturesToLoad.MATERIALS) != 0) {
|
||||
materials = new ArrayList<Material>();
|
||||
if ((featuresToLoad & FeaturesToLoad.TEXTURES) != 0) {
|
||||
textures = new ArrayList<Texture>();
|
||||
}
|
||||
}
|
||||
if ((featuresToLoad & FeaturesToLoad.ANIMATIONS) != 0) {
|
||||
animations = new ArrayList<Animation>();
|
||||
}
|
||||
}
|
||||
if ((featuresToLoad & FeaturesToLoad.CAMERAS) != 0) {
|
||||
cameras = new ArrayList<CameraNode>();
|
||||
}
|
||||
if ((featuresToLoad & FeaturesToLoad.LIGHTS) != 0) {
|
||||
lights = new ArrayList<LightNode>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a bitwise flag describing what features of the blend file will be included in the result.
|
||||
* @return bitwise mask of features that are to be loaded
|
||||
* @see FeaturesToLoad FeaturesToLoad
|
||||
*/
|
||||
public int getLoadedFeatures() {
|
||||
return featuresToLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds a scene to the result set.
|
||||
* @param scene
|
||||
* scene to be added to the result set
|
||||
*/
|
||||
public void addScene(Node scene) {
|
||||
if (scenes != null) {
|
||||
scenes.add(scene);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds an object to the result set.
|
||||
* @param object
|
||||
* object to be added to the result set
|
||||
*/
|
||||
public void addObject(Node object) {
|
||||
if (objects != null) {
|
||||
objects.add(object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds a material to the result set.
|
||||
* @param material
|
||||
* material to be added to the result set
|
||||
*/
|
||||
public void addMaterial(Material material) {
|
||||
if (materials != null) {
|
||||
materials.add(material);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds a texture to the result set.
|
||||
* @param texture
|
||||
* texture to be added to the result set
|
||||
*/
|
||||
public void addTexture(Texture texture) {
|
||||
if (textures != null) {
|
||||
textures.add(texture);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds a camera to the result set.
|
||||
* @param camera
|
||||
* camera to be added to the result set
|
||||
*/
|
||||
public void addCamera(CameraNode camera) {
|
||||
if (cameras != null) {
|
||||
cameras.add(camera);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds a light to the result set.
|
||||
* @param light
|
||||
* light to be added to the result set
|
||||
*/
|
||||
public void addLight(LightNode light) {
|
||||
if (lights != null) {
|
||||
lights.add(light);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the sky of the scene. Only one sky can be set.
|
||||
* @param sky
|
||||
* the sky to be set
|
||||
*/
|
||||
public void setSky(Spatial sky) {
|
||||
this.sky = sky;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds a scene filter. Filters are used to load FOG or other
|
||||
* scene effects that blender can define.
|
||||
* @param filter
|
||||
* the filter to be added
|
||||
*/
|
||||
public void addFilter(Filter filter) {
|
||||
if (filter != null) {
|
||||
if (filters == null) {
|
||||
filters = new ArrayList<Filter>(5);
|
||||
}
|
||||
filters.add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param backgroundColor
|
||||
* the background color
|
||||
*/
|
||||
public void setBackgroundColor(ColorRGBA backgroundColor) {
|
||||
this.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all loaded scenes
|
||||
*/
|
||||
public List<Node> getScenes() {
|
||||
return scenes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all loaded objects
|
||||
*/
|
||||
public List<Node> getObjects() {
|
||||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all loaded materials
|
||||
*/
|
||||
public List<Material> getMaterials() {
|
||||
return materials;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all loaded textures
|
||||
*/
|
||||
public List<Texture> getTextures() {
|
||||
return textures;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all loaded animations
|
||||
*/
|
||||
public List<Animation> getAnimations() {
|
||||
return animations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all loaded cameras
|
||||
*/
|
||||
public List<CameraNode> getCameras() {
|
||||
return cameras;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all loaded lights
|
||||
*/
|
||||
public List<LightNode> getLights() {
|
||||
return lights;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scene's sky
|
||||
*/
|
||||
public Spatial getSky() {
|
||||
return sky;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return scene filters
|
||||
*/
|
||||
public List<Filter> getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the background color
|
||||
*/
|
||||
public ColorRGBA getBackgroundColor() {
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int collideWith(Collidable other, CollisionResults results) throws UnsupportedCollisionException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateModelBound() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModelBound(BoundingVolume modelBound) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVertexCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTriangleCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spatial deepClone() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void depthFirstTraversal(SceneGraphVisitor visitor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue<Spatial> queue) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,17 +31,34 @@
|
||||
*/
|
||||
package com.jme3.scene.plugins.blender;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.animation.Animation;
|
||||
import com.jme3.asset.AssetNotFoundException;
|
||||
import com.jme3.asset.BlenderKey;
|
||||
import com.jme3.export.Savable;
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.post.Filter;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.plugins.blender.BlenderContext.LoadedDataType;
|
||||
import com.jme3.scene.plugins.blender.file.BlenderFileException;
|
||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||
import com.jme3.scene.plugins.blender.file.Structure;
|
||||
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
||||
import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
|
||||
import com.jme3.scene.plugins.blender.objects.Properties;
|
||||
import com.jme3.texture.Texture;
|
||||
|
||||
/**
|
||||
* A purpose of the helper class is to split calculation code into several classes. Each helper after use should be cleared because it can
|
||||
@ -49,14 +66,16 @@ import com.jme3.scene.plugins.blender.objects.Properties;
|
||||
* @author Marcin Roguski
|
||||
*/
|
||||
public abstract class AbstractBlenderHelper {
|
||||
private static final Logger LOGGER = Logger.getLogger(AbstractBlenderHelper.class.getName());
|
||||
|
||||
/** The blender context. */
|
||||
protected BlenderContext blenderContext;
|
||||
protected BlenderContext blenderContext;
|
||||
/** The version of the blend file. */
|
||||
protected final int blenderVersion;
|
||||
protected final int blenderVersion;
|
||||
/** This variable indicates if the Y asxis is the UP axis or not. */
|
||||
protected boolean fixUpAxis;
|
||||
protected boolean fixUpAxis;
|
||||
/** Quaternion used to rotate data when Y is up axis. */
|
||||
protected Quaternion upAxisRotationQuaternion;
|
||||
protected Quaternion upAxisRotationQuaternion;
|
||||
|
||||
/**
|
||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
|
||||
@ -129,4 +148,115 @@ public abstract class AbstractBlenderHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method loads library of a given ID from linked blender file.
|
||||
* @param id
|
||||
* the ID of the linked feature (it contains its name and blender path)
|
||||
* @return loaded feature or null if none was found
|
||||
* @throws BlenderFileException
|
||||
* and exception is throw when problems with reading a blend file occur
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Object loadLibrary(Structure id) throws BlenderFileException {
|
||||
Pointer pLib = (Pointer) id.getFieldValue("lib");
|
||||
if (pLib.isNotNull()) {
|
||||
String fullName = id.getFieldValue("name").toString();// we need full name with the prefix
|
||||
String nameOfFeatureToLoad = id.getName();
|
||||
Structure library = pLib.fetchData().get(0);
|
||||
String path = library.getFieldValue("filepath").toString();
|
||||
|
||||
if (!blenderContext.getLinkedFeatures().keySet().contains(path)) {
|
||||
File file = new File(path);
|
||||
List<String> pathsToCheck = new ArrayList<String>();
|
||||
String currentPath = file.getName();
|
||||
do {
|
||||
pathsToCheck.add(currentPath);
|
||||
file = file.getParentFile();
|
||||
if (file != null) {
|
||||
currentPath = file.getName() + '/' + currentPath;
|
||||
}
|
||||
} while (file != null);
|
||||
|
||||
Spatial loadedAsset = null;
|
||||
BlenderKey blenderKey = null;
|
||||
for (String p : pathsToCheck) {
|
||||
blenderKey = new BlenderKey(p);
|
||||
blenderKey.setLoadUnlinkedAssets(true);
|
||||
try {
|
||||
loadedAsset = blenderContext.getAssetManager().loadAsset(blenderKey);
|
||||
break;// break if no exception was thrown
|
||||
} catch (AssetNotFoundException e) {
|
||||
LOGGER.log(Level.FINEST, "Cannot locate linked resource at path: {0}.", p);
|
||||
}
|
||||
}
|
||||
|
||||
if (loadedAsset != null) {
|
||||
Map<String, Map<String, Object>> linkedData = loadedAsset.getUserData("linkedData");
|
||||
for (Entry<String, Map<String, Object>> entry : linkedData.entrySet()) {
|
||||
String linkedDataFilePath = "this".equals(entry.getKey()) ? path : entry.getKey();
|
||||
|
||||
List<Node> scenes = (List<Node>) entry.getValue().get("scenes");
|
||||
for (Node scene : scenes) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, "SC" + scene.getName(), scene);
|
||||
}
|
||||
List<Node> objects = (List<Node>) entry.getValue().get("objects");
|
||||
for (Node object : objects) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, "OB" + object.getName(), object);
|
||||
}
|
||||
List<TemporalMesh> meshes = (List<TemporalMesh>) entry.getValue().get("meshes");
|
||||
for (TemporalMesh mesh : meshes) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, "ME" + mesh.getName(), mesh);
|
||||
}
|
||||
List<MaterialContext> materials = (List<MaterialContext>) entry.getValue().get("materials");
|
||||
for (MaterialContext materialContext : materials) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, "MA" + materialContext.getName(), materialContext);
|
||||
}
|
||||
List<Texture> textures = (List<Texture>) entry.getValue().get("textures");
|
||||
for (Texture texture : textures) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, "TE" + texture.getName(), texture);
|
||||
}
|
||||
List<Texture> images = (List<Texture>) entry.getValue().get("images");
|
||||
for (Texture image : images) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, "IM" + image.getName(), image);
|
||||
}
|
||||
List<Animation> animations = (List<Animation>) entry.getValue().get("animations");
|
||||
for (Animation animation : animations) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, "AC" + animation.getName(), animation);
|
||||
}
|
||||
List<Camera> cameras = (List<Camera>) entry.getValue().get("cameras");
|
||||
for (Camera camera : cameras) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, "CA" + camera.getName(), camera);
|
||||
}
|
||||
List<Light> lights = (List<Light>) entry.getValue().get("lights");
|
||||
for (Light light : lights) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, "LA" + light.getName(), light);
|
||||
}
|
||||
Spatial sky = (Spatial) entry.getValue().get("sky");
|
||||
if (sky != null) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, sky.getName(), sky);
|
||||
}
|
||||
List<Filter> filters = (List<Filter>) entry.getValue().get("filters");
|
||||
for (Filter filter : filters) {
|
||||
blenderContext.addLinkedFeature(linkedDataFilePath, filter.getName(), filter);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, "No features loaded from path: {0}.", path);
|
||||
}
|
||||
}
|
||||
|
||||
Object result = blenderContext.getLinkedFeature(path, fullName);
|
||||
if (result == null) {
|
||||
LOGGER.log(Level.WARNING, "Could NOT find asset named {0} in the library of path: {1}.", new Object[] { nameOfFeatureToLoad, path });
|
||||
} else {
|
||||
blenderContext.addLoadedFeatures(id.getOldMemoryAddress(), LoadedDataType.STRUCTURE, id);
|
||||
blenderContext.addLoadedFeatures(id.getOldMemoryAddress(), LoadedDataType.FEATURE, result);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
LOGGER.warning("Library link points to nothing!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ import com.jme3.scene.plugins.blender.constraints.Constraint;
|
||||
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||
import com.jme3.scene.plugins.blender.file.DnaBlockData;
|
||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader.BlockCode;
|
||||
import com.jme3.scene.plugins.blender.file.Structure;
|
||||
|
||||
/**
|
||||
@ -64,49 +65,51 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
||||
*/
|
||||
public class BlenderContext {
|
||||
/** The blender file version. */
|
||||
private int blenderVersion;
|
||||
private int blenderVersion;
|
||||
/** The blender key. */
|
||||
private BlenderKey blenderKey;
|
||||
private BlenderKey blenderKey;
|
||||
/** The header of the file block. */
|
||||
private DnaBlockData dnaBlockData;
|
||||
private DnaBlockData dnaBlockData;
|
||||
/** The scene structure. */
|
||||
private Structure sceneStructure;
|
||||
private Structure sceneStructure;
|
||||
/** The input stream of the blend file. */
|
||||
private BlenderInputStream inputStream;
|
||||
private BlenderInputStream inputStream;
|
||||
/** The asset manager. */
|
||||
private AssetManager assetManager;
|
||||
private AssetManager assetManager;
|
||||
/** The blocks read from the file. */
|
||||
protected List<FileBlockHeader> blocks;
|
||||
protected List<FileBlockHeader> blocks;
|
||||
/**
|
||||
* A map containing the file block headers. The key is the old memory address.
|
||||
*/
|
||||
private Map<Long, FileBlockHeader> fileBlockHeadersByOma = new HashMap<Long, FileBlockHeader>();
|
||||
private Map<Long, FileBlockHeader> fileBlockHeadersByOma = new HashMap<Long, FileBlockHeader>();
|
||||
/** A map containing the file block headers. The key is the block code. */
|
||||
private Map<Integer, List<FileBlockHeader>> fileBlockHeadersByCode = new HashMap<Integer, List<FileBlockHeader>>();
|
||||
private Map<BlockCode, List<FileBlockHeader>> fileBlockHeadersByCode = new HashMap<BlockCode, List<FileBlockHeader>>();
|
||||
/**
|
||||
* This map stores the loaded features by their old memory address. The
|
||||
* first object in the value table is the loaded structure and the second -
|
||||
* the structure already converted into proper data.
|
||||
*/
|
||||
private Map<Long, Map<LoadedDataType, Object>> loadedFeatures = new HashMap<Long, Map<LoadedDataType, Object>>();
|
||||
private Map<Long, Map<LoadedDataType, Object>> loadedFeatures = new HashMap<Long, Map<LoadedDataType, Object>>();
|
||||
/** Features loaded from external blender files. The key is the file path and the value is a map between feature name and loaded feature. */
|
||||
private Map<String, Map<String, Object>> linkedFeatures = new HashMap<String, Map<String, Object>>();
|
||||
/** A stack that hold the parent structure of currently loaded feature. */
|
||||
private Stack<Structure> parentStack = new Stack<Structure>();
|
||||
private Stack<Structure> parentStack = new Stack<Structure>();
|
||||
/** A list of constraints for the specified object. */
|
||||
protected Map<Long, List<Constraint>> constraints = new HashMap<Long, List<Constraint>>();
|
||||
protected Map<Long, List<Constraint>> constraints = new HashMap<Long, List<Constraint>>();
|
||||
/** Animations loaded for features. */
|
||||
private Map<Long, List<Animation>> animations = new HashMap<Long, List<Animation>>();
|
||||
private Map<Long, List<Animation>> animations = new HashMap<Long, List<Animation>>();
|
||||
/** Loaded skeletons. */
|
||||
private Map<Long, Skeleton> skeletons = new HashMap<Long, Skeleton>();
|
||||
private Map<Long, Skeleton> skeletons = new HashMap<Long, Skeleton>();
|
||||
/** A map between skeleton and node it modifies. */
|
||||
private Map<Skeleton, Node> nodesWithSkeletons = new HashMap<Skeleton, Node>();
|
||||
private Map<Skeleton, Node> nodesWithSkeletons = new HashMap<Skeleton, Node>();
|
||||
/** A map of bone contexts. */
|
||||
protected Map<Long, BoneContext> boneContexts = new HashMap<Long, BoneContext>();
|
||||
protected Map<Long, BoneContext> boneContexts = new HashMap<Long, BoneContext>();
|
||||
/** A map og helpers that perform loading. */
|
||||
private Map<String, AbstractBlenderHelper> helpers = new HashMap<String, AbstractBlenderHelper>();
|
||||
private Map<String, AbstractBlenderHelper> helpers = new HashMap<String, AbstractBlenderHelper>();
|
||||
/** Markers used by loading classes to store some custom data. This is made to avoid putting this data into user properties. */
|
||||
private Map<String, Map<Object, Object>> markers = new HashMap<String, Map<Object, Object>>();
|
||||
private Map<String, Map<Object, Object>> markers = new HashMap<String, Map<Object, Object>>();
|
||||
/** A map of blender actions. The key is the action name and the value is the action itself. */
|
||||
private Map<String, BlenderAction> actions = new HashMap<String, BlenderAction>();
|
||||
private Map<String, BlenderAction> actions = new HashMap<String, BlenderAction>();
|
||||
|
||||
/**
|
||||
* This method sets the blender file version.
|
||||
@ -231,10 +234,10 @@ public class BlenderContext {
|
||||
*/
|
||||
public void addFileBlockHeader(Long oldMemoryAddress, FileBlockHeader fileBlockHeader) {
|
||||
fileBlockHeadersByOma.put(oldMemoryAddress, fileBlockHeader);
|
||||
List<FileBlockHeader> headers = fileBlockHeadersByCode.get(Integer.valueOf(fileBlockHeader.getCode()));
|
||||
List<FileBlockHeader> headers = fileBlockHeadersByCode.get(fileBlockHeader.getCode());
|
||||
if (headers == null) {
|
||||
headers = new ArrayList<FileBlockHeader>();
|
||||
fileBlockHeadersByCode.put(Integer.valueOf(fileBlockHeader.getCode()), headers);
|
||||
fileBlockHeadersByCode.put(fileBlockHeader.getCode(), headers);
|
||||
}
|
||||
headers.add(fileBlockHeader);
|
||||
}
|
||||
@ -258,7 +261,7 @@ public class BlenderContext {
|
||||
* the code of file blocks
|
||||
* @return a list of file blocks' headers of a specified code
|
||||
*/
|
||||
public List<FileBlockHeader> getFileBlocks(Integer code) {
|
||||
public List<FileBlockHeader> getFileBlocks(BlockCode code) {
|
||||
return fileBlockHeadersByCode.get(code);
|
||||
}
|
||||
|
||||
@ -299,7 +302,7 @@ public class BlenderContext {
|
||||
throw new IllegalArgumentException("One of the given arguments is null!");
|
||||
}
|
||||
Map<LoadedDataType, Object> map = loadedFeatures.get(oldMemoryAddress);
|
||||
if(map == null) {
|
||||
if (map == null) {
|
||||
map = new HashMap<BlenderContext.LoadedDataType, Object>();
|
||||
loadedFeatures.put(oldMemoryAddress, map);
|
||||
}
|
||||
@ -325,6 +328,48 @@ public class BlenderContext {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The method adds linked content to the blender context.
|
||||
* @param blenderFilePath
|
||||
* the path of linked blender file
|
||||
* @param featureName
|
||||
* the linked feature name
|
||||
* @param feature
|
||||
* the linked feature
|
||||
*/
|
||||
public void addLinkedFeature(String blenderFilePath, String featureName, Object feature) {
|
||||
if (feature != null) {
|
||||
Map<String, Object> linkedFeatures = this.linkedFeatures.get(blenderFilePath);
|
||||
if (linkedFeatures == null) {
|
||||
linkedFeatures = new HashMap<String, Object>();
|
||||
this.linkedFeatures.put(blenderFilePath, linkedFeatures);
|
||||
}
|
||||
if (!linkedFeatures.containsKey(featureName)) {
|
||||
linkedFeatures.put(featureName, feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method returns linked feature of a given name from the specified blender path.
|
||||
* @param blenderFilePath
|
||||
* the blender file path
|
||||
* @param featureName
|
||||
* the feature name we want to get
|
||||
* @return linked feature or null if none was found
|
||||
*/
|
||||
public Object getLinkedFeature(String blenderFilePath, String featureName) {
|
||||
Map<String, Object> linkedFeatures = this.linkedFeatures.get(blenderFilePath);
|
||||
return linkedFeatures != null ? linkedFeatures.get(featureName) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all linked features for the current blend file
|
||||
*/
|
||||
public Map<String, Map<String, Object>> getLinkedFeatures() {
|
||||
return linkedFeatures;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds the structure to the parent stack.
|
||||
*
|
||||
|
@ -33,17 +33,21 @@ package com.jme3.scene.plugins.blender;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.animation.Animation;
|
||||
import com.jme3.asset.AssetInfo;
|
||||
import com.jme3.asset.AssetLoader;
|
||||
import com.jme3.asset.BlenderKey;
|
||||
import com.jme3.asset.BlenderKey.FeaturesToLoad;
|
||||
import com.jme3.asset.BlenderKey.LoadingResults;
|
||||
import com.jme3.asset.ModelKey;
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.post.Filter;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.scene.CameraNode;
|
||||
import com.jme3.scene.LightNode;
|
||||
import com.jme3.scene.Node;
|
||||
@ -55,16 +59,20 @@ import com.jme3.scene.plugins.blender.curves.CurvesHelper;
|
||||
import com.jme3.scene.plugins.blender.file.BlenderFileException;
|
||||
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader.BlockCode;
|
||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||
import com.jme3.scene.plugins.blender.file.Structure;
|
||||
import com.jme3.scene.plugins.blender.landscape.LandscapeHelper;
|
||||
import com.jme3.scene.plugins.blender.lights.LightHelper;
|
||||
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
||||
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||
import com.jme3.scene.plugins.blender.meshes.MeshHelper;
|
||||
import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
|
||||
import com.jme3.scene.plugins.blender.modifiers.ModifierHelper;
|
||||
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||
import com.jme3.scene.plugins.blender.particles.ParticlesHelper;
|
||||
import com.jme3.scene.plugins.blender.textures.TextureHelper;
|
||||
import com.jme3.texture.Texture;
|
||||
|
||||
/**
|
||||
* This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures.
|
||||
@ -83,72 +91,130 @@ public class BlenderLoader implements AssetLoader {
|
||||
try {
|
||||
this.setup(assetInfo);
|
||||
|
||||
List<FileBlockHeader> sceneBlocks = new ArrayList<FileBlockHeader>();
|
||||
BlenderKey blenderKey = blenderContext.getBlenderKey();
|
||||
LoadingResults loadingResults = blenderKey.prepareLoadingResults();
|
||||
|
||||
AnimationHelper animationHelper = blenderContext.getHelper(AnimationHelper.class);
|
||||
animationHelper.loadAnimations();
|
||||
|
||||
|
||||
BlenderKey blenderKey = blenderContext.getBlenderKey();
|
||||
LoadedFeatures loadedFeatures = new LoadedFeatures();
|
||||
for (FileBlockHeader block : blocks) {
|
||||
switch (block.getCode()) {
|
||||
case FileBlockHeader.BLOCK_OB00:// Object
|
||||
case BLOCK_OB00:
|
||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
||||
Object object = objectHelper.toObject(block.getStructure(blenderContext), blenderContext);
|
||||
if (object instanceof LightNode) {
|
||||
loadingResults.addLight((LightNode) object);
|
||||
} else if (object instanceof CameraNode) {
|
||||
loadingResults.addCamera((CameraNode) object);
|
||||
} else if (object instanceof Node) {
|
||||
if (LOGGER.isLoggable(Level.FINE)) {
|
||||
LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() });
|
||||
Node object = (Node) objectHelper.toObject(block.getStructure(blenderContext), blenderContext);
|
||||
if (LOGGER.isLoggable(Level.FINE)) {
|
||||
LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { object.getName(), object.getLocalTranslation().toString(), object.getParent() == null ? "null" : object.getParent().getName() });
|
||||
}
|
||||
if (object.getParent() == null) {
|
||||
loadedFeatures.objects.add(object);
|
||||
}
|
||||
if (object instanceof LightNode && ((LightNode) object).getLight() != null) {
|
||||
loadedFeatures.lights.add(((LightNode) object).getLight());
|
||||
} else if (object instanceof CameraNode && ((CameraNode) object).getCamera() != null) {
|
||||
loadedFeatures.cameras.add(((CameraNode) object).getCamera());
|
||||
}
|
||||
break;
|
||||
case BLOCK_SC00:// Scene
|
||||
loadedFeatures.sceneBlocks.add(block);
|
||||
break;
|
||||
case BLOCK_MA00:// Material
|
||||
MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
|
||||
MaterialContext materialContext = materialHelper.toMaterialContext(block.getStructure(blenderContext), blenderContext);
|
||||
loadedFeatures.materials.add(materialContext);
|
||||
break;
|
||||
case BLOCK_ME00:// Mesh
|
||||
MeshHelper meshHelper = blenderContext.getHelper(MeshHelper.class);
|
||||
TemporalMesh temporalMesh = meshHelper.toTemporalMesh(block.getStructure(blenderContext), blenderContext);
|
||||
loadedFeatures.meshes.add(temporalMesh);
|
||||
break;
|
||||
case BLOCK_IM00:// Image
|
||||
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
|
||||
Texture image = textureHelper.loadImageAsTexture(block.getStructure(blenderContext), 0, blenderContext);
|
||||
if (image != null && image.getImage() != null) {// render results are stored as images but are not being loaded
|
||||
loadedFeatures.images.add(image);
|
||||
}
|
||||
break;
|
||||
case BLOCK_TE00:
|
||||
Structure textureStructure = block.getStructure(blenderContext);
|
||||
int type = ((Number) textureStructure.getFieldValue("type")).intValue();
|
||||
if (type == TextureHelper.TEX_IMAGE) {
|
||||
TextureHelper texHelper = blenderContext.getHelper(TextureHelper.class);
|
||||
Texture texture = texHelper.getTexture(textureStructure, null, blenderContext);
|
||||
if (texture != null) {// null is returned when texture has no image
|
||||
loadedFeatures.textures.add(texture);
|
||||
}
|
||||
if (this.isRootObject(loadingResults, (Node) object)) {
|
||||
loadingResults.addObject((Node) object);
|
||||
} else {
|
||||
LOGGER.fine("Only image textures can be loaded as unlinked assets. Generated textures will be applied to an existing object.");
|
||||
}
|
||||
break;
|
||||
case BLOCK_WO00:// World
|
||||
LandscapeHelper landscapeHelper = blenderContext.getHelper(LandscapeHelper.class);
|
||||
Structure worldStructure = block.getStructure(blenderContext);
|
||||
|
||||
String worldName = worldStructure.getName();
|
||||
if (blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) {
|
||||
|
||||
Light ambientLight = landscapeHelper.toAmbientLight(worldStructure);
|
||||
if (ambientLight != null) {
|
||||
loadedFeatures.objects.add(new LightNode(null, ambientLight));
|
||||
loadedFeatures.lights.add(ambientLight);
|
||||
}
|
||||
loadedFeatures.sky = landscapeHelper.toSky(worldStructure);
|
||||
loadedFeatures.backgroundColor = landscapeHelper.toBackgroundColor(worldStructure);
|
||||
|
||||
Filter fogFilter = landscapeHelper.toFog(worldStructure);
|
||||
if (fogFilter != null) {
|
||||
loadedFeatures.filters.add(landscapeHelper.toFog(worldStructure));
|
||||
}
|
||||
}
|
||||
break;
|
||||
// case FileBlockHeader.BLOCK_MA00:// Material
|
||||
// MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
|
||||
// MaterialContext materialContext = materialHelper.toMaterialContext(block.getStructure(blenderContext), blenderContext);
|
||||
// if (blenderKey.isLoadUnlinkedAssets() && blenderKey.shouldLoad(FeaturesToLoad.MATERIALS)) {
|
||||
// loadingResults.addMaterial(this.toMaterial(block.getStructure(blenderContext)));
|
||||
// }
|
||||
// break;
|
||||
case FileBlockHeader.BLOCK_SC00:// Scene
|
||||
if (blenderKey.shouldLoad(FeaturesToLoad.SCENES)) {
|
||||
sceneBlocks.add(block);
|
||||
}
|
||||
break;
|
||||
case FileBlockHeader.BLOCK_WO00:// World
|
||||
if (blenderKey.shouldLoad(FeaturesToLoad.WORLD)) {
|
||||
Structure worldStructure = block.getStructure(blenderContext);
|
||||
String worldName = worldStructure.getName();
|
||||
if (blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) {
|
||||
LandscapeHelper landscapeHelper = blenderContext.getHelper(LandscapeHelper.class);
|
||||
Light ambientLight = landscapeHelper.toAmbientLight(worldStructure);
|
||||
if(ambientLight != null) {
|
||||
loadingResults.addLight(new LightNode(null, ambientLight));
|
||||
}
|
||||
loadingResults.setSky(landscapeHelper.toSky(worldStructure));
|
||||
loadingResults.addFilter(landscapeHelper.toFog(worldStructure));
|
||||
loadingResults.setBackgroundColor(landscapeHelper.toBackgroundColor(worldStructure));
|
||||
}
|
||||
}
|
||||
case BLOCK_AC00:
|
||||
LOGGER.fine("Loading unlinked animations is not yet supported!");
|
||||
break;
|
||||
default:
|
||||
LOGGER.log(Level.FINEST, "Ommiting the block: {0}.", block.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
// bake constraints after everything is loaded
|
||||
LOGGER.fine("Baking constraints after every feature is loaded.");
|
||||
ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
|
||||
constraintHelper.bakeConstraints(blenderContext);
|
||||
|
||||
// load the scene at the very end so that the root nodes have no parent during loading or constraints applying
|
||||
for (FileBlockHeader sceneBlock : sceneBlocks) {
|
||||
loadingResults.addScene(this.toScene(sceneBlock.getStructure(blenderContext)));
|
||||
LOGGER.fine("Loading scenes and attaching them to the root object.");
|
||||
for (FileBlockHeader sceneBlock : loadedFeatures.sceneBlocks) {
|
||||
loadedFeatures.scenes.add(this.toScene(sceneBlock.getStructure(blenderContext)));
|
||||
}
|
||||
|
||||
return loadingResults;
|
||||
LOGGER.fine("Creating the root node of the model and applying loaded nodes of the scene and loaded features to it.");
|
||||
Node modelRoot = new Node(blenderKey.getName());
|
||||
for (Node scene : loadedFeatures.scenes) {
|
||||
modelRoot.attachChild(scene);
|
||||
}
|
||||
|
||||
if (blenderKey.isLoadUnlinkedAssets()) {
|
||||
LOGGER.fine("Setting loaded content as user data in resulting sptaial.");
|
||||
Map<String, Map<String, Object>> linkedData = new HashMap<String, Map<String, Object>>();
|
||||
|
||||
Map<String, Object> thisFileData = new HashMap<String, Object>();
|
||||
thisFileData.put("scenes", loadedFeatures.scenes == null ? new ArrayList<Object>() : loadedFeatures.scenes);
|
||||
thisFileData.put("objects", loadedFeatures.objects == null ? new ArrayList<Object>() : loadedFeatures.objects);
|
||||
thisFileData.put("meshes", loadedFeatures.meshes == null ? new ArrayList<Object>() : loadedFeatures.meshes);
|
||||
thisFileData.put("materials", loadedFeatures.materials == null ? new ArrayList<Object>() : loadedFeatures.materials);
|
||||
thisFileData.put("textures", loadedFeatures.textures == null ? new ArrayList<Object>() : loadedFeatures.textures);
|
||||
thisFileData.put("images", loadedFeatures.images == null ? new ArrayList<Object>() : loadedFeatures.images);
|
||||
thisFileData.put("animations", loadedFeatures.animations == null ? new ArrayList<Object>() : loadedFeatures.animations);
|
||||
thisFileData.put("cameras", loadedFeatures.cameras == null ? new ArrayList<Object>() : loadedFeatures.cameras);
|
||||
thisFileData.put("lights", loadedFeatures.lights == null ? new ArrayList<Object>() : loadedFeatures.lights);
|
||||
thisFileData.put("filters", loadedFeatures.filters == null ? new ArrayList<Object>() : loadedFeatures.filters);
|
||||
thisFileData.put("backgroundColor", loadedFeatures.backgroundColor);
|
||||
thisFileData.put("sky", loadedFeatures.sky);
|
||||
|
||||
linkedData.put("this", thisFileData);
|
||||
linkedData.putAll(blenderContext.getLinkedFeatures());
|
||||
|
||||
modelRoot.setUserData("linkedData", linkedData);
|
||||
}
|
||||
|
||||
return modelRoot;
|
||||
} catch (BlenderFileException e) {
|
||||
throw new IOException(e.getLocalizedMessage(), e);
|
||||
} catch (Exception e) {
|
||||
@ -158,62 +224,36 @@ public class BlenderLoader implements AssetLoader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates if the given spatial is a root object. It means it
|
||||
* has no parent or is directly attached to one of the already loaded scene
|
||||
* nodes.
|
||||
*
|
||||
* @param loadingResults
|
||||
* loading results containing the scene nodes
|
||||
* @param spatial
|
||||
* spatial object
|
||||
* @return <b>true</b> if the given spatial is a root object and
|
||||
* <b>false</b> otherwise
|
||||
*/
|
||||
protected boolean isRootObject(LoadingResults loadingResults, Spatial spatial) {
|
||||
if (spatial.getParent() == null) {
|
||||
return true;
|
||||
}
|
||||
for (Node scene : loadingResults.getScenes()) {
|
||||
if (spatial.getParent().equals(scene)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method converts the given structure to a scene node.
|
||||
* @param structure
|
||||
* structure of a scene
|
||||
* @return scene's node
|
||||
* @throws BlenderFileException
|
||||
* an exception throw when problems with blender file occur
|
||||
*/
|
||||
private Node toScene(Structure structure) {
|
||||
private Node toScene(Structure structure) throws BlenderFileException {
|
||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
||||
Node result = new Node(structure.getName());
|
||||
try {
|
||||
List<Structure> base = ((Structure) structure.getFieldValue("base")).evaluateListBase();
|
||||
for (Structure b : base) {
|
||||
Pointer pObject = (Pointer) b.getFieldValue("object");
|
||||
if (pObject.isNotNull()) {
|
||||
Structure objectStructure = pObject.fetchData().get(0);
|
||||
List<Structure> base = ((Structure) structure.getFieldValue("base")).evaluateListBase();
|
||||
for (Structure b : base) {
|
||||
Pointer pObject = (Pointer) b.getFieldValue("object");
|
||||
if (pObject.isNotNull()) {
|
||||
Structure objectStructure = pObject.fetchData().get(0);
|
||||
|
||||
Object object = objectHelper.toObject(objectStructure, blenderContext);
|
||||
if (object instanceof LightNode) {
|
||||
result.addLight(((LightNode) object).getLight());
|
||||
result.attachChild((LightNode) object);
|
||||
} else if (object instanceof Node) {
|
||||
if (LOGGER.isLoggable(Level.FINE)) {
|
||||
LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() });
|
||||
}
|
||||
if (((Node) object).getParent() == null) {
|
||||
result.attachChild((Spatial) object);
|
||||
}
|
||||
Object object = objectHelper.toObject(objectStructure, blenderContext);
|
||||
if (object instanceof LightNode) {
|
||||
result.addLight(((LightNode) object).getLight());// FIXME: check if this is needed !!!
|
||||
result.attachChild((LightNode) object);
|
||||
} else if (object instanceof Node) {
|
||||
if (LOGGER.isLoggable(Level.FINE)) {
|
||||
LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() });
|
||||
}
|
||||
if (((Node) object).getParent() == null) {
|
||||
result.attachChild((Spatial) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (BlenderFileException e) {
|
||||
LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -261,7 +301,7 @@ public class BlenderLoader implements AssetLoader {
|
||||
blenderContext.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), blenderContext));
|
||||
blenderContext.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber(), blenderContext));
|
||||
blenderContext.putHelper(LandscapeHelper.class, new LandscapeHelper(inputStream.getVersionNumber(), blenderContext));
|
||||
|
||||
|
||||
// reading the blocks (dna block is automatically saved in the blender context when found)
|
||||
FileBlockHeader sceneFileBlock = null;
|
||||
do {
|
||||
@ -269,7 +309,7 @@ public class BlenderLoader implements AssetLoader {
|
||||
if (!fileBlock.isDnaBlock()) {
|
||||
blocks.add(fileBlock);
|
||||
// save the scene's file block
|
||||
if (fileBlock.getCode() == FileBlockHeader.BLOCK_SC00) {
|
||||
if (fileBlock.getCode() == BlockCode.BLOCK_SC00) {
|
||||
sceneFileBlock = fileBlock;
|
||||
}
|
||||
}
|
||||
@ -287,4 +327,39 @@ public class BlenderLoader implements AssetLoader {
|
||||
blenderContext = null;
|
||||
blocks = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class holds the loading results according to the given loading flag.
|
||||
* @author Marcin Roguski (Kaelthas)
|
||||
*/
|
||||
private static class LoadedFeatures {
|
||||
private List<FileBlockHeader> sceneBlocks = new ArrayList<FileBlockHeader>();
|
||||
/** The scenes from the file. */
|
||||
private List<Node> scenes = new ArrayList<Node>();
|
||||
/** Objects from all scenes. */
|
||||
private List<Node> objects = new ArrayList<Node>();
|
||||
/** All meshes. */
|
||||
private List<TemporalMesh> meshes = new ArrayList<TemporalMesh>();
|
||||
/** Materials from all objects. */
|
||||
private List<MaterialContext> materials = new ArrayList<MaterialContext>();
|
||||
/** Textures from all objects. */
|
||||
private List<Texture> textures = new ArrayList<Texture>();
|
||||
/** The images stored in the blender file. */
|
||||
private List<Texture> images = new ArrayList<Texture>();
|
||||
/** Animations of all objects. */
|
||||
private List<Animation> animations = new ArrayList<Animation>();
|
||||
/** All cameras from the file. */
|
||||
private List<Camera> cameras = new ArrayList<Camera>();
|
||||
/** All lights from the file. */
|
||||
private List<Light> lights = new ArrayList<Light>();
|
||||
/** Loaded sky. */
|
||||
private Spatial sky;
|
||||
/** Scene filters (ie. FOG). */
|
||||
private List<Filter> filters = new ArrayList<Filter>();
|
||||
/**
|
||||
* The background color of the render loaded from the horizon color of the world. If no world is used than the gray color
|
||||
* is set to default (as in blender editor.
|
||||
*/
|
||||
private ColorRGBA backgroundColor = ColorRGBA.Gray;
|
||||
}
|
||||
}
|
||||
|
@ -31,79 +31,10 @@
|
||||
*/
|
||||
package com.jme3.scene.plugins.blender;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.asset.AssetInfo;
|
||||
import com.jme3.asset.BlenderKey;
|
||||
import com.jme3.asset.BlenderKey.FeaturesToLoad;
|
||||
import com.jme3.scene.LightNode;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.plugins.blender.animations.AnimationHelper;
|
||||
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
|
||||
import com.jme3.scene.plugins.blender.file.BlenderFileException;
|
||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||
|
||||
/**
|
||||
* This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures.
|
||||
*
|
||||
* @deprecated this class is deprecated; use BlenderLoader instead
|
||||
* @author Marcin Roguski (Kaelthas)
|
||||
*/
|
||||
public class BlenderModelLoader extends BlenderLoader {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(BlenderModelLoader.class.getName());
|
||||
|
||||
@Override
|
||||
public Spatial load(AssetInfo assetInfo) throws IOException {
|
||||
try {
|
||||
this.setup(assetInfo);
|
||||
|
||||
AnimationHelper animationHelper = blenderContext.getHelper(AnimationHelper.class);
|
||||
animationHelper.loadAnimations();
|
||||
|
||||
BlenderKey blenderKey = blenderContext.getBlenderKey();
|
||||
List<Node> rootObjects = new ArrayList<Node>();
|
||||
for (FileBlockHeader block : blocks) {
|
||||
if (block.getCode() == FileBlockHeader.BLOCK_OB00) {
|
||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
||||
Object object = objectHelper.toObject(block.getStructure(blenderContext), blenderContext);
|
||||
if (object instanceof LightNode && (blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) {
|
||||
rootObjects.add((LightNode) object);
|
||||
} else if (object instanceof Node && (blenderKey.getFeaturesToLoad() & FeaturesToLoad.OBJECTS) != 0) {
|
||||
LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() });
|
||||
if (((Node) object).getParent() == null) {
|
||||
rootObjects.add((Node) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bake constraints after everything is loaded
|
||||
ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
|
||||
constraintHelper.bakeConstraints(blenderContext);
|
||||
|
||||
// attach the nodes to the root node at the very end so that the root objects have no parents during constraint applying
|
||||
LOGGER.fine("Creating the root node of the model and applying loaded nodes of the scene to it.");
|
||||
Node modelRoot = new Node(blenderKey.getName());
|
||||
for (Node node : rootObjects) {
|
||||
if (node instanceof LightNode) {
|
||||
modelRoot.addLight(((LightNode) node).getLight());
|
||||
}
|
||||
modelRoot.attachChild(node);
|
||||
}
|
||||
|
||||
return modelRoot;
|
||||
} catch (BlenderFileException e) {
|
||||
throw new IOException(e.getLocalizedMessage(), e);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Unexpected importer exception occured: " + e.getLocalizedMessage(), e);
|
||||
} finally {
|
||||
this.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
||||
import com.jme3.scene.plugins.blender.file.BlenderFileException;
|
||||
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader.BlockCode;
|
||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||
import com.jme3.scene.plugins.blender.file.Structure;
|
||||
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||
@ -48,7 +49,7 @@ public class AnimationHelper extends AbstractBlenderHelper {
|
||||
*/
|
||||
public void loadAnimations() throws BlenderFileException {
|
||||
LOGGER.info("Loading animations that will be later applied to scene features.");
|
||||
List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
||||
List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(BlockCode.BLOCK_AC00);
|
||||
if (actionHeaders != null) {
|
||||
for (FileBlockHeader header : actionHeaders) {
|
||||
Structure actionStructure = header.getStructure(blenderContext);
|
||||
@ -70,7 +71,7 @@ public class AnimationHelper extends AbstractBlenderHelper {
|
||||
if (actions.size() > 0) {
|
||||
List<Animation> animations = new ArrayList<Animation>();
|
||||
for (BlenderAction action : actions) {
|
||||
SpatialTrack[] tracks = action.toTracks(node);
|
||||
SpatialTrack[] tracks = action.toTracks(node, blenderContext);
|
||||
if (tracks != null && tracks.length > 0) {
|
||||
Animation spatialAnimation = new Animation(action.getName(), action.getAnimationTime());
|
||||
spatialAnimation.setTracks(tracks);
|
||||
@ -109,7 +110,7 @@ public class AnimationHelper extends AbstractBlenderHelper {
|
||||
if (actions.size() > 0) {
|
||||
List<Animation> animations = new ArrayList<Animation>();
|
||||
for (BlenderAction action : actions) {
|
||||
BoneTrack[] tracks = action.toTracks(skeleton);
|
||||
BoneTrack[] tracks = action.toTracks(skeleton, blenderContext);
|
||||
if (tracks != null && tracks.length > 0) {
|
||||
Animation boneAnimation = new Animation(action.getName(), action.getAnimationTime());
|
||||
boneAnimation.setTracks(tracks);
|
||||
|
@ -10,9 +10,8 @@ import java.util.Map.Entry;
|
||||
import com.jme3.animation.BoneTrack;
|
||||
import com.jme3.animation.Skeleton;
|
||||
import com.jme3.animation.SpatialTrack;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||
|
||||
/**
|
||||
* An abstract representation of animation. The data stored here is mainly a
|
||||
@ -69,10 +68,10 @@ public class BlenderAction implements Cloneable {
|
||||
* the node that will be animated
|
||||
* @return the spatial tracks for the node
|
||||
*/
|
||||
public SpatialTrack[] toTracks(Node node) {
|
||||
public SpatialTrack[] toTracks(Node node, BlenderContext blenderContext) {
|
||||
List<SpatialTrack> tracks = new ArrayList<SpatialTrack>(featuresTracks.size());
|
||||
for (Entry<String, Ipo> entry : featuresTracks.entrySet()) {
|
||||
tracks.add((SpatialTrack) entry.getValue().calculateTrack(0, node.getLocalTranslation(), node.getLocalRotation(), node.getLocalScale(), 1, stopFrame, fps, true));
|
||||
tracks.add((SpatialTrack) entry.getValue().calculateTrack(0, null, node.getLocalTranslation(), node.getLocalRotation(), node.getLocalScale(), 1, stopFrame, fps, true));
|
||||
}
|
||||
return tracks.toArray(new SpatialTrack[tracks.size()]);
|
||||
}
|
||||
@ -84,11 +83,12 @@ public class BlenderAction implements Cloneable {
|
||||
* the skeleton that will be animated
|
||||
* @return the bone tracks for the node
|
||||
*/
|
||||
public BoneTrack[] toTracks(Skeleton skeleton) {
|
||||
public BoneTrack[] toTracks(Skeleton skeleton, BlenderContext blenderContext) {
|
||||
List<BoneTrack> tracks = new ArrayList<BoneTrack>(featuresTracks.size());
|
||||
for (Entry<String, Ipo> entry : featuresTracks.entrySet()) {
|
||||
int boneIndex = skeleton.getBoneIndex(entry.getKey());
|
||||
tracks.add((BoneTrack) entry.getValue().calculateTrack(boneIndex, Vector3f.ZERO, Quaternion.IDENTITY, Vector3f.UNIT_XYZ, 1, stopFrame, fps, false));
|
||||
BoneContext boneContext = blenderContext.getBoneContext(skeleton.getBone(boneIndex));
|
||||
tracks.add((BoneTrack) entry.getValue().calculateTrack(boneIndex, boneContext, boneContext.getBone().getBindPosition(), boneContext.getBone().getBindRotation(), boneContext.getBone().getBindScale(), 1, stopFrame, fps, false));
|
||||
}
|
||||
return tracks.toArray(new BoneTrack[tracks.size()]);
|
||||
}
|
||||
|
@ -25,10 +25,13 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||
*/
|
||||
public class BoneContext {
|
||||
// the flags of the bone
|
||||
public static final int SELECTED = 0x0001;
|
||||
public static final int CONNECTED_TO_PARENT = 0x0010;
|
||||
public static final int DEFORM = 0x1000;
|
||||
|
||||
public static final int SELECTED = 0x000001;
|
||||
public static final int CONNECTED_TO_PARENT = 0x000010;
|
||||
public static final int DEFORM = 0x001000;
|
||||
public static final int NO_LOCAL_LOCATION = 0x400000;
|
||||
public static final int NO_INHERIT_SCALE = 0x008000;
|
||||
public static final int NO_INHERIT_ROTATION = 0x000200;
|
||||
|
||||
/**
|
||||
* The bones' matrices have, unlike objects', the coordinate system identical to JME's (Y axis is UP, X to the right and Z toward us).
|
||||
* So in order to have them loaded properly we need to transform their armature matrix (which blender sees as rotated) to make sure we get identical results.
|
||||
|
@ -137,7 +137,7 @@ public class Ipo {
|
||||
* as jme while other features have different one (Z is UP)
|
||||
* @return bone track for the specified bone
|
||||
*/
|
||||
public Track calculateTrack(int targetIndex, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean spatialTrack) {
|
||||
public Track calculateTrack(int targetIndex, BoneContext boneContext, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean spatialTrack) {
|
||||
if (calculatedTrack == null) {
|
||||
// preparing data for track
|
||||
int framesAmount = stopFrame - startFrame;
|
||||
@ -236,6 +236,15 @@ public class Ipo {
|
||||
}
|
||||
}
|
||||
translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2]));
|
||||
|
||||
if(boneContext != null) {
|
||||
if(boneContext.getBone().getParent() == null && boneContext.is(BoneContext.NO_LOCAL_LOCATION)) {
|
||||
float temp = translations[index].z;
|
||||
translations[index].z = -translations[index].y;
|
||||
translations[index].y = temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (queternionRotationUsed) {
|
||||
rotations[index] = new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
|
||||
} else {
|
||||
@ -292,7 +301,7 @@ public class Ipo {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoneTrack calculateTrack(int boneIndex, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean boneTrack) {
|
||||
public BoneTrack calculateTrack(int boneIndex, BoneContext boneContext, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean boneTrack) {
|
||||
throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.scene.CameraNode;
|
||||
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||
import com.jme3.scene.plugins.blender.file.BlenderFileException;
|
||||
@ -43,7 +42,7 @@ public class CameraHelper extends AbstractBlenderHelper {
|
||||
* an exception is thrown when there are problems with the
|
||||
* blender file
|
||||
*/
|
||||
public CameraNode toCamera(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
|
||||
public Camera toCamera(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
|
||||
if (blenderVersion >= 250) {
|
||||
return this.toCamera250(structure, blenderContext.getSceneStructure());
|
||||
} else {
|
||||
@ -63,7 +62,7 @@ public class CameraHelper extends AbstractBlenderHelper {
|
||||
* an exception is thrown when there are problems with the
|
||||
* blender file
|
||||
*/
|
||||
private CameraNode toCamera250(Structure structure, Structure sceneStructure) throws BlenderFileException {
|
||||
private Camera toCamera250(Structure structure, Structure sceneStructure) throws BlenderFileException {
|
||||
int width = DEFAULT_CAM_WIDTH;
|
||||
int height = DEFAULT_CAM_HEIGHT;
|
||||
if (sceneStructure != null) {
|
||||
@ -99,7 +98,7 @@ public class CameraHelper extends AbstractBlenderHelper {
|
||||
sensor = ((Number) structure.getFieldValue(sensorName)).floatValue();
|
||||
}
|
||||
float focalLength = ((Number) structure.getFieldValue("lens")).floatValue();
|
||||
float fov = 2.0f * FastMath.atan((sensor / 2.0f) / focalLength);
|
||||
float fov = 2.0f * FastMath.atan(sensor / 2.0f / focalLength);
|
||||
if (sensorVertical) {
|
||||
fovY = fov * FastMath.RAD_TO_DEG;
|
||||
} else {
|
||||
@ -111,7 +110,8 @@ public class CameraHelper extends AbstractBlenderHelper {
|
||||
fovY = ((Number) structure.getFieldValue("ortho_scale")).floatValue();
|
||||
}
|
||||
camera.setFrustumPerspective(fovY, aspect, clipsta, clipend);
|
||||
return new CameraNode(null, camera);
|
||||
camera.setName(structure.getName());
|
||||
return camera;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,7 +124,7 @@ public class CameraHelper extends AbstractBlenderHelper {
|
||||
* an exception is thrown when there are problems with the
|
||||
* blender file
|
||||
*/
|
||||
private CameraNode toCamera249(Structure structure) throws BlenderFileException {
|
||||
private Camera toCamera249(Structure structure) throws BlenderFileException {
|
||||
Camera camera = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);
|
||||
int type = ((Number) structure.getFieldValue("type")).intValue();
|
||||
if (type != 0 && type != 1) {
|
||||
@ -142,6 +142,7 @@ public class CameraHelper extends AbstractBlenderHelper {
|
||||
aspect = ((Number) structure.getFieldValue("ortho_scale")).floatValue();
|
||||
}
|
||||
camera.setFrustumPerspective(aspect, camera.getWidth() / camera.getHeight(), clipsta, clipend);
|
||||
return new CameraNode(null, camera);
|
||||
camera.setName(structure.getName());
|
||||
return camera;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package com.jme3.scene.plugins.blender.curves;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||
import com.jme3.scene.plugins.blender.file.Structure;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class that helps to calculate the bezier curves calues. It uses doubles for performing calculations to minimize
|
||||
@ -12,21 +13,26 @@ import java.util.List;
|
||||
* @author Marcin Roguski (Kaelthas)
|
||||
*/
|
||||
public class BezierCurve {
|
||||
private static final int IPO_CONSTANT = 0;
|
||||
private static final int IPO_LINEAR = 1;
|
||||
private static final int IPO_BEZIER = 2;
|
||||
|
||||
public static final int X_VALUE = 0;
|
||||
public static final int Y_VALUE = 1;
|
||||
public static final int Z_VALUE = 2;
|
||||
public static final int X_VALUE = 0;
|
||||
public static final int Y_VALUE = 1;
|
||||
public static final int Z_VALUE = 2;
|
||||
/**
|
||||
* The type of the curve. Describes the data it modifies.
|
||||
* Used in ipos calculations.
|
||||
*/
|
||||
private int type;
|
||||
private int type;
|
||||
/** The dimension of the curve. */
|
||||
private int dimension;
|
||||
private int dimension;
|
||||
/** A table of the bezier points. */
|
||||
private double[][][] bezierPoints;
|
||||
private double[][][] bezierPoints;
|
||||
/** Array that stores a radius for each bezier triple. */
|
||||
private double[] radiuses;
|
||||
private double[] radiuses;
|
||||
/** Interpolation types of the bezier triples. */
|
||||
private int[] interpolations;
|
||||
|
||||
public BezierCurve(final int type, final List<Structure> bezTriples, final int dimension) {
|
||||
this(type, bezTriples, dimension, false);
|
||||
@ -44,6 +50,7 @@ public class BezierCurve {
|
||||
// the third index specifies the coordinates of the specific point in a bezier triple
|
||||
bezierPoints = new double[bezTriples.size()][3][dimension];
|
||||
radiuses = new double[bezTriples.size()];
|
||||
interpolations = new int[bezTriples.size()];
|
||||
int i = 0, j, k;
|
||||
for (Structure bezTriple : bezTriples) {
|
||||
DynamicArray<Number> vec = (DynamicArray<Number>) bezTriple.getFieldValue("vec");
|
||||
@ -57,7 +64,8 @@ public class BezierCurve {
|
||||
bezierPoints[i][j][1] = temp;
|
||||
}
|
||||
}
|
||||
radiuses[i++] = ((Number) bezTriple.getFieldValue("radius")).floatValue();
|
||||
radiuses[i] = ((Number) bezTriple.getFieldValue("radius")).floatValue();
|
||||
interpolations[i++] = ((Number) bezTriple.getFieldValue("ipo", IPO_BEZIER)).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,10 +83,19 @@ public class BezierCurve {
|
||||
for (int i = 0; i < bezierPoints.length - 1; ++i) {
|
||||
if (frame >= bezierPoints[i][1][0] && frame <= bezierPoints[i + 1][1][0]) {
|
||||
double t = (frame - bezierPoints[i][1][0]) / (bezierPoints[i + 1][1][0] - bezierPoints[i][1][0]);
|
||||
double oneMinusT = 1.0f - t;
|
||||
double oneMinusT2 = oneMinusT * oneMinusT;
|
||||
double t2 = t * t;
|
||||
return bezierPoints[i][1][valuePart] * oneMinusT2 * oneMinusT + 3.0f * bezierPoints[i][2][valuePart] * t * oneMinusT2 + 3.0f * bezierPoints[i + 1][0][valuePart] * t2 * oneMinusT + bezierPoints[i + 1][1][valuePart] * t2 * t;
|
||||
switch (interpolations[i]) {
|
||||
case IPO_BEZIER:
|
||||
double oneMinusT = 1.0f - t;
|
||||
double oneMinusT2 = oneMinusT * oneMinusT;
|
||||
double t2 = t * t;
|
||||
return bezierPoints[i][1][valuePart] * oneMinusT2 * oneMinusT + 3.0f * bezierPoints[i][2][valuePart] * t * oneMinusT2 + 3.0f * bezierPoints[i + 1][0][valuePart] * t2 * oneMinusT + bezierPoints[i + 1][1][valuePart] * t2 * t;
|
||||
case IPO_LINEAR:
|
||||
return (1f - t) * bezierPoints[i][1][valuePart] + t * bezierPoints[i + 1][1][valuePart];
|
||||
case IPO_CONSTANT:
|
||||
return bezierPoints[i][1][valuePart];
|
||||
default:
|
||||
throw new IllegalStateException("Unknown interpolation type for curve: " + interpolations[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (frame < bezierPoints[0][1][0]) {
|
||||
|
@ -31,6 +31,8 @@
|
||||
*/
|
||||
package com.jme3.scene.plugins.blender.file;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||
|
||||
/**
|
||||
@ -39,39 +41,23 @@ import com.jme3.scene.plugins.blender.BlenderContext;
|
||||
* @author Marcin Roguski
|
||||
*/
|
||||
public class FileBlockHeader {
|
||||
private static final Logger LOGGER = Logger.getLogger(FileBlockHeader.class.getName());
|
||||
|
||||
public static final int BLOCK_TE00 = 'T' << 24 | 'E' << 16; // TE00
|
||||
public static final int BLOCK_ME00 = 'M' << 24 | 'E' << 16; // ME00
|
||||
public static final int BLOCK_SR00 = 'S' << 24 | 'R' << 16; // SR00
|
||||
public static final int BLOCK_CA00 = 'C' << 24 | 'A' << 16; // CA00
|
||||
public static final int BLOCK_LA00 = 'L' << 24 | 'A' << 16; // LA00
|
||||
public static final int BLOCK_OB00 = 'O' << 24 | 'B' << 16; // OB00
|
||||
public static final int BLOCK_MA00 = 'M' << 24 | 'A' << 16; // MA00
|
||||
public static final int BLOCK_SC00 = 'S' << 24 | 'C' << 16; // SC00
|
||||
public static final int BLOCK_WO00 = 'W' << 24 | 'O' << 16; // WO00
|
||||
public static final int BLOCK_TX00 = 'T' << 24 | 'X' << 16; // TX00
|
||||
public static final int BLOCK_IP00 = 'I' << 24 | 'P' << 16; // IP00
|
||||
public static final int BLOCK_AC00 = 'A' << 24 | 'C' << 16; // AC00
|
||||
public static final int BLOCK_GLOB = 'G' << 24 | 'L' << 16 | 'O' << 8 | 'B'; // GLOB
|
||||
public static final int BLOCK_REND = 'R' << 24 | 'E' << 16 | 'N' << 8 | 'D'; // REND
|
||||
public static final int BLOCK_DATA = 'D' << 24 | 'A' << 16 | 'T' << 8 | 'A'; // DATA
|
||||
public static final int BLOCK_DNA1 = 'D' << 24 | 'N' << 16 | 'A' << 8 | '1'; // DNA1
|
||||
public static final int BLOCK_ENDB = 'E' << 24 | 'N' << 16 | 'D' << 8 | 'B'; // ENDB
|
||||
/** Identifier of the file-block [4 bytes]. */
|
||||
private int code;
|
||||
private BlockCode code;
|
||||
/** Total length of the data after the file-block-header [4 bytes]. */
|
||||
private int size;
|
||||
private int size;
|
||||
/**
|
||||
* Memory address the structure was located when written to disk [4 or 8 bytes (defined in file header as a pointer
|
||||
* size)].
|
||||
*/
|
||||
private long oldMemoryAddress;
|
||||
private long oldMemoryAddress;
|
||||
/** Index of the SDNA structure [4 bytes]. */
|
||||
private int sdnaIndex;
|
||||
private int sdnaIndex;
|
||||
/** Number of structure located in this file-block [4 bytes]. */
|
||||
private int count;
|
||||
private int count;
|
||||
/** Start position of the block's data in the stream. */
|
||||
private int blockPosition;
|
||||
private int blockPosition;
|
||||
|
||||
/**
|
||||
* Constructor. Loads the block header from the given stream during instance creation.
|
||||
@ -84,13 +70,13 @@ public class FileBlockHeader {
|
||||
*/
|
||||
public FileBlockHeader(BlenderInputStream inputStream, BlenderContext blenderContext) throws BlenderFileException {
|
||||
inputStream.alignPosition(4);
|
||||
code = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte();
|
||||
code = BlockCode.valueOf(inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte());
|
||||
size = inputStream.readInt();
|
||||
oldMemoryAddress = inputStream.readPointer();
|
||||
sdnaIndex = inputStream.readInt();
|
||||
count = inputStream.readInt();
|
||||
blockPosition = inputStream.getPosition();
|
||||
if (FileBlockHeader.BLOCK_DNA1 == code) {
|
||||
if (BlockCode.BLOCK_DNA1 == code) {
|
||||
blenderContext.setBlockData(new DnaBlockData(inputStream, blenderContext));
|
||||
} else {
|
||||
inputStream.setPosition(blockPosition + size);
|
||||
@ -116,7 +102,7 @@ public class FileBlockHeader {
|
||||
* This method returns the code of this data block.
|
||||
* @return the code of this data block
|
||||
*/
|
||||
public int getCode() {
|
||||
public BlockCode getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@ -157,7 +143,7 @@ public class FileBlockHeader {
|
||||
* @return true if this block is the last one in the file nad false otherwise
|
||||
*/
|
||||
public boolean isLastBlock() {
|
||||
return FileBlockHeader.BLOCK_ENDB == code;
|
||||
return BlockCode.BLOCK_ENDB == code;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,25 +151,44 @@ public class FileBlockHeader {
|
||||
* @return true if this block is the SDNA block and false otherwise
|
||||
*/
|
||||
public boolean isDnaBlock() {
|
||||
return FileBlockHeader.BLOCK_DNA1 == code;
|
||||
return BlockCode.BLOCK_DNA1 == code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FILE BLOCK HEADER [" + this.codeToString(code) + " : " + size + " : " + oldMemoryAddress + " : " + sdnaIndex + " : " + count + "]";
|
||||
return "FILE BLOCK HEADER [" + code.toString() + " : " + size + " : " + oldMemoryAddress + " : " + sdnaIndex + " : " + count + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* This method transforms the coded bloch id into a string value.
|
||||
* @param code
|
||||
* the id of the block
|
||||
* @return the string value of the block id
|
||||
*/
|
||||
protected String codeToString(int code) {
|
||||
char c1 = (char) ((code & 0xFF000000) >> 24);
|
||||
char c2 = (char) ((code & 0xFF0000) >> 16);
|
||||
char c3 = (char) ((code & 0xFF00) >> 8);
|
||||
char c4 = (char) (code & 0xFF);
|
||||
return String.valueOf(c1) + c2 + c3 + c4;
|
||||
public static enum BlockCode {
|
||||
BLOCK_ME00('M' << 24 | 'E' << 16), // mesh
|
||||
BLOCK_CA00('C' << 24 | 'A' << 16), // camera
|
||||
BLOCK_LA00('L' << 24 | 'A' << 16), // lamp
|
||||
BLOCK_OB00('O' << 24 | 'B' << 16), // object
|
||||
BLOCK_MA00('M' << 24 | 'A' << 16), // material
|
||||
BLOCK_SC00('S' << 24 | 'C' << 16), // scene
|
||||
BLOCK_WO00('W' << 24 | 'O' << 16), // world
|
||||
BLOCK_TX00('T' << 24 | 'X' << 16), // texture
|
||||
BLOCK_IP00('I' << 24 | 'P' << 16), // ipo
|
||||
BLOCK_AC00('A' << 24 | 'C' << 16), // action
|
||||
BLOCK_IM00('I' << 24 | 'M' << 16), // image
|
||||
BLOCK_TE00('T' << 24 | 'E' << 16), BLOCK_WM00('W' << 24 | 'M' << 16), BLOCK_SR00('S' << 24 | 'R' << 16), BLOCK_SN00('S' << 24 | 'N' << 16), BLOCK_BR00('B' << 24 | 'R' << 16), BLOCK_LS00('L' << 24 | 'S' << 16), BLOCK_GLOB('G' << 24 | 'L' << 16 | 'O' << 8 | 'B'), BLOCK_REND('R' << 24 | 'E' << 16 | 'N' << 8 | 'D'), BLOCK_DATA('D' << 24 | 'A' << 16 | 'T' << 8 | 'A'), BLOCK_DNA1('D' << 24 | 'N' << 16 | 'A' << 8 | '1'), BLOCK_ENDB('E' << 24 | 'N' << 16 | 'D' << 8 | 'B'), BLOCK_TEST('T' << 24 | 'E' << 16
|
||||
| 'S' << 8 | 'T'), BLOCK_UNKN(0);
|
||||
|
||||
private int code;
|
||||
|
||||
private BlockCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public static BlockCode valueOf(int code) {
|
||||
for (BlockCode blockCode : BlockCode.values()) {
|
||||
if (blockCode.code == code) {
|
||||
return blockCode;
|
||||
}
|
||||
}
|
||||
byte[] codeBytes = new byte[] { (byte) (code >> 24 & 0xFF), (byte) (code >> 16 & 0xFF), (byte) (code >> 8 & 0xFF), (byte) (code & 0xFF) };
|
||||
LOGGER.warning("Unknown block header: " + new String(codeBytes));
|
||||
return BLOCK_UNKN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,7 +254,8 @@ public class Structure implements Cloneable {
|
||||
Structure id = (Structure) fieldValue;
|
||||
return id == null ? null : id.getFieldValue("name").toString().substring(2);// blender adds 2-charactes as a name prefix
|
||||
}
|
||||
return null;
|
||||
Object name = this.getFieldValue("name", null);
|
||||
return name == null ? null : name.toString().substring(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -208,6 +208,6 @@ public class LandscapeHelper extends AbstractBlenderHelper {
|
||||
}
|
||||
|
||||
LOGGER.fine("Sky texture created. Creating sky.");
|
||||
return SkyFactory.createSky(blenderContext.getAssetManager(), texture, false);
|
||||
return SkyFactory.createSky(blenderContext.getAssetManager(), texture, SkyFactory.EnvMapType.CubeMap);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ import com.jme3.light.PointLight;
|
||||
import com.jme3.light.SpotLight;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.scene.LightNode;
|
||||
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||
import com.jme3.scene.plugins.blender.BlenderContext.LoadedDataType;
|
||||
@ -67,8 +66,8 @@ public class LightHelper extends AbstractBlenderHelper {
|
||||
super(blenderVersion, blenderContext);
|
||||
}
|
||||
|
||||
public LightNode toLight(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
|
||||
LightNode result = (LightNode) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedDataType.FEATURE);
|
||||
public Light toLight(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
|
||||
Light result = (Light) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedDataType.FEATURE);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
@ -111,6 +110,7 @@ public class LightHelper extends AbstractBlenderHelper {
|
||||
float g = ((Number) structure.getFieldValue("g")).floatValue();
|
||||
float b = ((Number) structure.getFieldValue("b")).floatValue();
|
||||
light.setColor(new ColorRGBA(r, g, b, 1.0f));
|
||||
return new LightNode(structure.getName(), light);
|
||||
light.setName(structure.getName());
|
||||
return light;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
package com.jme3.scene.plugins.blender.materials;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.export.JmeExporter;
|
||||
import com.jme3.export.JmeImporter;
|
||||
import com.jme3.export.Savable;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.material.RenderState.BlendMode;
|
||||
import com.jme3.material.RenderState.FaceCullMode;
|
||||
@ -30,7 +34,7 @@ import com.jme3.util.BufferUtils;
|
||||
* This class holds the data about the material.
|
||||
* @author Marcin Roguski (Kaelthas)
|
||||
*/
|
||||
public final class MaterialContext {
|
||||
public final class MaterialContext implements Savable {
|
||||
private static final Logger LOGGER = Logger.getLogger(MaterialContext.class.getName());
|
||||
|
||||
// texture mapping types
|
||||
@ -67,7 +71,7 @@ public final class MaterialContext {
|
||||
int diff_shader = ((Number) structure.getFieldValue("diff_shader")).intValue();
|
||||
diffuseShader = DiffuseShader.values()[diff_shader];
|
||||
ambientFactor = ((Number) structure.getFieldValue("amb")).floatValue();
|
||||
|
||||
|
||||
if (shadeless) {
|
||||
float r = ((Number) structure.getFieldValue("r")).floatValue();
|
||||
float g = ((Number) structure.getFieldValue("g")).floatValue();
|
||||
@ -107,6 +111,13 @@ public final class MaterialContext {
|
||||
this.transparent = transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the material
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies material to a given geometry.
|
||||
*
|
||||
@ -314,4 +325,14 @@ public final class MaterialContext {
|
||||
float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
|
||||
return new ColorRGBA(r, g, b, alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JmeExporter e) throws IOException {
|
||||
throw new IOException("Material context is not for saving! It implements savable only to be passed to another blend file as a Savable in user data!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(JmeImporter e) throws IOException {
|
||||
throw new IOException("Material context is not for loading! It implements savable only to be passed to another blend file as a Savable in user data!");
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
||||
import com.jme3.shader.VarType;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.Image.Format;
|
||||
import com.jme3.texture.image.ColorSpace;
|
||||
import com.jme3.texture.Texture;
|
||||
import com.jme3.util.BufferUtils;
|
||||
|
||||
@ -161,12 +162,17 @@ public class MaterialHelper extends AbstractBlenderHelper {
|
||||
* an exception is throw when problems with blend file occur
|
||||
*/
|
||||
public MaterialContext toMaterialContext(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
|
||||
LOGGER.log(Level.FINE, "Loading material.");
|
||||
MaterialContext result = (MaterialContext) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedDataType.FEATURE);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if ("ID".equals(structure.getType())) {
|
||||
LOGGER.fine("Loading material from external blend file.");
|
||||
return (MaterialContext) this.loadLibrary(structure);
|
||||
}
|
||||
|
||||
LOGGER.fine("Loading material.");
|
||||
result = new MaterialContext(structure, blenderContext);
|
||||
LOGGER.log(Level.FINE, "Material''s name: {0}", result.name);
|
||||
Long oma = structure.getOldMemoryAddress();
|
||||
@ -212,7 +218,7 @@ public class MaterialHelper extends AbstractBlenderHelper {
|
||||
}
|
||||
}
|
||||
|
||||
image = new Image(Format.RGBA8, w, h, bb);
|
||||
image = new Image(Format.RGBA8, w, h, bb, ColorSpace.Linear);
|
||||
texture.setImage(image);
|
||||
|
||||
result.setTextureParam("Texture", VarType.Texture2D, texture);
|
||||
|
@ -40,7 +40,6 @@ import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.asset.BlenderKey.FeaturesToLoad;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Vector2f;
|
||||
@ -52,7 +51,6 @@ import com.jme3.scene.plugins.blender.file.BlenderFileException;
|
||||
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||
import com.jme3.scene.plugins.blender.file.Structure;
|
||||
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
||||
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||
import com.jme3.scene.plugins.blender.objects.Properties;
|
||||
|
||||
@ -106,17 +104,18 @@ public class MeshHelper extends AbstractBlenderHelper {
|
||||
return temporalMesh.clone();
|
||||
}
|
||||
|
||||
if ("ID".equals(meshStructure.getType())) {
|
||||
LOGGER.fine("Loading mesh from external blend file.");
|
||||
return (TemporalMesh) this.loadLibrary(meshStructure);
|
||||
}
|
||||
|
||||
String name = meshStructure.getName();
|
||||
LOGGER.log(Level.FINE, "Reading mesh: {0}.", name);
|
||||
temporalMesh = new TemporalMesh(meshStructure, blenderContext);
|
||||
|
||||
LOGGER.fine("Loading materials.");
|
||||
MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
|
||||
MaterialContext[] materials = null;
|
||||
if ((blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {
|
||||
materials = materialHelper.getMaterials(meshStructure, blenderContext);
|
||||
}
|
||||
temporalMesh.setMaterials(materials);
|
||||
temporalMesh.setMaterials(materialHelper.getMaterials(meshStructure, blenderContext));
|
||||
|
||||
LOGGER.fine("Reading custom properties.");
|
||||
Properties properties = this.loadProperties(meshStructure, blenderContext);
|
||||
|
@ -40,12 +40,15 @@ import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.asset.BlenderKey.FeaturesToLoad;
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Matrix4f;
|
||||
import com.jme3.math.Transform;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.scene.CameraNode;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.LightNode;
|
||||
import com.jme3.scene.Mesh.Mode;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
@ -106,39 +109,34 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
||||
* an exception is thrown when the given data is inapropriate
|
||||
*/
|
||||
public Object toObject(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||
LOGGER.fine("Loading blender object.");
|
||||
Object loadedResult = blenderContext.getLoadedFeature(objectStructure.getOldMemoryAddress(), LoadedDataType.FEATURE);
|
||||
if (loadedResult != null) {
|
||||
return loadedResult;
|
||||
}
|
||||
|
||||
LOGGER.fine("Loading blender object.");
|
||||
if ("ID".equals(objectStructure.getType())) {
|
||||
Node object = (Node) this.loadLibrary(objectStructure);
|
||||
if (object.getParent() != null) {
|
||||
LOGGER.log(Level.FINEST, "Detaching object {0}, loaded from external file, from its parent.", object);
|
||||
object.getParent().detachChild(object);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
int type = ((Number) objectStructure.getFieldValue("type")).intValue();
|
||||
ObjectType objectType = ObjectType.valueOf(type);
|
||||
LOGGER.log(Level.FINE, "Type of the object: {0}.", objectType);
|
||||
if (objectType == ObjectType.LAMP && !blenderContext.getBlenderKey().shouldLoad(FeaturesToLoad.LIGHTS)) {
|
||||
LOGGER.fine("Lamps are not included in loading.");
|
||||
return null;
|
||||
}
|
||||
if (objectType == ObjectType.CAMERA && !blenderContext.getBlenderKey().shouldLoad(FeaturesToLoad.CAMERAS)) {
|
||||
LOGGER.fine("Cameras are not included in loading.");
|
||||
return null;
|
||||
}
|
||||
if (!blenderContext.getBlenderKey().shouldLoad(FeaturesToLoad.OBJECTS)) {
|
||||
LOGGER.fine("Objects are not included in loading.");
|
||||
return null;
|
||||
}
|
||||
|
||||
int lay = ((Number) objectStructure.getFieldValue("lay")).intValue();
|
||||
if ((lay & blenderContext.getBlenderKey().getLayersToLoad()) == 0) {
|
||||
LOGGER.fine("The layer this object is located in is not included in loading.");
|
||||
return null;
|
||||
}
|
||||
|
||||
LOGGER.fine("Checking if the object has not been already loaded.");
|
||||
Object loadedResult = blenderContext.getLoadedFeature(objectStructure.getOldMemoryAddress(), LoadedDataType.FEATURE);
|
||||
if (loadedResult != null) {
|
||||
return loadedResult;
|
||||
}
|
||||
|
||||
blenderContext.pushParent(objectStructure);
|
||||
String name = objectStructure.getName();
|
||||
LOGGER.log(Level.FINE, "Loading obejct: {0}", name);
|
||||
|
||||
|
||||
int restrictflag = ((Number) objectStructure.getFieldValue("restrictflag")).intValue();
|
||||
boolean visible = (restrictflag & 0x01) != 0;
|
||||
|
||||
@ -171,7 +169,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
||||
Pointer pMesh = (Pointer) objectStructure.getFieldValue("data");
|
||||
List<Structure> meshesArray = pMesh.fetchData();
|
||||
TemporalMesh temporalMesh = meshHelper.toTemporalMesh(meshesArray.get(0), blenderContext);
|
||||
if(temporalMesh != null) {
|
||||
if (temporalMesh != null) {
|
||||
result.attachChild(temporalMesh);
|
||||
}
|
||||
break;
|
||||
@ -183,7 +181,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
||||
CurvesHelper curvesHelper = blenderContext.getHelper(CurvesHelper.class);
|
||||
Structure curveData = pCurve.fetchData().get(0);
|
||||
TemporalMesh curvesTemporalMesh = curvesHelper.toCurve(curveData, blenderContext);
|
||||
if(curvesTemporalMesh != null) {
|
||||
if (curvesTemporalMesh != null) {
|
||||
result.attachChild(curvesTemporalMesh);
|
||||
}
|
||||
}
|
||||
@ -193,10 +191,12 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
||||
if (pLamp.isNotNull()) {
|
||||
LightHelper lightHelper = blenderContext.getHelper(LightHelper.class);
|
||||
List<Structure> lampsArray = pLamp.fetchData();
|
||||
result = lightHelper.toLight(lampsArray.get(0), blenderContext);
|
||||
if (result == null) {
|
||||
Light light = lightHelper.toLight(lampsArray.get(0), blenderContext);
|
||||
if (light == null) {
|
||||
// probably some light type is not supported, just create a node so that we can maintain child-parent relationship for nodes
|
||||
result = new Node(name);
|
||||
} else {
|
||||
result = new LightNode(name, light);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -205,19 +205,25 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
||||
if (pCamera.isNotNull()) {
|
||||
CameraHelper cameraHelper = blenderContext.getHelper(CameraHelper.class);
|
||||
List<Structure> camerasArray = pCamera.fetchData();
|
||||
result = cameraHelper.toCamera(camerasArray.get(0), blenderContext);
|
||||
Camera camera = cameraHelper.toCamera(camerasArray.get(0), blenderContext);
|
||||
if (camera == null) {
|
||||
// just create a node so that we can maintain child-parent relationship for nodes
|
||||
result = new Node(name);
|
||||
} else {
|
||||
result = new CameraNode(name, camera);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGGER.log(Level.WARNING, "Unsupported object type: {0}", type);
|
||||
}
|
||||
|
||||
|
||||
if (result != null) {
|
||||
LOGGER.fine("Storing loaded feature in blender context and applying markers (those will be removed before the final result is released).");
|
||||
Long oma = objectStructure.getOldMemoryAddress();
|
||||
blenderContext.addLoadedFeatures(oma, LoadedDataType.STRUCTURE, objectStructure);
|
||||
blenderContext.addLoadedFeatures(oma, LoadedDataType.FEATURE, result);
|
||||
|
||||
|
||||
blenderContext.addMarker(OMA_MARKER, result, objectStructure.getOldMemoryAddress());
|
||||
if (objectType == ObjectType.ARMATURE) {
|
||||
blenderContext.addMarker(ARMATURE_NODE_MARKER, result, Boolean.TRUE);
|
||||
@ -235,13 +241,13 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
||||
for (Modifier modifier : modifiers) {
|
||||
modifier.apply(result, blenderContext);
|
||||
}
|
||||
|
||||
|
||||
if (result.getChildren() != null && result.getChildren().size() > 0) {
|
||||
if(result.getChildren().size() == 1 && result.getChild(0) instanceof TemporalMesh) {
|
||||
if (result.getChildren().size() == 1 && result.getChild(0) instanceof TemporalMesh) {
|
||||
LOGGER.fine("Converting temporal mesh into jme geometries.");
|
||||
((TemporalMesh)result.getChild(0)).toGeometries();
|
||||
((TemporalMesh) result.getChild(0)).toGeometries();
|
||||
}
|
||||
|
||||
|
||||
LOGGER.fine("Applying proper scale to the geometries.");
|
||||
for (Spatial child : result.getChildren()) {
|
||||
if (child instanceof Geometry) {
|
||||
|
@ -444,13 +444,17 @@ public class CombinedTexture {
|
||||
case RGB8:
|
||||
return true;// these types have no alpha by definition
|
||||
case ABGR8:
|
||||
case DXT1A:
|
||||
case DXT3:
|
||||
case DXT5:
|
||||
case Luminance16FAlpha16F:
|
||||
case Luminance8Alpha8:
|
||||
case RGBA16F:
|
||||
case RGBA32F:
|
||||
case RGBA8:// with these types it is better to make sure if the texture is or is not transparent
|
||||
case RGBA8:
|
||||
case ARGB8:
|
||||
case BGRA8:
|
||||
case RGB5A1:// with these types it is better to make sure if the texture is or is not transparent
|
||||
PixelInputOutput pixelInputOutput = PixelIOFactory.getPixelIO(image.getFormat());
|
||||
TexturePixel pixel = new TexturePixel();
|
||||
int depth = image.getDepth() == 0 ? 1 : image.getDepth();
|
||||
@ -465,6 +469,8 @@ public class CombinedTexture {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown image format: " + image.getFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,13 +41,13 @@ public final class ImageUtils {
|
||||
public static Image createEmptyImage(Format format, int width, int height, int depth) {
|
||||
int bufferSize = width * height * (format.getBitsPerPixel() >> 3);
|
||||
if (depth < 2) {
|
||||
return new Image(format, width, height, BufferUtils.createByteBuffer(bufferSize));
|
||||
return new Image(format, width, height, BufferUtils.createByteBuffer(bufferSize), com.jme3.texture.image.ColorSpace.Linear);
|
||||
}
|
||||
ArrayList<ByteBuffer> data = new ArrayList<ByteBuffer>(depth);
|
||||
for (int i = 0; i < depth; ++i) {
|
||||
data.add(BufferUtils.createByteBuffer(bufferSize));
|
||||
}
|
||||
return new Image(Format.RGB8, width, height, depth, data);
|
||||
return new Image(Format.RGB8, width, height, depth, data, com.jme3.texture.image.ColorSpace.Linear);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -337,7 +337,7 @@ public final class ImageUtils {
|
||||
alphas[0] = data.get() * 255.0f;
|
||||
alphas[1] = data.get() * 255.0f;
|
||||
//the casts to long must be done here because otherwise 32-bit integers would be shifetd by 32 and 40 bits which would result in improper values
|
||||
long alphaIndices = (long)data.get() | (long)data.get() << 8 | (long)data.get() << 16 | (long)data.get() << 24 | (long)data.get() << 32 | (long)data.get() << 40;
|
||||
long alphaIndices = data.get() | (long)data.get() << 8 | (long)data.get() << 16 | (long)data.get() << 24 | (long)data.get() << 32 | (long)data.get() << 40;
|
||||
if (alphas[0] > alphas[1]) {// 6 interpolated alpha values.
|
||||
alphas[2] = (6 * alphas[0] + alphas[1]) / 7;
|
||||
alphas[3] = (5 * alphas[0] + 2 * alphas[1]) / 7;
|
||||
@ -404,7 +404,8 @@ public final class ImageUtils {
|
||||
dataArray.add(BufferUtils.createByteBuffer(bytes));
|
||||
}
|
||||
|
||||
Image result = depth > 1 ? new Image(Format.RGBA8, image.getWidth(), image.getHeight(), depth, dataArray) : new Image(Format.RGBA8, image.getWidth(), image.getHeight(), dataArray.get(0));
|
||||
Image result = depth > 1 ? new Image(Format.RGBA8, image.getWidth(), image.getHeight(), depth, dataArray, com.jme3.texture.image.ColorSpace.Linear) :
|
||||
new Image(Format.RGBA8, image.getWidth(), image.getHeight(), dataArray.get(0), com.jme3.texture.image.ColorSpace.Linear);
|
||||
if (newMipmapSizes != null) {
|
||||
result.setMipMapSizes(newMipmapSizes);
|
||||
}
|
||||
@ -467,6 +468,6 @@ public final class ImageUtils {
|
||||
private static Image toJmeImage(BufferedImage bufferedImage, Format format) {
|
||||
ByteBuffer byteBuffer = BufferUtils.createByteBuffer(bufferedImage.getWidth() * bufferedImage.getHeight() * 3);
|
||||
ImageToAwt.convert(bufferedImage, format, byteBuffer);
|
||||
return new Image(format, bufferedImage.getWidth(), bufferedImage.getHeight(), byteBuffer);
|
||||
return new Image(format, bufferedImage.getWidth(), bufferedImage.getHeight(), byteBuffer, com.jme3.texture.image.ColorSpace.Linear);
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
* data. The returned texture has the name set to the value of its blender
|
||||
* type.
|
||||
*
|
||||
* @param tex
|
||||
* @param textureStructure
|
||||
* texture structure filled with data
|
||||
* @param blenderContext
|
||||
* the blender context
|
||||
@ -130,23 +130,29 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
* this exception is thrown when the blend file structure is
|
||||
* somehow invalid or corrupted
|
||||
*/
|
||||
public Texture getTexture(Structure tex, Structure mTex, BlenderContext blenderContext) throws BlenderFileException {
|
||||
Texture result = (Texture) blenderContext.getLoadedFeature(tex.getOldMemoryAddress(), LoadedDataType.FEATURE);
|
||||
public Texture getTexture(Structure textureStructure, Structure mTex, BlenderContext blenderContext) throws BlenderFileException {
|
||||
Texture result = (Texture) blenderContext.getLoadedFeature(textureStructure.getOldMemoryAddress(), LoadedDataType.FEATURE);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
int type = ((Number) tex.getFieldValue("type")).intValue();
|
||||
int imaflag = ((Number) tex.getFieldValue("imaflag")).intValue();
|
||||
|
||||
if ("ID".equals(textureStructure.getType())) {
|
||||
LOGGER.fine("Loading texture from external blend file.");
|
||||
return (Texture) this.loadLibrary(textureStructure);
|
||||
}
|
||||
|
||||
int type = ((Number) textureStructure.getFieldValue("type")).intValue();
|
||||
int imaflag = ((Number) textureStructure.getFieldValue("imaflag")).intValue();
|
||||
|
||||
switch (type) {
|
||||
case TEX_IMAGE:// (it is first because probably this will be most commonly used)
|
||||
Pointer pImage = (Pointer) tex.getFieldValue("ima");
|
||||
Pointer pImage = (Pointer) textureStructure.getFieldValue("ima");
|
||||
if (pImage.isNotNull()) {
|
||||
Structure image = pImage.fetchData().get(0);
|
||||
Texture loadedTexture = this.loadTexture(image, imaflag, blenderContext);
|
||||
Texture loadedTexture = this.loadImageAsTexture(image, imaflag, blenderContext);
|
||||
if (loadedTexture != null) {
|
||||
result = loadedTexture;
|
||||
this.applyColorbandAndColorFactors(tex, result.getImage(), blenderContext);
|
||||
this.applyColorbandAndColorFactors(textureStructure, result.getImage(), blenderContext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -160,7 +166,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
case TEX_MUSGRAVE:
|
||||
case TEX_VORONOI:
|
||||
case TEX_DISTNOISE:
|
||||
result = new GeneratedTexture(tex, mTex, textureGeneratorFactory.createTextureGenerator(type), blenderContext);
|
||||
result = new GeneratedTexture(textureStructure, mTex, textureGeneratorFactory.createTextureGenerator(type), blenderContext);
|
||||
break;
|
||||
case TEX_NONE:// No texture, do nothing
|
||||
break;
|
||||
@ -169,13 +175,13 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
case TEX_PLUGIN:
|
||||
case TEX_ENVMAP:
|
||||
case TEX_OCEAN:
|
||||
LOGGER.log(Level.WARNING, "Unsupported texture type: {0} for texture: {1}", new Object[] { type, tex.getName() });
|
||||
LOGGER.log(Level.WARNING, "Unsupported texture type: {0} for texture: {1}", new Object[] { type, textureStructure.getName() });
|
||||
break;
|
||||
default:
|
||||
throw new BlenderFileException("Unknown texture type: " + type + " for texture: " + tex.getName());
|
||||
throw new BlenderFileException("Unknown texture type: " + type + " for texture: " + textureStructure.getName());
|
||||
}
|
||||
if (result != null) {
|
||||
result.setName(tex.getName());
|
||||
result.setName(textureStructure.getName());
|
||||
result.setWrap(WrapMode.Repeat);
|
||||
|
||||
// decide if the mipmaps will be generated
|
||||
@ -195,14 +201,14 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
}
|
||||
|
||||
if (type != TEX_IMAGE) {// only generated textures should have this key
|
||||
result.setKey(new GeneratedTextureKey(tex.getName()));
|
||||
result.setKey(new GeneratedTextureKey(textureStructure.getName()));
|
||||
}
|
||||
|
||||
if (LOGGER.isLoggable(Level.FINE)) {
|
||||
LOGGER.log(Level.FINE, "Adding texture {0} to the loaded features with OMA = {1}", new Object[] { result.getName(), tex.getOldMemoryAddress() });
|
||||
LOGGER.log(Level.FINE, "Adding texture {0} to the loaded features with OMA = {1}", new Object[] { result.getName(), textureStructure.getOldMemoryAddress() });
|
||||
}
|
||||
blenderContext.addLoadedFeatures(tex.getOldMemoryAddress(), LoadedDataType.STRUCTURE, tex);
|
||||
blenderContext.addLoadedFeatures(tex.getOldMemoryAddress(), LoadedDataType.FEATURE, result);
|
||||
blenderContext.addLoadedFeatures(textureStructure.getOldMemoryAddress(), LoadedDataType.STRUCTURE, textureStructure);
|
||||
blenderContext.addLoadedFeatures(textureStructure.getOldMemoryAddress(), LoadedDataType.FEATURE, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -222,29 +228,39 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
* this exception is thrown when the blend file structure is
|
||||
* somehow invalid or corrupted
|
||||
*/
|
||||
protected Texture loadTexture(Structure imageStructure, int imaflag, BlenderContext blenderContext) throws BlenderFileException {
|
||||
public Texture loadImageAsTexture(Structure imageStructure, int imaflag, BlenderContext blenderContext) throws BlenderFileException {
|
||||
LOGGER.log(Level.FINE, "Fetching texture with OMA = {0}", imageStructure.getOldMemoryAddress());
|
||||
Texture result = null;
|
||||
Image im = (Image) blenderContext.getLoadedFeature(imageStructure.getOldMemoryAddress(), LoadedDataType.FEATURE);
|
||||
if (im == null) {
|
||||
String texturePath = imageStructure.getFieldValue("name").toString();
|
||||
Pointer pPackedFile = (Pointer) imageStructure.getFieldValue("packedfile");
|
||||
if (pPackedFile.isNull()) {
|
||||
LOGGER.log(Level.FINE, "Reading texture from file: {0}", texturePath);
|
||||
result = this.loadImageFromFile(texturePath, imaflag, blenderContext);
|
||||
// if (im == null) { HACK force reaload always, as constructor in else case is destroying the TextureKeys!
|
||||
if ("ID".equals(imageStructure.getType())) {
|
||||
LOGGER.fine("Loading texture from external blend file.");
|
||||
result = (Texture) this.loadLibrary(imageStructure);
|
||||
} else {
|
||||
LOGGER.fine("Packed texture. Reading directly from the blend file!");
|
||||
Structure packedFile = pPackedFile.fetchData().get(0);
|
||||
Pointer pData = (Pointer) packedFile.getFieldValue("data");
|
||||
FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pData.getOldMemoryAddress());
|
||||
blenderContext.getInputStream().setPosition(dataFileBlock.getBlockPosition());
|
||||
ImageLoader imageLoader = new ImageLoader();
|
||||
String texturePath = imageStructure.getFieldValue("name").toString();
|
||||
Pointer pPackedFile = (Pointer) imageStructure.getFieldValue("packedfile");
|
||||
if (pPackedFile.isNull()) {
|
||||
LOGGER.log(Level.FINE, "Reading texture from file: {0}", texturePath);
|
||||
result = this.loadImageFromFile(texturePath, imaflag, blenderContext);
|
||||
} else {
|
||||
LOGGER.fine("Packed texture. Reading directly from the blend file!");
|
||||
Structure packedFile = pPackedFile.fetchData().get(0);
|
||||
Pointer pData = (Pointer) packedFile.getFieldValue("data");
|
||||
FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pData.getOldMemoryAddress());
|
||||
blenderContext.getInputStream().setPosition(dataFileBlock.getBlockPosition());
|
||||
|
||||
// Should the texture be flipped? It works for sinbad ..
|
||||
result = new Texture2D(imageLoader.loadImage(blenderContext.getInputStream(), dataFileBlock.getBlockPosition(), true));
|
||||
// Should the texture be flipped? It works for sinbad ..
|
||||
result = new Texture2D(new ImageLoader().loadImage(blenderContext.getInputStream(), dataFileBlock.getBlockPosition(), true));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = new Texture2D(im);
|
||||
//} else {
|
||||
// result = new Texture2D(im);
|
||||
// }
|
||||
|
||||
if (result != null) {// render result is not being loaded
|
||||
blenderContext.addLoadedFeatures(imageStructure.getOldMemoryAddress(), LoadedDataType.STRUCTURE, imageStructure);
|
||||
blenderContext.addLoadedFeatures(imageStructure.getOldMemoryAddress(), LoadedDataType.FEATURE, result.getImage());
|
||||
result.setName(imageStructure.getName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -524,6 +540,18 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the texture data from the given material or sky structure.
|
||||
* @param structure
|
||||
* the structure of material or sky
|
||||
* @param diffuseColorArray
|
||||
* array of diffuse colors
|
||||
* @param skyTexture
|
||||
* indicates it we're going to read sky texture or not
|
||||
* @return a list of combined textures
|
||||
* @throws BlenderFileException
|
||||
* an exception is thrown when problems with reading the blend file occur
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<CombinedTexture> readTextureData(Structure structure, float[] diffuseColorArray, boolean skyTexture) throws BlenderFileException {
|
||||
DynamicArray<Pointer> mtexsArray = (DynamicArray<Pointer>) structure.getFieldValue("mtex");
|
||||
|
@ -31,6 +31,7 @@ import com.jme3.texture.Image;
|
||||
import com.jme3.texture.Image.Format;
|
||||
import com.jme3.texture.Texture;
|
||||
import com.jme3.texture.Texture2D;
|
||||
import com.jme3.texture.image.ColorSpace;
|
||||
import com.jme3.util.BufferUtils;
|
||||
|
||||
/**
|
||||
@ -77,7 +78,7 @@ import com.jme3.util.BufferUtils;
|
||||
for (int i = 0; i < facesCount; ++i) {
|
||||
faceTextures.add(new TriangleTextureElement(i, texture2d.getImage(), uvs, true, blenderContext));
|
||||
}
|
||||
this.format = texture2d.getImage().getFormat();
|
||||
format = texture2d.getImage().getFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,7 +114,7 @@ import com.jme3.util.BufferUtils;
|
||||
*/
|
||||
public void blend(TextureBlender textureBlender, TriangulatedTexture baseTexture, BlenderContext blenderContext) {
|
||||
Format newFormat = null;
|
||||
for (TriangleTextureElement triangleTextureElement : this.faceTextures) {
|
||||
for (TriangleTextureElement triangleTextureElement : faceTextures) {
|
||||
Image baseImage = baseTexture == null ? null : baseTexture.getFaceTextureElement(triangleTextureElement.faceIndex).image;
|
||||
triangleTextureElement.image = textureBlender.blend(triangleTextureElement.image, baseImage, blenderContext);
|
||||
if (newFormat == null) {
|
||||
@ -122,7 +123,7 @@ import com.jme3.util.BufferUtils;
|
||||
throw new IllegalArgumentException("Face texture element images MUST have the same image format!");
|
||||
}
|
||||
}
|
||||
this.format = newFormat;
|
||||
format = newFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -242,7 +243,7 @@ import com.jme3.util.BufferUtils;
|
||||
resultUVS.set(entry.getKey().faceIndex * 3 + 2, uvs[2]);
|
||||
}
|
||||
|
||||
Image resultImage = new Image(format, resultImageWidth, resultImageHeight, BufferUtils.createByteBuffer(resultImageWidth * resultImageHeight * (format.getBitsPerPixel() >> 3)));
|
||||
Image resultImage = new Image(format, resultImageWidth, resultImageHeight, BufferUtils.createByteBuffer(resultImageWidth * resultImageHeight * (format.getBitsPerPixel() >> 3)), ColorSpace.Linear);
|
||||
resultTexture = new Texture2D(resultImage);
|
||||
for (Entry<TriangleTextureElement, Integer[]> entry : imageLayoutData.entrySet()) {
|
||||
if (!duplicatedFaceIndexes.contains(entry.getKey().faceIndex)) {
|
||||
@ -420,7 +421,7 @@ import com.jme3.util.BufferUtils;
|
||||
data.put(pixel.getA8());
|
||||
}
|
||||
}
|
||||
image = new Image(Format.RGBA8, width, height, data);
|
||||
image = new Image(Format.RGBA8, width, height, data, ColorSpace.Linear);
|
||||
|
||||
// modify the UV values so that they fit the new image
|
||||
float heightUV = maxUVY - minUVY;
|
||||
@ -481,7 +482,7 @@ import com.jme3.util.BufferUtils;
|
||||
imageHeight = 1;
|
||||
}
|
||||
ByteBuffer data = BufferUtils.createByteBuffer(imageWidth * imageHeight * (imageFormat.getBitsPerPixel() >> 3));
|
||||
image = new Image(texture.getImage().getFormat(), imageWidth, imageHeight, data);
|
||||
image = new Image(texture.getImage().getFormat(), imageWidth, imageHeight, data, ColorSpace.Linear);
|
||||
|
||||
// computing the pixels
|
||||
PixelInputOutput pixelWriter = PixelIOFactory.getPixelIO(imageFormat);
|
||||
@ -529,8 +530,8 @@ import com.jme3.util.BufferUtils;
|
||||
public void computeFinalUVCoordinates(int totalImageWidth, int totalImageHeight, int xPos, int yPos, Vector2f[] result) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
result[i] = new Vector2f();
|
||||
result[i].x = xPos / (float) totalImageWidth + this.uv[i].x * (this.image.getWidth() / (float) totalImageWidth);
|
||||
result[i].y = yPos / (float) totalImageHeight + this.uv[i].y * (this.image.getHeight() / (float) totalImageHeight);
|
||||
result[i].x = xPos / (float) totalImageWidth + uv[i].x * (image.getWidth() / (float) totalImageWidth);
|
||||
result[i].y = yPos / (float) totalImageHeight + uv[i].y * (image.getHeight() / (float) totalImageHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -623,9 +624,9 @@ import com.jme3.util.BufferUtils;
|
||||
* a position in 3D space
|
||||
*/
|
||||
public RectangleEnvelope(Vector3f pointPosition) {
|
||||
this.min = pointPosition;
|
||||
this.h = this.w = Vector3f.ZERO;
|
||||
this.width = this.height = 1;
|
||||
min = pointPosition;
|
||||
h = w = Vector3f.ZERO;
|
||||
width = height = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -642,8 +643,8 @@ import com.jme3.util.BufferUtils;
|
||||
this.min = min;
|
||||
this.h = h;
|
||||
this.w = w;
|
||||
this.width = w.length();
|
||||
this.height = h.length();
|
||||
width = w.length();
|
||||
height = h.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,10 +1,12 @@
|
||||
package com.jme3.scene.plugins.blender.textures.blending;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import jme3tools.converters.MipMapGenerator;
|
||||
|
||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||
import com.jme3.texture.Image;
|
||||
import java.util.logging.Logger;
|
||||
import jme3tools.converters.MipMapGenerator;
|
||||
|
||||
/**
|
||||
* An abstract class that contains the basic methods used by the classes that
|
||||
@ -103,12 +105,12 @@ import jme3tools.converters.MipMapGenerator;
|
||||
|
||||
public void copyBlendingData(TextureBlender textureBlender) {
|
||||
if (textureBlender instanceof AbstractTextureBlender) {
|
||||
this.flag = ((AbstractTextureBlender) textureBlender).flag;
|
||||
this.negateTexture = ((AbstractTextureBlender) textureBlender).negateTexture;
|
||||
this.blendType = ((AbstractTextureBlender) textureBlender).blendType;
|
||||
this.materialColor = ((AbstractTextureBlender) textureBlender).materialColor.clone();
|
||||
this.color = ((AbstractTextureBlender) textureBlender).color.clone();
|
||||
this.blendFactor = ((AbstractTextureBlender) textureBlender).blendFactor;
|
||||
flag = ((AbstractTextureBlender) textureBlender).flag;
|
||||
negateTexture = ((AbstractTextureBlender) textureBlender).negateTexture;
|
||||
blendType = ((AbstractTextureBlender) textureBlender).blendType;
|
||||
materialColor = ((AbstractTextureBlender) textureBlender).materialColor.clone();
|
||||
color = ((AbstractTextureBlender) textureBlender).color.clone();
|
||||
blendFactor = ((AbstractTextureBlender) textureBlender).blendFactor;
|
||||
} else {
|
||||
LOGGER.warning("Cannot copy blending data from other types than " + this.getClass());
|
||||
}
|
||||
|
@ -38,7 +38,9 @@ import com.jme3.scene.plugins.blender.textures.io.PixelIOFactory;
|
||||
import com.jme3.scene.plugins.blender.textures.io.PixelInputOutput;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.Image.Format;
|
||||
import com.jme3.texture.image.ColorSpace;
|
||||
import com.jme3.util.BufferUtils;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -141,7 +143,7 @@ public class TextureBlenderAWT extends AbstractTextureBlender {
|
||||
dataArray.add(newData);
|
||||
}
|
||||
|
||||
Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray) : new Image(Format.RGBA8, width, height, dataArray.get(0));
|
||||
Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray, ColorSpace.Linear) : new Image(Format.RGBA8, width, height, dataArray.get(0), ColorSpace.Linear);
|
||||
if (image.getMipMapSizes() != null) {
|
||||
result.setMipMapSizes(image.getMipMapSizes().clone());
|
||||
}
|
||||
|
@ -6,9 +6,12 @@ import com.jme3.scene.plugins.blender.textures.io.PixelIOFactory;
|
||||
import com.jme3.scene.plugins.blender.textures.io.PixelInputOutput;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.Image.Format;
|
||||
import com.jme3.texture.image.ColorSpace;
|
||||
import com.jme3.util.BufferUtils;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import jme3tools.converters.RGB565;
|
||||
|
||||
/**
|
||||
@ -119,7 +122,7 @@ public class TextureBlenderDDS extends TextureBlenderAWT {
|
||||
dataArray.add(newData);
|
||||
}
|
||||
|
||||
Image result = dataArray.size() > 1 ? new Image(format, width, height, depth, dataArray) : new Image(format, width, height, dataArray.get(0));
|
||||
Image result = dataArray.size() > 1 ? new Image(format, width, height, depth, dataArray, ColorSpace.Linear) : new Image(format, width, height, dataArray.get(0), ColorSpace.Linear);
|
||||
if (image.getMipMapSizes() != null) {
|
||||
result.setMipMapSizes(image.getMipMapSizes().clone());
|
||||
}
|
||||
|
@ -31,13 +31,13 @@
|
||||
*/
|
||||
package com.jme3.scene.plugins.blender.textures.blending;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.Image.Format;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This class creates the texture blending class depending on the texture type.
|
||||
*
|
||||
@ -66,7 +66,6 @@ public class TextureBlenderFactory {
|
||||
* the texture format
|
||||
* @return texture blending class
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static TextureBlender createTextureBlender(Format format, int flag, boolean negate, int blendType, float[] materialColor, float[] color, float colfac) {
|
||||
switch (format) {
|
||||
case Luminance8:
|
||||
|
@ -7,7 +7,9 @@ import com.jme3.scene.plugins.blender.textures.io.PixelIOFactory;
|
||||
import com.jme3.scene.plugins.blender.textures.io.PixelInputOutput;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.Image.Format;
|
||||
import com.jme3.texture.image.ColorSpace;
|
||||
import com.jme3.util.BufferUtils;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
@ -93,7 +95,7 @@ public class TextureBlenderLuminance extends AbstractTextureBlender {
|
||||
dataArray.add(newData);
|
||||
}
|
||||
|
||||
Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray) : new Image(Format.RGBA8, width, height, dataArray.get(0));
|
||||
Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray, ColorSpace.Linear) : new Image(Format.RGBA8, width, height, dataArray.get(0), ColorSpace.Linear);
|
||||
if (image.getMipMapSizes() != null) {
|
||||
result.setMipMapSizes(image.getMipMapSizes().clone());
|
||||
}
|
||||
|
@ -17,12 +17,18 @@ import jme3tools.converters.RGB565;
|
||||
case RGBA8:
|
||||
pixel.fromARGB8(data.get(index + 3), data.get(index), data.get(index + 1), data.get(index + 2));
|
||||
break;
|
||||
case ARGB8:
|
||||
pixel.fromARGB8(data.get(index), data.get(index + 1), data.get(index + 2), data.get(index + 3));
|
||||
break;
|
||||
case ABGR8:
|
||||
pixel.fromARGB8(data.get(index), data.get(index + 3), data.get(index + 2), data.get(index + 1));
|
||||
break;
|
||||
case BGR8:
|
||||
pixel.fromARGB8((byte) 0xFF, data.get(index + 2), data.get(index + 1), data.get(index));
|
||||
break;
|
||||
case BGRA8:
|
||||
pixel.fromARGB8(data.get(index + 3), data.get(index + 2), data.get(index + 1), data.get(index));
|
||||
break;
|
||||
case RGB8:
|
||||
pixel.fromARGB8((byte) 0xFF, data.get(index), data.get(index + 1), data.get(index + 2));
|
||||
break;
|
||||
@ -72,6 +78,12 @@ import jme3tools.converters.RGB565;
|
||||
data.put(index + 2, pixel.getB8());
|
||||
data.put(index + 3, pixel.getA8());
|
||||
break;
|
||||
case ARGB8:
|
||||
data.put(index, pixel.getA8());
|
||||
data.put(index + 1, pixel.getR8());
|
||||
data.put(index + 2, pixel.getG8());
|
||||
data.put(index + 3, pixel.getB8());
|
||||
break;
|
||||
case ABGR8:
|
||||
data.put(index, pixel.getA8());
|
||||
data.put(index + 1, pixel.getB8());
|
||||
@ -83,6 +95,12 @@ import jme3tools.converters.RGB565;
|
||||
data.put(index + 1, pixel.getG8());
|
||||
data.put(index + 2, pixel.getR8());
|
||||
break;
|
||||
case BGRA8:
|
||||
data.put(index, pixel.getB8());
|
||||
data.put(index + 1, pixel.getG8());
|
||||
data.put(index + 2, pixel.getR8());
|
||||
data.put(index + 3, pixel.getA8());
|
||||
break;
|
||||
case RGB8:
|
||||
data.put(index, pixel.getR8());
|
||||
data.put(index + 1, pixel.getG8());
|
||||
|
@ -26,7 +26,9 @@ public class PixelIOFactory {
|
||||
case ABGR8:
|
||||
case RGBA8:
|
||||
case BGR8:
|
||||
case BGRA8:
|
||||
case RGB8:
|
||||
case ARGB8:
|
||||
case RGB111110F:
|
||||
case RGB16F:
|
||||
case RGB16F_to_RGB111110F:
|
||||
|
@ -175,7 +175,7 @@ binaries.withType(SharedLibraryBinary) { binary ->
|
||||
// Add depend on build
|
||||
jar.dependsOn builderTask
|
||||
// Add output to libs folder
|
||||
task "copyBinaryToLibs${targetPlatform}"(type: Copy) {
|
||||
task "copyBinaryToLibs${targetPlatform}"(type: Copy, dependsOn: builderTask) {
|
||||
from builderTask.outputFile
|
||||
into "libs/native/${targetPlatform.operatingSystem.name}/${targetPlatform.architecture.name}"
|
||||
}
|
||||
|
@ -468,6 +468,67 @@ extern "C" {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_sweepTest_1native
|
||||
(JNIEnv * env, jobject object, jlong shapeId, jobject from, jobject to, jlong spaceId, jobject resultlist, jfloat allowedCcdPenetration) {
|
||||
|
||||
jmePhysicsSpace* space = reinterpret_cast<jmePhysicsSpace*> (spaceId);
|
||||
if (space == NULL) {
|
||||
jclass newExc = env->FindClass("java/lang/NullPointerException");
|
||||
env->ThrowNew(newExc, "The physics space does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
btCollisionShape* shape = reinterpret_cast<btCollisionShape*> (shapeId);
|
||||
if (shape == NULL) {
|
||||
jclass newExc = env->FindClass("java/lang/NullPointerException");
|
||||
env->ThrowNew(newExc, "The shape does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
struct AllConvexResultCallback : public btCollisionWorld::ConvexResultCallback {
|
||||
|
||||
AllConvexResultCallback(const btTransform& convexFromWorld, const btTransform & convexToWorld) : m_convexFromWorld(convexFromWorld), m_convexToWorld(convexToWorld) {
|
||||
}
|
||||
jobject resultlist;
|
||||
JNIEnv* env;
|
||||
btTransform m_convexFromWorld; //used to calculate hitPointWorld from hitFraction
|
||||
btTransform m_convexToWorld;
|
||||
|
||||
btVector3 m_hitNormalWorld;
|
||||
btVector3 m_hitPointWorld;
|
||||
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace) {
|
||||
if (normalInWorldSpace) {
|
||||
m_hitNormalWorld = convexResult.m_hitNormalLocal;
|
||||
}
|
||||
else {
|
||||
m_hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis() * convexResult.m_hitNormalLocal;
|
||||
}
|
||||
m_hitPointWorld.setInterpolate3(m_convexFromWorld.getBasis() * m_convexFromWorld.getOrigin(), m_convexToWorld.getBasis() * m_convexToWorld.getOrigin(), convexResult.m_hitFraction);
|
||||
|
||||
jmeBulletUtil::addSweepResult(env, resultlist, &m_hitNormalWorld, &m_hitPointWorld, convexResult.m_hitFraction, convexResult.m_hitCollisionObject);
|
||||
|
||||
return 1.f;
|
||||
}
|
||||
};
|
||||
|
||||
btTransform native_to = btTransform();
|
||||
jmeBulletUtil::convert(env, to, &native_to);
|
||||
|
||||
btTransform native_from = btTransform();
|
||||
jmeBulletUtil::convert(env, from, &native_from);
|
||||
|
||||
btScalar native_allowed_ccd_penetration = btScalar(allowedCcdPenetration);
|
||||
|
||||
AllConvexResultCallback resultCallback(native_from, native_to);
|
||||
resultCallback.env = env;
|
||||
resultCallback.resultlist = resultlist;
|
||||
space->getDynamicsWorld()->convexSweepTest((btConvexShape *) shape, native_from, native_to, resultCallback, native_allowed_ccd_penetration);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -165,6 +165,15 @@ JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_initNativePhysics
|
||||
JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_finalizeNative
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
|
||||
/*
|
||||
* Class: com_jme3_bullet_PhysicsSpace
|
||||
* Method : sweepTest_native
|
||||
* Signature: (J;L;Lcom/jme3/math/Transform;Lcom/jme3/math/Transform;L;JLjava/util/List;F)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_sweepTest_1native
|
||||
(JNIEnv *, jobject, jlong, jobject, jobject, jlong, jobject, jfloat);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -59,6 +59,38 @@ void jmeBulletUtil::convert(JNIEnv* env, jobject in, btVector3* out) {
|
||||
out->setZ(z);
|
||||
}
|
||||
|
||||
void jmeBulletUtil::convert(JNIEnv* env, jobject in, btQuaternion* out) {
|
||||
if (in == NULL || out == NULL) {
|
||||
jmeClasses::throwNPE(env);
|
||||
}
|
||||
float x = env->GetFloatField(in, jmeClasses::Quaternion_x);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
float y = env->GetFloatField(in, jmeClasses::Quaternion_y); //env->CallFloatMethod(in, jmeClasses::Vector3f_getY);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
float z = env->GetFloatField(in, jmeClasses::Quaternion_z); //env->CallFloatMethod(in, jmeClasses::Vector3f_getZ);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
float w = env->GetFloatField(in, jmeClasses::Quaternion_w); //env->CallFloatMethod(in, jmeClasses::Vector3f_getZ);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
out->setX(x);
|
||||
out->setY(y);
|
||||
out->setZ(z);
|
||||
out->setW(w);
|
||||
}
|
||||
|
||||
|
||||
void jmeBulletUtil::convert(JNIEnv* env, const btVector3* in, jobject out) {
|
||||
if (in == NULL || out == NULL) {
|
||||
jmeClasses::throwNPE(env);
|
||||
@ -325,3 +357,61 @@ void jmeBulletUtil::addResult(JNIEnv* env, jobject resultlist, btVector3* hitnor
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void jmeBulletUtil::addSweepResult(JNIEnv* env, jobject resultlist, btVector3* hitnormal, btVector3* m_hitPointWorld, btScalar m_hitFraction, const btCollisionObject* hitobject) {
|
||||
|
||||
jobject singleresult = env->AllocObject(jmeClasses::PhysicsSweep_Class);
|
||||
jobject hitnormalvec = env->AllocObject(jmeClasses::Vector3f);
|
||||
|
||||
convert(env, hitnormal, hitnormalvec);
|
||||
jmeUserPointer *up1 = (jmeUserPointer*)hitobject->getUserPointer();
|
||||
|
||||
env->SetObjectField(singleresult, jmeClasses::PhysicsSweep_normalInWorldSpace, hitnormalvec);
|
||||
env->SetFloatField(singleresult, jmeClasses::PhysicsSweep_hitfraction, m_hitFraction);
|
||||
|
||||
env->SetObjectField(singleresult, jmeClasses::PhysicsSweep_collisionObject, up1->javaCollisionObject);
|
||||
env->CallVoidMethod(resultlist, jmeClasses::PhysicsSweep_addmethod, singleresult);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void jmeBulletUtil::convert(JNIEnv* env, jobject in, btTransform* out) {
|
||||
if (in == NULL || out == NULL) {
|
||||
jmeClasses::throwNPE(env);
|
||||
}
|
||||
|
||||
jobject translation_vec = env->CallObjectMethod(in, jmeClasses::Transform_translation);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
jobject rot_quat = env->CallObjectMethod(in, jmeClasses::Transform_rotation);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
//Scale currently not supported by bullet
|
||||
//@TBD: Create an assertion somewhere to avoid scale values
|
||||
jobject scale_vec = env->GetObjectField(in, jmeClasses::Transform_scale);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
*/
|
||||
btVector3 native_translation_vec = btVector3();
|
||||
//btVector3 native_scale_vec = btVector3();
|
||||
btQuaternion native_rot_quat = btQuaternion();
|
||||
|
||||
convert(env, translation_vec, &native_translation_vec);
|
||||
//convert(env, scale_vec, native_scale_vec);
|
||||
convert(env, rot_quat, &native_rot_quat);
|
||||
|
||||
out->setRotation(native_rot_quat);
|
||||
out->setOrigin(native_translation_vec);
|
||||
}
|
||||
|
@ -42,10 +42,13 @@ public:
|
||||
static void convert(JNIEnv* env, jobject in, btVector3* out);
|
||||
static void convert(JNIEnv* env, const btVector3* in, jobject out);
|
||||
static void convert(JNIEnv* env, jobject in, btMatrix3x3* out);
|
||||
static void convert(JNIEnv* env, jobject in, btQuaternion* out);
|
||||
static void convert(JNIEnv* env, const btMatrix3x3* in, jobject out);
|
||||
static void convertQuat(JNIEnv* env, jobject in, btMatrix3x3* out);
|
||||
static void convertQuat(JNIEnv* env, const btMatrix3x3* in, jobject out);
|
||||
static void convert(JNIEnv* env, jobject in, btTransform* out);
|
||||
static void addResult(JNIEnv* env, jobject resultlist, btVector3* hitnormal, btVector3* m_hitPointWorld,const btScalar m_hitFraction,const btCollisionObject* hitobject);
|
||||
static void addSweepResult(JNIEnv* env, jobject resultlist, btVector3* hitnormal, btVector3* m_hitPointWorld, const btScalar m_hitFraction, const btCollisionObject* hitobject);
|
||||
private:
|
||||
jmeBulletUtil(){};
|
||||
~jmeBulletUtil(){};
|
||||
|
@ -91,6 +91,21 @@ jfieldID jmeClasses::PhysicsRay_collisionObject;
|
||||
jclass jmeClasses::PhysicsRay_listresult;
|
||||
jmethodID jmeClasses::PhysicsRay_addmethod;
|
||||
|
||||
jclass jmeClasses::PhysicsSweep_Class;
|
||||
jmethodID jmeClasses::PhysicsSweep_newSingleResult;
|
||||
|
||||
jfieldID jmeClasses::PhysicsSweep_normalInWorldSpace;
|
||||
jfieldID jmeClasses::PhysicsSweep_hitfraction;
|
||||
jfieldID jmeClasses::PhysicsSweep_collisionObject;
|
||||
|
||||
jclass jmeClasses::PhysicsSweep_listresult;
|
||||
jmethodID jmeClasses::PhysicsSweep_addmethod;
|
||||
|
||||
|
||||
jclass jmeClasses::Transform;
|
||||
jmethodID jmeClasses::Transform_rotation;
|
||||
jmethodID jmeClasses::Transform_translation;
|
||||
|
||||
//private fields
|
||||
//JNIEnv* jmeClasses::env;
|
||||
JavaVM* jmeClasses::vm;
|
||||
@ -240,6 +255,70 @@ void jmeClasses::initJavaClasses(JNIEnv* env) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicsSweep_Class = (jclass)env->NewGlobalRef(env->FindClass("com/jme3/bullet/collision/PhysicsSweepTestResult"));
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicsSweep_newSingleResult = env->GetMethodID(PhysicsSweep_Class, "<init>", "()V");
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicsSweep_normalInWorldSpace = env->GetFieldID(PhysicsSweep_Class, "hitNormalLocal", "Lcom/jme3/math/Vector3f;");
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
PhysicsSweep_hitfraction = env->GetFieldID(PhysicsSweep_Class, "hitFraction", "F");
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
PhysicsSweep_collisionObject = env->GetFieldID(PhysicsSweep_Class, "collisionObject", "Lcom/jme3/bullet/collision/PhysicsCollisionObject;");
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicsSweep_listresult = env->FindClass("java/util/List");
|
||||
PhysicsSweep_listresult = (jclass)env->NewGlobalRef(PhysicsSweep_listresult);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicsSweep_addmethod = env->GetMethodID(PhysicsSweep_listresult, "add", "(Ljava/lang/Object;)Z");
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
Transform = (jclass)env->NewGlobalRef(env->FindClass("com/jme3/math/Transform"));
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
Transform_rotation = env->GetMethodID(Transform, "getRotation", "()Lcom/jme3/math/Quaternion;");
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
Transform_translation = env->GetMethodID(Transform, "getTranslation", "()Lcom/jme3/math/Vector3f;");
|
||||
if (env->ExceptionCheck()) {
|
||||
env->Throw(env->ExceptionOccurred());
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void jmeClasses::throwNPE(JNIEnv* env) {
|
||||
|
@ -89,6 +89,18 @@ public:
|
||||
static jclass PhysicsRay_listresult;
|
||||
static jmethodID PhysicsRay_addmethod;
|
||||
|
||||
static jclass PhysicsSweep_Class;
|
||||
static jmethodID PhysicsSweep_newSingleResult;
|
||||
static jfieldID PhysicsSweep_normalInWorldSpace;
|
||||
static jfieldID PhysicsSweep_hitfraction;
|
||||
static jfieldID PhysicsSweep_collisionObject;
|
||||
static jclass PhysicsSweep_listresult;
|
||||
static jmethodID PhysicsSweep_addmethod;
|
||||
|
||||
static jclass Transform;
|
||||
static jmethodID Transform_rotation;
|
||||
static jmethodID Transform_translation;
|
||||
|
||||
static jclass DebugMeshCallback;
|
||||
static jmethodID DebugMeshCallback_addVector;
|
||||
|
||||
|
@ -820,6 +820,10 @@ public class PhysicsSpace {
|
||||
// return lrr.hitFraction;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Performs a sweep collision test and returns the results as a list of
|
||||
* PhysicsSweepTestResults<br/> You have to use different Transforms for
|
||||
@ -828,48 +832,47 @@ public class PhysicsSpace {
|
||||
* center.
|
||||
*/
|
||||
public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end) {
|
||||
List<PhysicsSweepTestResult> results = new LinkedList<PhysicsSweepTestResult>();
|
||||
// if (!(shape.getCShape() instanceof ConvexShape)) {
|
||||
// logger.log(Level.WARNING, "Trying to sweep test with incompatible mesh shape!");
|
||||
// return results;
|
||||
// }
|
||||
// dynamicsWorld.convexSweepTest((ConvexShape) shape.getCShape(), Converter.convert(start, sweepTrans1), Converter.convert(end, sweepTrans2), new InternalSweepListener(results));
|
||||
return results;
|
||||
|
||||
List results = new LinkedList();
|
||||
sweepTest(shape, start, end , results);
|
||||
return (List<PhysicsSweepTestResult>) results;
|
||||
}
|
||||
|
||||
public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end, List<PhysicsSweepTestResult> results) {
|
||||
return sweepTest(shape, start, end, results, 0.0f);
|
||||
}
|
||||
|
||||
public native void sweepTest_native(long shape, Transform from, Transform to, long physicsSpaceId, List<PhysicsSweepTestResult> results, float allowedCcdPenetration);
|
||||
/**
|
||||
* Performs a sweep collision test and returns the results as a list of
|
||||
* PhysicsSweepTestResults<br/> You have to use different Transforms for
|
||||
* start and end (at least distance > 0.4f). SweepTest will not see a
|
||||
* start and end (at least distance > allowedCcdPenetration). SweepTest will not see a
|
||||
* collision if it starts INSIDE an object and is moving AWAY from its
|
||||
* center.
|
||||
*/
|
||||
public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end, List<PhysicsSweepTestResult> results) {
|
||||
public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end, List<PhysicsSweepTestResult> results, float allowedCcdPenetration ) {
|
||||
results.clear();
|
||||
// if (!(shape.getCShape() instanceof ConvexShape)) {
|
||||
// logger.log(Level.WARNING, "Trying to sweep test with incompatible mesh shape!");
|
||||
// return results;
|
||||
// }
|
||||
// dynamicsWorld.convexSweepTest((ConvexShape) shape.getCShape(), Converter.convert(start, sweepTrans1), Converter.convert(end, sweepTrans2), new InternalSweepListener(results));
|
||||
sweepTest_native(shape.getObjectId(), start, end, physicsSpaceId, results, allowedCcdPenetration);
|
||||
return results;
|
||||
}
|
||||
|
||||
// private class InternalSweepListener extends CollisionWorld.ConvexResultCallback {
|
||||
//
|
||||
// private List<PhysicsSweepTestResult> results;
|
||||
//
|
||||
// public InternalSweepListener(List<PhysicsSweepTestResult> results) {
|
||||
// this.results = results;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float addSingleResult(LocalConvexResult lcr, boolean bln) {
|
||||
// PhysicsCollisionObject obj = (PhysicsCollisionObject) lcr.hitCollisionObject.getUserPointer();
|
||||
// results.add(new PhysicsSweepTestResult(obj, Converter.convert(lcr.hitNormalLocal), lcr.hitFraction, bln));
|
||||
// return lcr.hitFraction;
|
||||
// }
|
||||
// }
|
||||
/* private class InternalSweepListener extends CollisionWorld.ConvexResultCallback {
|
||||
|
||||
private List<PhysicsSweepTestResult> results;
|
||||
|
||||
public InternalSweepListener(List<PhysicsSweepTestResult> results) {
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float addSingleResult(LocalConvexResult lcr, boolean bln) {
|
||||
PhysicsCollisionObject obj = (PhysicsCollisionObject) lcr.hitCollisionObject.getUserPointer();
|
||||
results.add(new PhysicsSweepTestResult(obj, Converter.convert(lcr.hitNormalLocal), lcr.hitFraction, bln));
|
||||
return lcr.hitFraction;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* destroys the current PhysicsSpace so that a new one can be created
|
||||
*/
|
||||
|
@ -26,14 +26,29 @@ import org.ajoberstar.grgit.*
|
||||
|
||||
task updateVersion << {
|
||||
|
||||
def grgit = Grgit.open(project.file('.').parent)
|
||||
|
||||
def jmeGitHash = grgit.head().id
|
||||
def jmeShortGitHash = grgit.head().abbreviatedId
|
||||
def jmeBuildDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date())
|
||||
def jmeBranchName = grgit.branch.current.name
|
||||
|
||||
def verfile = file('src/main/java/com/jme3/system/JmeVersion.java')
|
||||
def jmeGitHash
|
||||
def jmeShortGitHash
|
||||
def jmeBuildDate
|
||||
def jmeBranchName
|
||||
|
||||
try {
|
||||
def grgit = Grgit.open(project.file('.').parent)
|
||||
jmeGitHash = grgit.head().id
|
||||
jmeShortGitHash = grgit.head().abbreviatedId
|
||||
jmeBuildDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date())
|
||||
jmeBranchName = grgit.branch.current.name
|
||||
} catch (ex) {
|
||||
// Failed to get repo info
|
||||
logger.warn("Failed to get repository info: " + ex.message + ". " + \
|
||||
"Only partial build info will be generated.")
|
||||
|
||||
jmeGitHash = ""
|
||||
jmeShortGitHash = ""
|
||||
jmeBuildDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date())
|
||||
jmeBranchName = "unknown"
|
||||
}
|
||||
|
||||
verfile.text = "\npackage com.jme3.system;\n\n" +
|
||||
"/**\n * THIS IS AN AUTO-GENERATED FILE..\n * DO NOT MODIFY!\n */\n" +
|
||||
"public class JmeVersion {\n" +
|
||||
|
@ -312,7 +312,6 @@ public final class AnimChannel {
|
||||
}
|
||||
}
|
||||
animation = null;
|
||||
// System.out.println("Setting notified false");
|
||||
notified = false;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ public final class AssetConfig {
|
||||
public static void loadText(AssetManager assetManager, URL configUrl) throws IOException{
|
||||
InputStream in = configUrl.openStream();
|
||||
try {
|
||||
Scanner scan = new Scanner(in);
|
||||
Scanner scan = new Scanner(in, "UTF-8");
|
||||
scan.useLocale(Locale.US); // Fix commas / periods ??
|
||||
while (scan.hasNext()){
|
||||
String cmd = scan.next();
|
||||
|
@ -312,13 +312,12 @@ public class DesktopAssetManager implements AssetManager {
|
||||
protected <T> T registerAndCloneSmartAsset(AssetKey<T> key, T obj, AssetProcessor proc, AssetCache cache) {
|
||||
// object obj is the original asset
|
||||
// create an instance for user
|
||||
T clone = (T) obj;
|
||||
if (proc == null) {
|
||||
throw new IllegalStateException("Asset implements "
|
||||
+ "CloneableSmartAsset but doesn't "
|
||||
+ "have processor to handle cloning");
|
||||
} else {
|
||||
clone = (T) proc.createClone(obj);
|
||||
T clone = (T) proc.createClone(obj);
|
||||
if (cache != null && clone != obj) {
|
||||
cache.registerAssetClone(key, clone);
|
||||
} else {
|
||||
@ -326,8 +325,8 @@ public class DesktopAssetManager implements AssetManager {
|
||||
+ "CloneableSmartAsset but doesn't have cache or "
|
||||
+ "was not cloned");
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,7 +47,7 @@ import java.util.logging.Logger;
|
||||
* This is done by keeping an instance of each asset loader and asset
|
||||
* locator object in a thread local.
|
||||
*/
|
||||
public class ImplHandler {
|
||||
final class ImplHandler {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ImplHandler.class.getName());
|
||||
|
||||
@ -75,7 +75,7 @@ public class ImplHandler {
|
||||
this.assetManager = assetManager;
|
||||
}
|
||||
|
||||
protected class ImplThreadLocal<T> extends ThreadLocal {
|
||||
protected static class ImplThreadLocal<T> extends ThreadLocal {
|
||||
|
||||
private final Class<T> type;
|
||||
private final String path;
|
||||
@ -83,7 +83,7 @@ public class ImplHandler {
|
||||
|
||||
public ImplThreadLocal(Class<T> type, String[] extensions){
|
||||
this.type = type;
|
||||
this.extensions = extensions;
|
||||
this.extensions = extensions.clone();
|
||||
this.path = null;
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,6 @@ import java.util.List;
|
||||
* Used for loading {@link ShaderNodeDefinition shader nodes definition}
|
||||
*
|
||||
* Tells if the defintion has to be loaded with or without its documentation
|
||||
*
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class ShaderNodeDefinitionKey extends AssetKey<List<ShaderNodeDefinition>> {
|
||||
|
||||
|
@ -155,11 +155,7 @@ public class WeakRefCloneAssetCache implements AssetCache {
|
||||
}
|
||||
|
||||
public <T> T getFromCache(AssetKey<T> key) {
|
||||
AssetRef smartInfo;
|
||||
synchronized (smartCache){
|
||||
smartInfo = smartCache.get(key);
|
||||
}
|
||||
|
||||
AssetRef smartInfo = smartCache.get(key);
|
||||
if (smartInfo == null) {
|
||||
return null;
|
||||
} else {
|
||||
|
@ -51,6 +51,9 @@ import static com.jme3.audio.openal.EFX.*;
|
||||
public class ALAudioRenderer implements AudioRenderer, Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ALAudioRenderer.class.getName());
|
||||
|
||||
private static final String THREAD_NAME = "jME3 Audio Decoder";
|
||||
|
||||
private final NativeObjectManager objManager = new NativeObjectManager();
|
||||
// When multiplied by STREAMING_BUFFER_COUNT, will equal 44100 * 2 * 2
|
||||
// which is exactly 1 second of audio.
|
||||
@ -75,7 +78,7 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
|
||||
|
||||
// Fill streaming sources every 50 ms
|
||||
private static final float UPDATE_RATE = 0.05f;
|
||||
private final Thread decoderThread = new Thread(this, "jME3 Audio Decoding Thread");
|
||||
private final Thread decoderThread = new Thread(this, THREAD_NAME);
|
||||
private final Object threadLock = new Object();
|
||||
|
||||
private final AL al;
|
||||
|
@ -640,8 +640,7 @@ public class BoundingSphere extends BoundingVolume {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
return new BoundingSphere(radius,
|
||||
(center != null ? (Vector3f) center.clone() : null));
|
||||
return new BoundingSphere(radius, center.clone());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,6 +109,11 @@ public class CollisionResult implements Comparable<CollisionResult> {
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Float.floatToIntBits(distance);
|
||||
}
|
||||
|
||||
public Vector3f getContactPoint() {
|
||||
return contactPoint;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ import java.io.IOException;
|
||||
* the light intensity slowly decrease between the inner cone and the outer cone.
|
||||
* @author Nehon
|
||||
*/
|
||||
public class SpotLight extends Light implements Savable {
|
||||
public class SpotLight extends Light {
|
||||
|
||||
protected Vector3f position = new Vector3f();
|
||||
protected Vector3f direction = new Vector3f(0,-1,0);
|
||||
|
@ -103,11 +103,10 @@ public class TechniqueDef implements Savable {
|
||||
private EnumSet<Caps> requiredCaps = EnumSet.noneOf(Caps.class);
|
||||
private String name;
|
||||
|
||||
private EnumMap<Shader.ShaderType,String> shaderLanguage;
|
||||
private EnumMap<Shader.ShaderType,String> shaderName;
|
||||
private EnumMap<Shader.ShaderType,String> shaderLanguages;
|
||||
private EnumMap<Shader.ShaderType,String> shaderNames;
|
||||
|
||||
private DefineList presetDefines;
|
||||
private boolean usesShaders;
|
||||
private boolean usesNodes = false;
|
||||
private List<ShaderNode> shaderNodes;
|
||||
private ShaderGenerationInfo shaderGenerationInfo;
|
||||
@ -140,8 +139,8 @@ public class TechniqueDef implements Savable {
|
||||
* Serialization only. Do not use.
|
||||
*/
|
||||
public TechniqueDef(){
|
||||
shaderLanguage=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
|
||||
shaderName=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
|
||||
shaderLanguages=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
|
||||
shaderNames=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,7 +225,7 @@ public class TechniqueDef implements Savable {
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isUsingShaders(){
|
||||
return usesShaders;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,36 +257,44 @@ public class TechniqueDef implements Savable {
|
||||
* @param fragLanguage The fragment shader language
|
||||
*/
|
||||
public void setShaderFile(String vertexShader, String fragmentShader, String vertLanguage, String fragLanguage) {
|
||||
this.shaderLanguage.put(Shader.ShaderType.Vertex, vertLanguage);
|
||||
this.shaderName.put(Shader.ShaderType.Vertex, vertexShader);
|
||||
this.shaderLanguage.put(Shader.ShaderType.Fragment, fragLanguage);
|
||||
this.shaderName.put(Shader.ShaderType.Fragment, fragmentShader);
|
||||
this.shaderLanguages.put(Shader.ShaderType.Vertex, vertLanguage);
|
||||
this.shaderNames.put(Shader.ShaderType.Vertex, vertexShader);
|
||||
this.shaderLanguages.put(Shader.ShaderType.Fragment, fragLanguage);
|
||||
this.shaderNames.put(Shader.ShaderType.Fragment, fragmentShader);
|
||||
|
||||
requiredCaps.clear();
|
||||
Caps vertCap = Caps.valueOf(vertLanguage);
|
||||
requiredCaps.add(vertCap);
|
||||
Caps fragCap = Caps.valueOf(fragLanguage);
|
||||
requiredCaps.add(fragCap);
|
||||
|
||||
usesShaders = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the shaders that this technique definition will use.
|
||||
*
|
||||
* @param shaderName EnumMap containing all shader names for this stage
|
||||
* @param shaderLanguage EnumMap containing all shader languages for this stage
|
||||
* @param shaderNames EnumMap containing all shader names for this stage
|
||||
* @param shaderLanguages EnumMap containing all shader languages for this stage
|
||||
*/
|
||||
public void setShaderFile(EnumMap<Shader.ShaderType, String> shaderName, EnumMap<Shader.ShaderType, String> shaderLanguage) {
|
||||
for (Shader.ShaderType shaderType : shaderName.keySet()) {
|
||||
this.shaderLanguage.put(shaderType,shaderLanguage.get(shaderType));
|
||||
this.shaderName.put(shaderType,shaderName.get(shaderType));
|
||||
if(shaderType.equals(Shader.ShaderType.Geometry)){
|
||||
public void setShaderFile(EnumMap<Shader.ShaderType, String> shaderNames, EnumMap<Shader.ShaderType, String> shaderLanguages) {
|
||||
requiredCaps.clear();
|
||||
|
||||
for (Shader.ShaderType shaderType : shaderNames.keySet()) {
|
||||
String language = shaderLanguages.get(shaderType);
|
||||
String shaderFile = shaderNames.get(shaderType);
|
||||
|
||||
this.shaderLanguages.put(shaderType, language);
|
||||
this.shaderNames.put(shaderType, shaderFile);
|
||||
|
||||
Caps vertCap = Caps.valueOf(language);
|
||||
requiredCaps.add(vertCap);
|
||||
|
||||
if (shaderType.equals(Shader.ShaderType.Geometry)) {
|
||||
requiredCaps.add(Caps.GeometryShader);
|
||||
}else if(shaderType.equals(Shader.ShaderType.TessellationControl)){
|
||||
} else if (shaderType.equals(Shader.ShaderType.TessellationControl)) {
|
||||
requiredCaps.add(Caps.TesselationShader);
|
||||
}
|
||||
}
|
||||
usesShaders=true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -362,7 +369,7 @@ public class TechniqueDef implements Savable {
|
||||
* @return the name of the fragment shader to be used.
|
||||
*/
|
||||
public String getFragmentShaderName() {
|
||||
return shaderName.get(Shader.ShaderType.Fragment);
|
||||
return shaderNames.get(Shader.ShaderType.Fragment);
|
||||
}
|
||||
|
||||
|
||||
@ -373,42 +380,34 @@ public class TechniqueDef implements Savable {
|
||||
* @return the name of the vertex shader to be used.
|
||||
*/
|
||||
public String getVertexShaderName() {
|
||||
return shaderName.get(Shader.ShaderType.Vertex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getVertexShaderLanguage() } instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getShaderLanguage() {
|
||||
return shaderLanguage.get(Shader.ShaderType.Vertex);
|
||||
return shaderNames.get(Shader.ShaderType.Vertex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the language of the fragment shader used in this technique.
|
||||
*/
|
||||
public String getFragmentShaderLanguage() {
|
||||
return shaderLanguage.get(Shader.ShaderType.Fragment);
|
||||
return shaderLanguages.get(Shader.ShaderType.Fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the language of the vertex shader used in this technique.
|
||||
*/
|
||||
public String getVertexShaderLanguage() {
|
||||
return shaderLanguage.get(Shader.ShaderType.Vertex);
|
||||
return shaderLanguages.get(Shader.ShaderType.Vertex);
|
||||
}
|
||||
|
||||
/**Returns the language for each shader program
|
||||
* @param shaderType
|
||||
*/
|
||||
public String getShaderProgramLanguage(Shader.ShaderType shaderType){
|
||||
return shaderLanguage.get(shaderType);
|
||||
return shaderLanguages.get(shaderType);
|
||||
}
|
||||
/**Returns the name for each shader program
|
||||
* @param shaderType
|
||||
*/
|
||||
public String getShaderProgramName(Shader.ShaderType shaderType){
|
||||
return shaderName.get(shaderType);
|
||||
return shaderNames.get(shaderType);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -453,22 +452,21 @@ public class TechniqueDef implements Savable {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(name, "name", null);
|
||||
|
||||
oc.write(shaderName.get(Shader.ShaderType.Vertex), "vertName", null);
|
||||
oc.write(shaderName.get(Shader.ShaderType.Fragment), "fragName", null);
|
||||
oc.write(shaderName.get(Shader.ShaderType.Geometry), "geomName", null);
|
||||
oc.write(shaderName.get(Shader.ShaderType.TessellationControl), "tsctrlName", null);
|
||||
oc.write(shaderName.get(Shader.ShaderType.TessellationEvaluation), "tsevalName", null);
|
||||
oc.write(shaderLanguage.get(Shader.ShaderType.Vertex), "vertLanguage", null);
|
||||
oc.write(shaderLanguage.get(Shader.ShaderType.Fragment), "fragLanguage", null);
|
||||
oc.write(shaderLanguage.get(Shader.ShaderType.Geometry), "geomLanguage", null);
|
||||
oc.write(shaderLanguage.get(Shader.ShaderType.TessellationControl), "tsctrlLanguage", null);
|
||||
oc.write(shaderLanguage.get(Shader.ShaderType.TessellationEvaluation), "tsevalLanguage", null);
|
||||
oc.write(shaderNames.get(Shader.ShaderType.Vertex), "vertName", null);
|
||||
oc.write(shaderNames.get(Shader.ShaderType.Fragment), "fragName", null);
|
||||
oc.write(shaderNames.get(Shader.ShaderType.Geometry), "geomName", null);
|
||||
oc.write(shaderNames.get(Shader.ShaderType.TessellationControl), "tsctrlName", null);
|
||||
oc.write(shaderNames.get(Shader.ShaderType.TessellationEvaluation), "tsevalName", null);
|
||||
oc.write(shaderLanguages.get(Shader.ShaderType.Vertex), "vertLanguage", null);
|
||||
oc.write(shaderLanguages.get(Shader.ShaderType.Fragment), "fragLanguage", null);
|
||||
oc.write(shaderLanguages.get(Shader.ShaderType.Geometry), "geomLanguage", null);
|
||||
oc.write(shaderLanguages.get(Shader.ShaderType.TessellationControl), "tsctrlLanguage", null);
|
||||
oc.write(shaderLanguages.get(Shader.ShaderType.TessellationEvaluation), "tsevalLanguage", null);
|
||||
|
||||
oc.write(presetDefines, "presetDefines", null);
|
||||
oc.write(lightMode, "lightMode", LightMode.Disable);
|
||||
oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
|
||||
oc.write(renderState, "renderState", null);
|
||||
oc.write(usesShaders, "usesShaders", false);
|
||||
oc.write(usesNodes, "usesNodes", false);
|
||||
oc.writeSavableArrayList((ArrayList)shaderNodes,"shaderNodes", null);
|
||||
oc.write(shaderGenerationInfo, "shaderGenerationInfo", null);
|
||||
@ -482,28 +480,27 @@ public class TechniqueDef implements Savable {
|
||||
public void read(JmeImporter im) throws IOException{
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
name = ic.readString("name", null);
|
||||
shaderName.put(Shader.ShaderType.Vertex,ic.readString("vertName", null));
|
||||
shaderName.put(Shader.ShaderType.Fragment,ic.readString("fragName", null));
|
||||
shaderName.put(Shader.ShaderType.Geometry,ic.readString("geomName", null));
|
||||
shaderName.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlName", null));
|
||||
shaderName.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalName", null));
|
||||
shaderNames.put(Shader.ShaderType.Vertex,ic.readString("vertName", null));
|
||||
shaderNames.put(Shader.ShaderType.Fragment,ic.readString("fragName", null));
|
||||
shaderNames.put(Shader.ShaderType.Geometry,ic.readString("geomName", null));
|
||||
shaderNames.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlName", null));
|
||||
shaderNames.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalName", null));
|
||||
presetDefines = (DefineList) ic.readSavable("presetDefines", null);
|
||||
lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable);
|
||||
shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable);
|
||||
renderState = (RenderState) ic.readSavable("renderState", null);
|
||||
usesShaders = ic.readBoolean("usesShaders", false);
|
||||
|
||||
if (ic.getSavableVersion(TechniqueDef.class) == 0) {
|
||||
// Old version
|
||||
shaderLanguage.put(Shader.ShaderType.Vertex,ic.readString("shaderLang", null));
|
||||
shaderLanguage.put(Shader.ShaderType.Fragment,shaderLanguage.get(Shader.ShaderType.Vertex));
|
||||
shaderLanguages.put(Shader.ShaderType.Vertex,ic.readString("shaderLang", null));
|
||||
shaderLanguages.put(Shader.ShaderType.Fragment,shaderLanguages.get(Shader.ShaderType.Vertex));
|
||||
} else {
|
||||
// New version
|
||||
shaderLanguage.put(Shader.ShaderType.Vertex,ic.readString("vertLanguage", null));
|
||||
shaderLanguage.put(Shader.ShaderType.Fragment,ic.readString("fragLanguage", null));
|
||||
shaderLanguage.put(Shader.ShaderType.Geometry,ic.readString("geomLanguage", null));
|
||||
shaderLanguage.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlLanguage", null));
|
||||
shaderLanguage.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalLanguage", null));
|
||||
shaderLanguages.put(Shader.ShaderType.Vertex,ic.readString("vertLanguage", null));
|
||||
shaderLanguages.put(Shader.ShaderType.Fragment,ic.readString("fragLanguage", null));
|
||||
shaderLanguages.put(Shader.ShaderType.Geometry,ic.readString("geomLanguage", null));
|
||||
shaderLanguages.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlLanguage", null));
|
||||
shaderLanguages.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalLanguage", null));
|
||||
}
|
||||
|
||||
usesNodes = ic.readBoolean("usesNodes", false);
|
||||
@ -518,7 +515,6 @@ public class TechniqueDef implements Savable {
|
||||
public void setShaderNodes(List<ShaderNode> shaderNodes) {
|
||||
this.shaderNodes = shaderNodes;
|
||||
usesNodes = true;
|
||||
usesShaders = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -526,7 +522,7 @@ public class TechniqueDef implements Savable {
|
||||
* @return
|
||||
*/
|
||||
public EnumMap<Shader.ShaderType, String> getShaderProgramNames() {
|
||||
return shaderName;
|
||||
return shaderNames;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -534,7 +530,7 @@ public class TechniqueDef implements Savable {
|
||||
* @return
|
||||
*/
|
||||
public EnumMap<Shader.ShaderType, String> getShaderProgramLanguages() {
|
||||
return shaderLanguage;
|
||||
return shaderLanguages;
|
||||
}
|
||||
|
||||
public ShaderGenerationInfo getShaderGenerationInfo() {
|
||||
@ -566,5 +562,4 @@ public class TechniqueDef implements Savable {
|
||||
public void setLightSpace(LightSpace lightSpace) {
|
||||
this.lightSpace = lightSpace;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1321,13 +1321,6 @@ public class GLRenderer implements Renderer {
|
||||
|
||||
|
||||
glfbo.glBindFramebufferEXT(GLExt.GL_FRAMEBUFFER_EXT, prevFBO);
|
||||
try {
|
||||
checkFrameBufferError();
|
||||
} catch (IllegalStateException ex) {
|
||||
logger.log(Level.SEVERE, "Source FBO:\n{0}", src);
|
||||
logger.log(Level.SEVERE, "Dest FBO:\n{0}", dst);
|
||||
throw ex;
|
||||
}
|
||||
} else {
|
||||
throw new RendererException("Framebuffer blitting not supported by the video hardware");
|
||||
}
|
||||
@ -1488,6 +1481,8 @@ public class GLRenderer implements Renderer {
|
||||
updateFrameBufferAttachment(fb, colorBuf);
|
||||
}
|
||||
|
||||
checkFrameBufferError();
|
||||
|
||||
fb.clearUpdateNeeded();
|
||||
}
|
||||
|
||||
@ -1645,8 +1640,6 @@ public class GLRenderer implements Renderer {
|
||||
assert context.boundFBO == fb.getId();
|
||||
|
||||
context.boundFB = fb;
|
||||
|
||||
checkFrameBufferError();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2221,53 +2214,25 @@ public class GLRenderer implements Renderer {
|
||||
int usage = convertUsage(vb.getUsage());
|
||||
vb.getData().rewind();
|
||||
|
||||
// if (created || vb.hasDataSizeChanged()) {
|
||||
// upload data based on format
|
||||
switch (vb.getFormat()) {
|
||||
case Byte:
|
||||
case UnsignedByte:
|
||||
gl.glBufferData(target, (ByteBuffer) vb.getData(), usage);
|
||||
break;
|
||||
// case Half:
|
||||
case Short:
|
||||
case UnsignedShort:
|
||||
gl.glBufferData(target, (ShortBuffer) vb.getData(), usage);
|
||||
break;
|
||||
case Int:
|
||||
case UnsignedInt:
|
||||
glext.glBufferData(target, (IntBuffer) vb.getData(), usage);
|
||||
break;
|
||||
case Float:
|
||||
gl.glBufferData(target, (FloatBuffer) vb.getData(), usage);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown buffer format.");
|
||||
}
|
||||
// } else {
|
||||
// // Invalidate buffer data (orphan) before uploading new data.
|
||||
// switch (vb.getFormat()) {
|
||||
// case Byte:
|
||||
// case UnsignedByte:
|
||||
// gl.glBufferSubData(target, 0, (ByteBuffer) vb.getData());
|
||||
// break;
|
||||
// case Short:
|
||||
// case UnsignedShort:
|
||||
// gl.glBufferSubData(target, 0, (ShortBuffer) vb.getData());
|
||||
// break;
|
||||
// case Int:
|
||||
// case UnsignedInt:
|
||||
// gl.glBufferSubData(target, 0, (IntBuffer) vb.getData());
|
||||
// break;
|
||||
// case Float:
|
||||
// gl.glBufferSubData(target, 0, (FloatBuffer) vb.getData());
|
||||
// break;
|
||||
// case Double:
|
||||
// gl.glBufferSubData(target, 0, (DoubleBuffer) vb.getData());
|
||||
// break;
|
||||
// default:
|
||||
// throw new UnsupportedOperationException("Unknown buffer format.");
|
||||
// }
|
||||
// }
|
||||
switch (vb.getFormat()) {
|
||||
case Byte:
|
||||
case UnsignedByte:
|
||||
gl.glBufferData(target, (ByteBuffer) vb.getData(), usage);
|
||||
break;
|
||||
case Short:
|
||||
case UnsignedShort:
|
||||
gl.glBufferData(target, (ShortBuffer) vb.getData(), usage);
|
||||
break;
|
||||
case Int:
|
||||
case UnsignedInt:
|
||||
glext.glBufferData(target, (IntBuffer) vb.getData(), usage);
|
||||
break;
|
||||
case Float:
|
||||
gl.glBufferData(target, (FloatBuffer) vb.getData(), usage);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown buffer format.");
|
||||
}
|
||||
|
||||
vb.clearUpdateNeeded();
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ public final class GLTracer implements InvocationHandler {
|
||||
// noEnumArgs("glTexParameteri", 2);
|
||||
noEnumArgs("glTexImage2D", 1, 3, 4, 5);
|
||||
noEnumArgs("glTexImage3D", 1, 3, 4, 5, 6);
|
||||
noEnumArgs("glTexSubImage2D", 1, 2, 3, 4, 5);
|
||||
noEnumArgs("glTexSubImage3D", 1, 2, 3, 4, 5, 6, 7);
|
||||
noEnumArgs("glCompressedTexImage2D", 1, 3, 4, 5);
|
||||
noEnumArgs("glCompressedTexSubImage3D", 1, 2, 3, 4, 5, 6, 7);
|
||||
@ -83,6 +84,8 @@ public final class GLTracer implements InvocationHandler {
|
||||
noEnumArgs("glDrawRangeElements", 1, 2, 3, 5);
|
||||
noEnumArgs("glDrawArrays", 1, 2);
|
||||
noEnumArgs("glDeleteBuffers", 0);
|
||||
noEnumArgs("glBindVertexArray", 0);
|
||||
noEnumArgs("glGenVertexArrays", 0);
|
||||
|
||||
noEnumArgs("glBindFramebufferEXT", 1);
|
||||
noEnumArgs("glBindRenderbufferEXT", 1);
|
||||
@ -110,6 +113,7 @@ public final class GLTracer implements InvocationHandler {
|
||||
noEnumArgs("glUniform1f", 0);
|
||||
noEnumArgs("glUniform2f", 0);
|
||||
noEnumArgs("glUniform3f", 0);
|
||||
noEnumArgs("glUniform4", 0);
|
||||
noEnumArgs("glUniform4f", 0);
|
||||
noEnumArgs("glGetAttribLocation", 0, -1);
|
||||
noEnumArgs("glDetachShader", 0, 1);
|
||||
|
@ -64,7 +64,7 @@ import java.util.logging.Logger;
|
||||
* TODO more automagic (batch when needed in the updateLogicalState)
|
||||
* @author Nehon
|
||||
*/
|
||||
public class BatchNode extends GeometryGroupNode implements Savable {
|
||||
public class BatchNode extends GeometryGroupNode {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(BatchNode.class.getName());
|
||||
/**
|
||||
|
@ -58,7 +58,7 @@ import java.util.logging.Logger;
|
||||
* @author Gregg Patton
|
||||
* @author Joshua Slack
|
||||
*/
|
||||
public class Node extends Spatial implements Savable {
|
||||
public class Node extends Spatial {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Node.class.getName());
|
||||
|
||||
|
@ -33,6 +33,12 @@ package com.jme3.scene;
|
||||
|
||||
import com.jme3.export.*;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <code>UserData</code> is used to contain user data objects
|
||||
@ -48,28 +54,40 @@ public final class UserData implements Savable {
|
||||
* shape generation should ignore them.
|
||||
*/
|
||||
public static final String JME_PHYSICSIGNORE = "JmePhysicsIgnore";
|
||||
|
||||
|
||||
/**
|
||||
* For geometries using shared mesh, this will specify the shared
|
||||
* mesh reference.
|
||||
*/
|
||||
public static final String JME_SHAREDMESH = "JmeSharedMesh";
|
||||
|
||||
protected byte type;
|
||||
protected Object value;
|
||||
public static final String JME_SHAREDMESH = "JmeSharedMesh";
|
||||
|
||||
private static final int TYPE_INTEGER = 0;
|
||||
private static final int TYPE_FLOAT = 1;
|
||||
private static final int TYPE_BOOLEAN = 2;
|
||||
private static final int TYPE_STRING = 3;
|
||||
private static final int TYPE_LONG = 4;
|
||||
private static final int TYPE_SAVABLE = 5;
|
||||
private static final int TYPE_LIST = 6;
|
||||
private static final int TYPE_MAP = 7;
|
||||
private static final int TYPE_ARRAY = 8;
|
||||
|
||||
protected byte type;
|
||||
protected Object value;
|
||||
|
||||
public UserData() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>UserData</code> with the given
|
||||
* Creates a new <code>UserData</code> with the given
|
||||
* type and value.
|
||||
*
|
||||
* @param type Type of data, should be between 0 and 4.
|
||||
* @param value Value of the data
|
||||
* @param type
|
||||
* Type of data, should be between 0 and 8.
|
||||
* @param value
|
||||
* Value of the data
|
||||
*/
|
||||
public UserData(byte type, Object value) {
|
||||
assert type >= 0 && type <= 4;
|
||||
assert type >= 0 && type <= 8;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
@ -85,15 +103,23 @@ public final class UserData implements Savable {
|
||||
|
||||
public static byte getObjectType(Object type) {
|
||||
if (type instanceof Integer) {
|
||||
return 0;
|
||||
return TYPE_INTEGER;
|
||||
} else if (type instanceof Float) {
|
||||
return 1;
|
||||
return TYPE_FLOAT;
|
||||
} else if (type instanceof Boolean) {
|
||||
return 2;
|
||||
return TYPE_BOOLEAN;
|
||||
} else if (type instanceof String) {
|
||||
return 3;
|
||||
return TYPE_STRING;
|
||||
} else if (type instanceof Long) {
|
||||
return 4;
|
||||
return TYPE_LONG;
|
||||
} else if (type instanceof Savable) {
|
||||
return TYPE_SAVABLE;
|
||||
} else if (type instanceof List) {
|
||||
return TYPE_LIST;
|
||||
} else if (type instanceof Map) {
|
||||
return TYPE_MAP;
|
||||
} else if (type instanceof Object[]) {
|
||||
return TYPE_ARRAY;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported type: " + type.getClass().getName());
|
||||
}
|
||||
@ -101,56 +127,195 @@ public final class UserData implements Savable {
|
||||
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(type, "type", (byte)0);
|
||||
oc.write(type, "type", (byte) 0);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
case TYPE_INTEGER:
|
||||
int i = (Integer) value;
|
||||
oc.write(i, "intVal", 0);
|
||||
break;
|
||||
case 1:
|
||||
case TYPE_FLOAT:
|
||||
float f = (Float) value;
|
||||
oc.write(f, "floatVal", 0f);
|
||||
break;
|
||||
case 2:
|
||||
case TYPE_BOOLEAN:
|
||||
boolean b = (Boolean) value;
|
||||
oc.write(b, "boolVal", false);
|
||||
break;
|
||||
case 3:
|
||||
case TYPE_STRING:
|
||||
String s = (String) value;
|
||||
oc.write(s, "strVal", null);
|
||||
break;
|
||||
case 4:
|
||||
case TYPE_LONG:
|
||||
Long l = (Long) value;
|
||||
oc.write(l, "longVal", 0l);
|
||||
break;
|
||||
case TYPE_SAVABLE:
|
||||
Savable sav = (Savable) value;
|
||||
oc.write(sav, "savableVal", null);
|
||||
break;
|
||||
case TYPE_LIST:
|
||||
this.writeList(oc, (List<?>) value, "0");
|
||||
break;
|
||||
case TYPE_MAP:
|
||||
Map<?, ?> map = (Map<?, ?>) value;
|
||||
this.writeList(oc, map.keySet(), "0");
|
||||
this.writeList(oc, map.values(), "1");
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
this.writeList(oc, Arrays.asList((Object[]) value), "0");
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException("Unsupported value type: " + value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public void read(JmeImporter im) throws IOException {
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
type = ic.readByte("type", (byte) 0);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
case TYPE_INTEGER:
|
||||
value = ic.readInt("intVal", 0);
|
||||
break;
|
||||
case 1:
|
||||
case TYPE_FLOAT:
|
||||
value = ic.readFloat("floatVal", 0f);
|
||||
break;
|
||||
case 2:
|
||||
case TYPE_BOOLEAN:
|
||||
value = ic.readBoolean("boolVal", false);
|
||||
break;
|
||||
case 3:
|
||||
case TYPE_STRING:
|
||||
value = ic.readString("strVal", null);
|
||||
break;
|
||||
case 4:
|
||||
case TYPE_LONG:
|
||||
value = ic.readLong("longVal", 0l);
|
||||
break;
|
||||
case TYPE_SAVABLE:
|
||||
value = ic.readSavable("savableVal", null);
|
||||
break;
|
||||
case TYPE_LIST:
|
||||
value = this.readList(ic, "0");
|
||||
break;
|
||||
case TYPE_MAP:
|
||||
Map<Object, Object> map = new HashMap<Object, Object>();
|
||||
List<?> keys = this.readList(ic, "0");
|
||||
List<?> values = this.readList(ic, "1");
|
||||
for (int i = 0; i < keys.size(); ++i) {
|
||||
map.put(keys.get(i), values.get(i));
|
||||
}
|
||||
value = map;
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
value = this.readList(ic, "0").toArray();
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException("Unknown type of stored data: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method stores a list in the capsule.
|
||||
* @param oc
|
||||
* output capsule
|
||||
* @param list
|
||||
* the list to be stored
|
||||
* @throws IOException
|
||||
*/
|
||||
private void writeList(OutputCapsule oc, Collection<?> list, String listName) throws IOException {
|
||||
if (list != null) {
|
||||
oc.write(list.size(), listName + "size", 0);
|
||||
int counter = 0;
|
||||
for (Object o : list) {
|
||||
// t is for 'type'; v is for 'value'
|
||||
if (o instanceof Integer) {
|
||||
oc.write(TYPE_INTEGER, listName + "t" + counter, 0);
|
||||
oc.write((Integer) o, listName + "v" + counter, 0);
|
||||
} else if (o instanceof Float) {
|
||||
oc.write(TYPE_FLOAT, listName + "t" + counter, 0);
|
||||
oc.write((Float) o, listName + "v" + counter, 0f);
|
||||
} else if (o instanceof Boolean) {
|
||||
oc.write(TYPE_BOOLEAN, listName + "t" + counter, 0);
|
||||
oc.write((Boolean) o, listName + "v" + counter, false);
|
||||
} else if (o instanceof String || o == null) {// treat null's like Strings just to store them and keep the List like the user intended
|
||||
oc.write(TYPE_STRING, listName + "t" + counter, 0);
|
||||
oc.write((String) o, listName + "v" + counter, null);
|
||||
} else if (o instanceof Long) {
|
||||
oc.write(TYPE_LONG, listName + "t" + counter, 0);
|
||||
oc.write((Long) o, listName + "v" + counter, 0L);
|
||||
} else if (o instanceof Savable) {
|
||||
oc.write(TYPE_SAVABLE, listName + "t" + counter, 0);
|
||||
oc.write((Savable) o, listName + "v" + counter, null);
|
||||
} else if(o instanceof Object[]) {
|
||||
oc.write(TYPE_ARRAY, listName + "t" + counter, 0);
|
||||
this.writeList(oc, Arrays.asList((Object[]) o), listName + "v" + counter);
|
||||
} else if(o instanceof List) {
|
||||
oc.write(TYPE_LIST, listName + "t" + counter, 0);
|
||||
this.writeList(oc, (List<?>) o, listName + "v" + counter);
|
||||
} else if(o instanceof Map) {
|
||||
oc.write(TYPE_MAP, listName + "t" + counter, 0);
|
||||
Map<?, ?> map = (Map<?, ?>) o;
|
||||
this.writeList(oc, map.keySet(), listName + "v(keys)" + counter);
|
||||
this.writeList(oc, map.values(), listName + "v(vals)" + counter);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported type stored in the list: " + o.getClass());
|
||||
}
|
||||
|
||||
++counter;
|
||||
}
|
||||
} else {
|
||||
oc.write(0, "size", 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method loads a list from the given input capsule.
|
||||
* @param ic
|
||||
* the input capsule
|
||||
* @return loaded list (an empty list in case its size is 0)
|
||||
* @throws IOException
|
||||
*/
|
||||
private List<?> readList(InputCapsule ic, String listName) throws IOException {
|
||||
int size = ic.readInt(listName + "size", 0);
|
||||
List<Object> list = new ArrayList<Object>(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
int type = ic.readInt(listName + "t" + i, 0);
|
||||
switch (type) {
|
||||
case TYPE_INTEGER:
|
||||
list.add(ic.readInt(listName + "v" + i, 0));
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
list.add(ic.readFloat(listName + "v" + i, 0));
|
||||
break;
|
||||
case TYPE_BOOLEAN:
|
||||
list.add(ic.readBoolean(listName + "v" + i, false));
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
list.add(ic.readString(listName + "v" + i, null));
|
||||
break;
|
||||
case TYPE_LONG:
|
||||
list.add(ic.readLong(listName + "v" + i, 0L));
|
||||
break;
|
||||
case TYPE_SAVABLE:
|
||||
list.add(ic.readSavable(listName + "v" + i, null));
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
list.add(this.readList(ic, listName + "v" + i).toArray());
|
||||
break;
|
||||
case TYPE_LIST:
|
||||
list.add(this.readList(ic, listName + "v" + i));
|
||||
break;
|
||||
case TYPE_MAP:
|
||||
Map<Object, Object> map = new HashMap<Object, Object>();
|
||||
List<?> keys = this.readList(ic, listName + "v(keys)" + i);
|
||||
List<?> values = this.readList(ic, listName + "v(vals)" + i);
|
||||
for (int j = 0; j < keys.size(); ++j) {
|
||||
map.put(keys.get(j), values.get(j));
|
||||
}
|
||||
list.add(map);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown type of stored data in a list: " + type);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public class InstancedNode extends GeometryGroupNode {
|
||||
setGeometryStartIndex(geom, startIndex);
|
||||
}
|
||||
|
||||
private static class InstanceTypeKey implements Cloneable {
|
||||
private static final class InstanceTypeKey implements Cloneable {
|
||||
|
||||
Mesh mesh;
|
||||
Material material;
|
||||
|
@ -266,7 +266,7 @@ public class Dome extends Mesh {
|
||||
vars.release();
|
||||
|
||||
// pole
|
||||
vb.put(center.x).put(center.y + radius).put(center.z);
|
||||
vb.put(this.center.x).put(this.center.y + radius).put(this.center.z);
|
||||
nb.put(0).put(insideView ? -1 : 1).put(0);
|
||||
tb.put(0.5f).put(1.0f);
|
||||
|
||||
|
@ -40,7 +40,7 @@ import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class DefineList implements Savable, Cloneable {
|
||||
public final class DefineList implements Savable, Cloneable {
|
||||
|
||||
private static final String ONE = "1";
|
||||
|
||||
|
@ -46,6 +46,8 @@ public class NullContext implements JmeContext, Runnable {
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(NullContext.class.getName());
|
||||
|
||||
protected static final String THREAD_NAME = "jME3 Headless Main";
|
||||
|
||||
protected AtomicBoolean created = new AtomicBoolean(false);
|
||||
protected AtomicBoolean needClose = new AtomicBoolean(false);
|
||||
protected final Object createdLock = new Object();
|
||||
@ -150,7 +152,7 @@ public class NullContext implements JmeContext, Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(this, "Headless Application Thread").start();
|
||||
new Thread(this, THREAD_NAME).start();
|
||||
if (waitFor)
|
||||
waitFor(true);
|
||||
}
|
||||
|
@ -72,9 +72,10 @@ import java.util.ArrayList;
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class FrameBuffer extends NativeObject {
|
||||
public static int SLOT_UNDEF = -1;
|
||||
public static int SLOT_DEPTH = -100;
|
||||
public static int SLOT_DEPTH_STENCIL = -101;
|
||||
|
||||
public static final int SLOT_UNDEF = -1;
|
||||
public static final int SLOT_DEPTH = -100;
|
||||
public static final int SLOT_DEPTH_STENCIL = -101;
|
||||
|
||||
private int width = 0;
|
||||
private int height = 0;
|
||||
|
@ -488,7 +488,8 @@ public abstract class Texture implements CloneableSmartAsset, Savable, Cloneable
|
||||
|
||||
/**
|
||||
* @return the anisotropic filtering level for this texture. Default value
|
||||
* is 1 (no anisotrophy), 2 means x2, 4 is x4, etc.
|
||||
* is 0 (use value from config),
|
||||
* 1 means 1x (no anisotrophy), 2 means x2, 4 is x4, etc.
|
||||
*/
|
||||
public int getAnisotropicFilter() {
|
||||
return anisotropicFilter;
|
||||
@ -499,11 +500,7 @@ public abstract class Texture implements CloneableSmartAsset, Savable, Cloneable
|
||||
* the anisotropic filtering level for this texture.
|
||||
*/
|
||||
public void setAnisotropicFilter(int level) {
|
||||
if (level < 1) {
|
||||
anisotropicFilter = 1;
|
||||
} else {
|
||||
anisotropicFilter = level;
|
||||
}
|
||||
anisotropicFilter = Math.max(0, level);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -34,6 +34,7 @@ package com.jme3.util;
|
||||
import com.jme3.util.IntMap.Entry;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Similar to a {@link Map} except that ints are used as keys.
|
||||
@ -234,7 +235,7 @@ public final class IntMap<T> implements Iterable<Entry<T>>, Cloneable {
|
||||
|
||||
public Entry next() {
|
||||
if (el >= size)
|
||||
throw new IllegalStateException("No more elements!");
|
||||
throw new NoSuchElementException("No more elements!");
|
||||
|
||||
if (cur != null){
|
||||
Entry e = cur;
|
||||
|
@ -274,11 +274,9 @@ public class TangentBinormalGenerator {
|
||||
triData.setIndex(index);
|
||||
triData.triangleOffset = i * 3 ;
|
||||
}
|
||||
if (triData != null) {
|
||||
vertices.get(index[0]).triangles.add(triData);
|
||||
vertices.get(index[1]).triangles.add(triData);
|
||||
vertices.get(index[2]).triangles.add(triData);
|
||||
}
|
||||
vertices.get(index[0]).triangles.add(triData);
|
||||
vertices.get(index[1]).triangles.add(triData);
|
||||
vertices.get(index[2]).triangles.add(triData);
|
||||
}
|
||||
|
||||
return vertices;
|
||||
@ -483,7 +481,7 @@ public class TangentBinormalGenerator {
|
||||
boolean isDegenerate = isDegenerateTriangle(v[0], v[1], v[2]);
|
||||
TriangleData triData = processTriangle(index, v, t);
|
||||
|
||||
if (triData != null && !isDegenerate) {
|
||||
if (!isDegenerate) {
|
||||
vertices.get(index[0]).triangles.add(triData);
|
||||
vertices.get(index[1]).triangles.add(triData);
|
||||
vertices.get(index[2]).triangles.add(triData);
|
||||
@ -529,11 +527,9 @@ public class TangentBinormalGenerator {
|
||||
populateFromBuffer(t[2], textureBuffer, index[2]);
|
||||
|
||||
TriangleData triData = processTriangle(index, v, t);
|
||||
if (triData != null) {
|
||||
vertices.get(index[0]).triangles.add(triData);
|
||||
vertices.get(index[1]).triangles.add(triData);
|
||||
vertices.get(index[2]).triangles.add(triData);
|
||||
}
|
||||
vertices.get(index[0]).triangles.add(triData);
|
||||
vertices.get(index[1]).triangles.add(triData);
|
||||
vertices.get(index[2]).triangles.add(triData);
|
||||
|
||||
Vector3f vTemp = v[1];
|
||||
v[1] = v[2];
|
||||
|
@ -71,7 +71,7 @@ public class BlockLanguageParser {
|
||||
private void load(InputStream in) throws IOException{
|
||||
reset();
|
||||
|
||||
reader = new InputStreamReader(in);
|
||||
reader = new InputStreamReader(in, "UTF-8");
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
boolean insideComment = false;
|
||||
|
@ -126,7 +126,8 @@ void main(){
|
||||
DiffuseSum = m_Diffuse * vec4(lightColor.rgb, 1.0);
|
||||
SpecularSum = (m_Specular * lightColor).rgb;
|
||||
#else
|
||||
AmbientSum = g_AmbientLightColor.rgb; // Default: ambient color is dark gray
|
||||
// Defaults: Ambient and diffuse are white, specular is black.
|
||||
AmbientSum = g_AmbientLightColor.rgb;
|
||||
DiffuseSum = vec4(lightColor.rgb, 1.0);
|
||||
SpecularSum = vec3(0.0);
|
||||
#endif
|
||||
|
@ -117,6 +117,7 @@ void main(){
|
||||
SpecularSum = m_Specular.rgb;
|
||||
DiffuseSum = m_Diffuse;
|
||||
#else
|
||||
// Defaults: Ambient and diffuse are white, specular is black.
|
||||
AmbientSum = g_AmbientLightColor.rgb;
|
||||
SpecularSum = vec3(0.0);
|
||||
DiffuseSum = vec4(1.0);
|
||||
|
@ -30,6 +30,14 @@ float computeSpotFalloff(in vec4 lightDirection, in vec3 lightVector){
|
||||
float innerAngleCos = floor(lightDirection.w) * 0.001;
|
||||
float outerAngleCos = fract(lightDirection.w);
|
||||
float innerMinusOuter = innerAngleCos - outerAngleCos;
|
||||
return clamp((curAngleCos - outerAngleCos) / innerMinusOuter, step(lightDirection.w, 0.001), 1.0);
|
||||
float falloff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, step(lightDirection.w, 0.001), 1.0);
|
||||
|
||||
#ifdef SRGB
|
||||
// Use quadratic falloff (notice the ^4)
|
||||
return pow(clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0), 4.0);
|
||||
#else
|
||||
// Use linear falloff
|
||||
return falloff;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ public class WAVLoader implements AssetLoader {
|
||||
break;
|
||||
case i_data:
|
||||
// Compute duration based on data chunk size
|
||||
duration = len / bytesPerSec;
|
||||
duration = (float)(len / bytesPerSec);
|
||||
|
||||
if (readStream) {
|
||||
readDataChunkForStream(inOffset, len);
|
||||
|
@ -270,9 +270,7 @@ public final class BinaryImporter implements JmeImporter {
|
||||
try {
|
||||
return load(fis, listener);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
fis.close();
|
||||
}
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,6 +186,7 @@ public class J3MLoader implements AssetLoader {
|
||||
tex.setWrap(WrapMode.Repeat);
|
||||
}
|
||||
tex.setKey(texKey);
|
||||
tex.setName(texKey.getName());
|
||||
}
|
||||
return tex;
|
||||
}else{
|
||||
|
@ -71,7 +71,7 @@ public class VideoRecorderAppState extends AbstractAppState {
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread th = new Thread(r);
|
||||
th.setName("jME Video Processing Thread");
|
||||
th.setName("jME3 Video Processor");
|
||||
th.setDaemon(true);
|
||||
return th;
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ import java.util.List;
|
||||
public class TestSweepTest extends SimpleApplication {
|
||||
|
||||
private BulletAppState bulletAppState = new BulletAppState();
|
||||
private CapsuleCollisionShape obstacleCollisionShape = new CapsuleCollisionShape(0.3f, 0.5f);
|
||||
private CapsuleCollisionShape capsuleCollisionShape = new CapsuleCollisionShape(1f, 1f);
|
||||
private CapsuleCollisionShape obstacleCollisionShape;
|
||||
private CapsuleCollisionShape capsuleCollisionShape;
|
||||
private Node capsule;
|
||||
private Node obstacle;
|
||||
private float dist = .5f;
|
||||
@ -33,6 +33,9 @@ public class TestSweepTest extends SimpleApplication {
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
obstacleCollisionShape = new CapsuleCollisionShape(0.3f, 0.5f);
|
||||
capsuleCollisionShape = new CapsuleCollisionShape(1f, 1f);
|
||||
|
||||
stateManager.attach(bulletAppState);
|
||||
|
||||
capsule = new Node("capsule");
|
||||
@ -56,14 +59,19 @@ public class TestSweepTest extends SimpleApplication {
|
||||
public void simpleUpdate(float tpf) {
|
||||
|
||||
float move = tpf * 1;
|
||||
boolean colliding = false;
|
||||
|
||||
List<PhysicsSweepTestResult> sweepTest = bulletAppState.getPhysicsSpace().sweepTest(capsuleCollisionShape, new Transform(capsule.getWorldTranslation()), new Transform(capsule.getWorldTranslation().add(dist, 0, 0)));
|
||||
|
||||
if (sweepTest.size() > 0) {
|
||||
PhysicsSweepTestResult get = sweepTest.get(0);
|
||||
PhysicsCollisionObject collisionObject = get.getCollisionObject();
|
||||
fpsText.setText("Almost colliding with " + collisionObject.getUserObject().toString());
|
||||
} else {
|
||||
for (PhysicsSweepTestResult result : sweepTest) {
|
||||
if (result.getCollisionObject().getCollisionShape() != capsuleCollisionShape) {
|
||||
PhysicsCollisionObject collisionObject = result.getCollisionObject();
|
||||
fpsText.setText("Almost colliding with " + collisionObject.getUserObject().toString());
|
||||
colliding = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colliding) {
|
||||
// if the sweep is clear then move the spatial
|
||||
capsule.move(move, 0, 0);
|
||||
}
|
||||
|
@ -759,14 +759,6 @@ public class IGLESShaderRenderer implements Renderer {
|
||||
Image[] textures = context.boundTextures;
|
||||
|
||||
int type = convertTextureType(tex.getType());
|
||||
if (!context.textureIndexList.moveToNew(unit)) {
|
||||
// if (context.boundTextureUnit != unit){
|
||||
// glActiveTexture(GL_TEXTURE0 + unit);
|
||||
// context.boundTextureUnit = unit;
|
||||
// }
|
||||
// glEnable(type);
|
||||
}
|
||||
|
||||
if (textures[unit] != image) {
|
||||
if (context.boundTextureUnit != unit) {
|
||||
JmeIosGLES.glActiveTexture(JmeIosGLES.GL_TEXTURE0 + unit);
|
||||
@ -1768,7 +1760,6 @@ public class IGLESShaderRenderer implements Renderer {
|
||||
JmeIosGLES.checkGLError();
|
||||
}
|
||||
clearVertexAttribs();
|
||||
clearTextureUnits();
|
||||
}
|
||||
|
||||
private void renderMeshDefault(Mesh mesh, int lod, int count) {
|
||||
@ -1807,7 +1798,6 @@ public class IGLESShaderRenderer implements Renderer {
|
||||
JmeIosGLES.checkGLError();
|
||||
}
|
||||
clearVertexAttribs();
|
||||
clearTextureUnits();
|
||||
}
|
||||
|
||||
|
||||
@ -2085,23 +2075,6 @@ public class IGLESShaderRenderer implements Renderer {
|
||||
context.attribIndexList.copyNewToOld();
|
||||
}
|
||||
|
||||
|
||||
public void clearTextureUnits() {
|
||||
IDList textureList = context.textureIndexList;
|
||||
Image[] textures = context.boundTextures;
|
||||
for (int i = 0; i < textureList.oldLen; i++) {
|
||||
int idx = textureList.oldList[i];
|
||||
// if (context.boundTextureUnit != idx){
|
||||
// glActiveTexture(GL_TEXTURE0 + idx);
|
||||
// context.boundTextureUnit = idx;
|
||||
// }
|
||||
// glDisable(convertTextureType(textures[idx].getType()));
|
||||
textures[idx] = null;
|
||||
}
|
||||
context.textureIndexList.copyNewToOld();
|
||||
}
|
||||
|
||||
|
||||
public void updateFrameBuffer(FrameBuffer fb) {
|
||||
int id = fb.getId();
|
||||
if (id == -1) {
|
||||
|
@ -5,7 +5,7 @@ if (!hasProperty('mainClass')) {
|
||||
dependencies {
|
||||
compile project(':jme3-core')
|
||||
compile project(':jme3-desktop')
|
||||
compile 'org.jogamp.gluegen:gluegen-rt-main:2.2.0'
|
||||
compile 'org.jogamp.jogl:jogl-all-main:2.2.0'
|
||||
compile 'org.jogamp.joal:joal-main:2.2.0'
|
||||
compile 'org.jogamp.gluegen:gluegen-rt-main:2.3.1'
|
||||
compile 'org.jogamp.jogl:jogl-all-main:2.3.1'
|
||||
compile 'org.jogamp.joal:joal-main:2.3.1'
|
||||
}
|
||||
|
@ -45,11 +45,11 @@ import com.jogamp.newt.opengl.GLWindow;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.nativewindow.util.Dimension;
|
||||
import javax.media.nativewindow.util.DimensionImmutable;
|
||||
import javax.media.nativewindow.util.PixelFormat;
|
||||
import javax.media.nativewindow.util.PixelRectangle;
|
||||
import javax.media.nativewindow.util.Point;
|
||||
import com.jogamp.nativewindow.util.Dimension;
|
||||
import com.jogamp.nativewindow.util.DimensionImmutable;
|
||||
import com.jogamp.nativewindow.util.PixelFormat;
|
||||
import com.jogamp.nativewindow.util.PixelRectangle;
|
||||
import com.jogamp.nativewindow.util.Point;
|
||||
|
||||
public class NewtMouseInput implements MouseInput, MouseListener {
|
||||
|
||||
|
@ -70,15 +70,15 @@ import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.nativewindow.NativeWindowFactory;
|
||||
import javax.media.opengl.GL;
|
||||
import javax.media.opengl.GL2;
|
||||
import javax.media.opengl.GL2ES1;
|
||||
import javax.media.opengl.GL2ES2;
|
||||
import javax.media.opengl.GL2ES3;
|
||||
import javax.media.opengl.GL2GL3;
|
||||
import javax.media.opengl.GL3;
|
||||
import javax.media.opengl.GLContext;
|
||||
import com.jogamp.nativewindow.NativeWindowFactory;
|
||||
import com.jogamp.opengl.GL;
|
||||
import com.jogamp.opengl.GL2;
|
||||
import com.jogamp.opengl.GL2ES1;
|
||||
import com.jogamp.opengl.GL2ES2;
|
||||
import com.jogamp.opengl.GL2ES3;
|
||||
import com.jogamp.opengl.GL2GL3;
|
||||
import com.jogamp.opengl.GL3;
|
||||
import com.jogamp.opengl.GLContext;
|
||||
import jme3tools.converters.MipMapGenerator;
|
||||
import jme3tools.shader.ShaderDebug;
|
||||
|
||||
@ -1800,7 +1800,7 @@ public class JoglRenderer implements Renderer {
|
||||
if (samples > 1) {
|
||||
return GL3.GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
|
||||
} else {
|
||||
return GL.GL_TEXTURE_2D_ARRAY;
|
||||
return GL2ES3.GL_TEXTURE_2D_ARRAY;
|
||||
}
|
||||
case ThreeDimensional:
|
||||
return GL2ES2.GL_TEXTURE_3D;
|
||||
@ -2014,7 +2014,7 @@ public class JoglRenderer implements Renderer {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
TextureUtil.uploadTexture(img, GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, linearizeSrgbImages);
|
||||
}
|
||||
} else if (target == GL.GL_TEXTURE_2D_ARRAY) {
|
||||
} else if (target == GL2ES3.GL_TEXTURE_2D_ARRAY) {
|
||||
if (!caps.contains(Caps.TextureArray)) {
|
||||
throw new RendererException("Texture arrays not supported by graphics hardware");
|
||||
}
|
||||
|
@ -36,14 +36,17 @@ import com.jme3.renderer.RendererException;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.Image.Format;
|
||||
import com.jme3.texture.image.ColorSpace;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.opengl.GL;
|
||||
import javax.media.opengl.GL2;
|
||||
import javax.media.opengl.GL2ES2;
|
||||
import javax.media.opengl.GL2GL3;
|
||||
import javax.media.opengl.GLContext;
|
||||
|
||||
import com.jogamp.opengl.GL;
|
||||
import com.jogamp.opengl.GL2;
|
||||
import com.jogamp.opengl.GL2ES2;
|
||||
import com.jogamp.opengl.GL2ES3;
|
||||
import com.jogamp.opengl.GL2GL3;
|
||||
import com.jogamp.opengl.GLContext;
|
||||
|
||||
public class TextureUtil {
|
||||
|
||||
@ -124,9 +127,9 @@ public class TextureUtil {
|
||||
setFormat(Format.RGB32F, GL.GL_RGB32F, GL.GL_RGB, GL.GL_FLOAT, false);
|
||||
|
||||
// Special RGB formats
|
||||
setFormat(Format.RGB111110F, GL.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_UNSIGNED_INT_10F_11F_11F_REV, false);
|
||||
setFormat(Format.RGB111110F, GL2ES3.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_UNSIGNED_INT_10F_11F_11F_REV, false);
|
||||
setFormat(Format.RGB9E5, GL2GL3.GL_RGB9_E5, GL.GL_RGB, GL2GL3.GL_UNSIGNED_INT_5_9_9_9_REV, false);
|
||||
setFormat(Format.RGB16F_to_RGB111110F, GL.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_HALF_FLOAT, false);
|
||||
setFormat(Format.RGB16F_to_RGB111110F, GL2ES3.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_HALF_FLOAT, false);
|
||||
setFormat(Format.RGB16F_to_RGB9E5, GL2.GL_RGB9_E5, GL.GL_RGB, GL.GL_HALF_FLOAT, false);
|
||||
|
||||
// RGBA formats
|
||||
@ -346,7 +349,7 @@ public class TextureUtil {
|
||||
glFmt.format,
|
||||
glFmt.dataType,
|
||||
data);
|
||||
}else if (target == GL.GL_TEXTURE_2D_ARRAY){
|
||||
}else if (target == GL2ES3.GL_TEXTURE_2D_ARRAY){
|
||||
// prepare data for 2D array
|
||||
// or upload slice
|
||||
if (index == -1){
|
||||
|
@ -45,20 +45,20 @@ import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.opengl.DebugGL2;
|
||||
import javax.media.opengl.DebugGL3;
|
||||
import javax.media.opengl.DebugGL3bc;
|
||||
import javax.media.opengl.DebugGL4;
|
||||
import javax.media.opengl.DebugGL4bc;
|
||||
import javax.media.opengl.DebugGLES1;
|
||||
import javax.media.opengl.DebugGLES2;
|
||||
import javax.media.opengl.GL;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import javax.media.opengl.GLCapabilities;
|
||||
import javax.media.opengl.GLEventListener;
|
||||
import javax.media.opengl.GLProfile;
|
||||
import javax.media.opengl.GLRunnable;
|
||||
import javax.media.opengl.awt.GLCanvas;
|
||||
import com.jogamp.opengl.DebugGL2;
|
||||
import com.jogamp.opengl.DebugGL3;
|
||||
import com.jogamp.opengl.DebugGL3bc;
|
||||
import com.jogamp.opengl.DebugGL4;
|
||||
import com.jogamp.opengl.DebugGL4bc;
|
||||
import com.jogamp.opengl.DebugGLES1;
|
||||
import com.jogamp.opengl.DebugGLES2;
|
||||
import com.jogamp.opengl.GL;
|
||||
import com.jogamp.opengl.GLAutoDrawable;
|
||||
import com.jogamp.opengl.GLCapabilities;
|
||||
import com.jogamp.opengl.GLEventListener;
|
||||
import com.jogamp.opengl.GLProfile;
|
||||
import com.jogamp.opengl.GLRunnable;
|
||||
import com.jogamp.opengl.awt.GLCanvas;
|
||||
|
||||
public abstract class JoglAbstractDisplay extends JoglContext implements GLEventListener {
|
||||
|
||||
|
@ -35,7 +35,7 @@ package com.jme3.system.jogl;
|
||||
import com.jme3.system.JmeCanvasContext;
|
||||
import java.awt.Canvas;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import com.jogamp.opengl.GLAutoDrawable;
|
||||
|
||||
public class JoglCanvas extends JoglAbstractDisplay implements JmeCanvasContext {
|
||||
|
||||
|
@ -47,14 +47,16 @@ import java.nio.IntBuffer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.opengl.GL;
|
||||
import javax.media.opengl.GL2GL3;
|
||||
import javax.media.opengl.GLContext;
|
||||
import com.jogamp.opengl.GL;
|
||||
import com.jogamp.opengl.GL2GL3;
|
||||
import com.jogamp.opengl.GLContext;
|
||||
|
||||
public abstract class JoglContext implements JmeContext {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(JoglContext.class.getName());
|
||||
|
||||
protected static final String THREAD_NAME = "jME3 Main";
|
||||
|
||||
protected AtomicBoolean created = new AtomicBoolean(false);
|
||||
protected AtomicBoolean renderable = new AtomicBoolean(false);
|
||||
protected final Object createdLock = new Object();
|
||||
|
@ -45,7 +45,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import com.jogamp.opengl.GLAutoDrawable;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
|
@ -44,19 +44,19 @@ import com.jogamp.opengl.util.AnimatorBase;
|
||||
import com.jogamp.opengl.util.FPSAnimator;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.opengl.DebugGL2;
|
||||
import javax.media.opengl.DebugGL3;
|
||||
import javax.media.opengl.DebugGL3bc;
|
||||
import javax.media.opengl.DebugGL4;
|
||||
import javax.media.opengl.DebugGL4bc;
|
||||
import javax.media.opengl.DebugGLES1;
|
||||
import javax.media.opengl.DebugGLES2;
|
||||
import javax.media.opengl.GL;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import javax.media.opengl.GLCapabilities;
|
||||
import javax.media.opengl.GLEventListener;
|
||||
import javax.media.opengl.GLProfile;
|
||||
import javax.media.opengl.GLRunnable;
|
||||
import com.jogamp.opengl.DebugGL2;
|
||||
import com.jogamp.opengl.DebugGL3;
|
||||
import com.jogamp.opengl.DebugGL3bc;
|
||||
import com.jogamp.opengl.DebugGL4;
|
||||
import com.jogamp.opengl.DebugGL4bc;
|
||||
import com.jogamp.opengl.DebugGLES1;
|
||||
import com.jogamp.opengl.DebugGLES2;
|
||||
import com.jogamp.opengl.GL;
|
||||
import com.jogamp.opengl.GLAutoDrawable;
|
||||
import com.jogamp.opengl.GLCapabilities;
|
||||
import com.jogamp.opengl.GLEventListener;
|
||||
import com.jogamp.opengl.GLProfile;
|
||||
import com.jogamp.opengl.GLRunnable;
|
||||
|
||||
public abstract class JoglNewtAbstractDisplay extends JoglContext implements GLEventListener {
|
||||
|
||||
|
@ -35,7 +35,7 @@ package com.jme3.system.jogl;
|
||||
import com.jme3.system.JmeCanvasContext;
|
||||
import com.jogamp.newt.awt.NewtCanvasAWT;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import com.jogamp.opengl.GLAutoDrawable;
|
||||
|
||||
public class JoglNewtCanvas extends JoglNewtAbstractDisplay implements JmeCanvasContext {
|
||||
|
||||
|
@ -42,8 +42,8 @@ import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.nativewindow.util.Dimension;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import com.jogamp.nativewindow.util.Dimension;
|
||||
import com.jogamp.opengl.GLAutoDrawable;
|
||||
|
||||
public class JoglNewtDisplay extends JoglNewtAbstractDisplay {
|
||||
|
||||
|
@ -41,12 +41,12 @@ import com.jogamp.newt.NewtVersion;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.media.opengl.GL;
|
||||
import javax.media.opengl.GLCapabilities;
|
||||
import javax.media.opengl.GLContext;
|
||||
import javax.media.opengl.GLDrawableFactory;
|
||||
import javax.media.opengl.GLOffscreenAutoDrawable;
|
||||
import javax.media.opengl.GLProfile;
|
||||
import com.jogamp.opengl.GL;
|
||||
import com.jogamp.opengl.GLCapabilities;
|
||||
import com.jogamp.opengl.GLContext;
|
||||
import com.jogamp.opengl.GLDrawableFactory;
|
||||
import com.jogamp.opengl.GLOffscreenAutoDrawable;
|
||||
import com.jogamp.opengl.GLProfile;
|
||||
|
||||
|
||||
public class JoglOffscreenBuffer extends JoglContext implements Runnable {
|
||||
@ -146,7 +146,7 @@ public class JoglOffscreenBuffer extends JoglContext implements Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(this, "JOGL Renderer Thread").start();
|
||||
new Thread(this, THREAD_NAME).start();
|
||||
if (waitFor) {
|
||||
waitFor(true);
|
||||
}
|
||||
|
@ -181,7 +181,9 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna
|
||||
|
||||
// check input after we synchronize with framerate.
|
||||
// this reduces input lag.
|
||||
Display.processMessages();
|
||||
if (renderable.get()){
|
||||
Display.processMessages();
|
||||
}
|
||||
|
||||
// Subclasses just call GLObjectManager clean up objects here
|
||||
// it is safe .. for now.
|
||||
|
@ -96,7 +96,7 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
|
||||
canvas.setFocusable(true);
|
||||
canvas.setIgnoreRepaint(true);
|
||||
|
||||
renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
|
||||
renderThread = new Thread(LwjglCanvas.this, THREAD_NAME);
|
||||
renderThread.start();
|
||||
}else if (needClose.get()){
|
||||
return;
|
||||
@ -162,7 +162,7 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
|
||||
if (renderThread == null){
|
||||
logger.log(Level.FINE, "MAIN: Creating OGL thread.");
|
||||
|
||||
renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
|
||||
renderThread = new Thread(LwjglCanvas.this, THREAD_NAME);
|
||||
renderThread.start();
|
||||
}
|
||||
// do not do anything.
|
||||
|
@ -67,6 +67,8 @@ public abstract class LwjglContext implements JmeContext {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglContext.class.getName());
|
||||
|
||||
protected static final String THREAD_NAME = "jME3 Main";
|
||||
|
||||
protected AtomicBoolean created = new AtomicBoolean(false);
|
||||
protected AtomicBoolean renderable = new AtomicBoolean(false);
|
||||
protected final Object createdLock = new Object();
|
||||
|
@ -166,7 +166,7 @@ public class LwjglDisplay extends LwjglAbstractDisplay {
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(this, "LWJGL Renderer Thread").start();
|
||||
new Thread(this, THREAD_NAME).start();
|
||||
if (waitFor)
|
||||
waitFor(true);
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(this, "LWJGL Renderer Thread").start();
|
||||
new Thread(this, THREAD_NAME).start();
|
||||
if (waitFor)
|
||||
waitFor(true);
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ import com.jme3.texture.Image.Format;
|
||||
import com.jme3.texture.Texture.MagFilter;
|
||||
import com.jme3.texture.Texture.MinFilter;
|
||||
import com.jme3.texture.Texture2D;
|
||||
import com.jme3.texture.image.ColorSpace;
|
||||
import com.jme3.util.BufferUtils;
|
||||
|
||||
import de.lessvoid.nifty.render.batch.spi.BatchRenderBackend;
|
||||
@ -302,7 +303,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
|
||||
initialData.rewind();
|
||||
modifyTexture(
|
||||
getTextureAtlas(atlasTextureId),
|
||||
new com.jme3.texture.Image(Format.RGBA8, image.getWidth(), image.getHeight(), initialData),
|
||||
new com.jme3.texture.Image(Format.RGBA8, image.getWidth(), image.getHeight(), initialData, ColorSpace.sRGB),
|
||||
x,
|
||||
y);
|
||||
}
|
||||
@ -338,7 +339,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
|
||||
}
|
||||
initialData.rewind();
|
||||
|
||||
Texture2D texture = new Texture2D(new com.jme3.texture.Image(Format.RGBA8, width, height, initialData));
|
||||
Texture2D texture = new Texture2D(new com.jme3.texture.Image(Format.RGBA8, width, height, initialData, ColorSpace.sRGB));
|
||||
texture.setMinFilter(MinFilter.NearestNoMipMaps);
|
||||
texture.setMagFilter(MagFilter.Nearest);
|
||||
return texture;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user