commit
c50f0426bf
@ -0,0 +1,13 @@ |
||||
apply plugin: 'com.android.application' |
||||
|
||||
group = 'com.jme3' |
||||
version = jmeVersion + '-' + jmeVersionTag |
||||
|
||||
sourceCompatibility = '1.6' |
||||
|
||||
repositories { |
||||
mavenCentral() |
||||
maven { |
||||
url "http://nifty-gui.sourceforge.net/nifty-maven-repo" |
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
dependencies { |
||||
compile project(':jme3-core') |
||||
compile project(':jme3-android') |
||||
compile project(':jme3-effects') |
||||
compile project(':jme3-bullet') |
||||
compile project(':jme3-bullet-native-android') |
||||
compile project(':jme3-networking') |
||||
compile project(':jme3-niftygui') |
||||
compile project(':jme3-plugins') |
||||
compile project(':jme3-terrain') |
||||
compile project(':jme3-testdata') |
||||
} |
||||
|
||||
android { |
||||
compileSdkVersion 10 |
||||
buildToolsVersion "22.0.1" |
||||
|
||||
lintOptions { |
||||
// Fix nifty gui referencing "java.awt" package. |
||||
disable 'InvalidPackage' |
||||
} |
||||
|
||||
defaultConfig { |
||||
applicationId "com.jme3.android" |
||||
minSdkVersion 10 // Android 2.3 GINGERBREAD |
||||
targetSdkVersion 22 // Android 5.1 LOLLIPOP |
||||
versionCode 1 |
||||
versionName "1.0" // TODO: from settings.gradle |
||||
} |
||||
|
||||
buildTypes { |
||||
release { |
||||
minifyEnabled false |
||||
} |
||||
debug { |
||||
applicationIdSuffix ".debug" |
||||
debuggable true |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||
package="com.jme3.android"> |
||||
|
||||
<!-- Tell the system that you need ES 2.0. --> |
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" /> |
||||
|
||||
<!-- Tell the system that you need distinct touches (for the zoom gesture). --> |
||||
<uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="true" /> |
||||
|
||||
<application android:label="@string/app_name" android:allowBackup="true"> |
||||
<activity android:name="jme3test.android.TestChooserAndroid" |
||||
android:label="@string/app_name"> |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
</activity> |
||||
</application> |
||||
|
||||
</manifest> |
@ -0,0 +1,12 @@ |
||||
package jme3test.android; |
||||
|
||||
import android.content.pm.ActivityInfo; |
||||
import android.app.*; |
||||
import android.os.Bundle; |
||||
|
||||
public class TestChooserAndroid extends Activity { |
||||
@Override |
||||
public void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
} |
||||
} |
@ -0,0 +1,6 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<string name="app_name">JMEAndroidTest</string> |
||||
<string name="about">About</string> |
||||
<string name="quit">Quit</string> |
||||
</resources> |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@ -0,0 +1,5 @@ |
||||
# When running this project we don't need javadoc to be built. |
||||
buildJavaDoc = false |
||||
|
||||
# We want assertions, because this is the test project. |
||||
assertions = true |
File diff suppressed because it is too large
Load Diff
@ -1,514 +0,0 @@ |
||||
/* |
||||
* 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.renderer.lwjgl; |
||||
|
||||
import com.jme3.renderer.Caps; |
||||
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.EnumSet; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
import static org.lwjgl.opengl.ARBDepthBufferFloat.*; |
||||
import static org.lwjgl.opengl.ARBES3Compatibility.*; |
||||
import static org.lwjgl.opengl.ARBHalfFloatPixel.*; |
||||
import static org.lwjgl.opengl.ARBTextureFloat.*; |
||||
import static org.lwjgl.opengl.ARBTextureMultisample.*; |
||||
import static org.lwjgl.opengl.EXTPackedDepthStencil.*; |
||||
import static org.lwjgl.opengl.EXTPackedFloat.*; |
||||
import static org.lwjgl.opengl.EXTTextureArray.*; |
||||
import static org.lwjgl.opengl.EXTTextureCompressionS3TC.*; |
||||
import static org.lwjgl.opengl.EXTTextureSRGB.*; |
||||
import static org.lwjgl.opengl.EXTTextureSharedExponent.*; |
||||
import static org.lwjgl.opengl.GL11.*; |
||||
import static org.lwjgl.opengl.GL12.*; |
||||
import static org.lwjgl.opengl.GL13.*; |
||||
import static org.lwjgl.opengl.GL14.*; |
||||
|
||||
/** |
||||
* |
||||
* Should not be used, has been replaced by Unified Rendering Architechture. |
||||
* @deprecated |
||||
*/ |
||||
@Deprecated |
||||
class TextureUtil { |
||||
|
||||
static class GLImageFormat { |
||||
|
||||
int internalFormat; |
||||
int format; |
||||
int dataType; |
||||
boolean compressed; |
||||
|
||||
public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed) { |
||||
this.internalFormat = internalFormat; |
||||
this.format = format; |
||||
this.dataType = dataType; |
||||
this.compressed = compressed; |
||||
} |
||||
} |
||||
|
||||
private static final GLImageFormat[] formatToGL = new GLImageFormat[Format.values().length]; |
||||
|
||||
private static void setFormat(Format format, int glInternalFormat, int glFormat, int glDataType, boolean glCompressed){ |
||||
formatToGL[format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, glCompressed); |
||||
} |
||||
|
||||
static { |
||||
// Alpha formats
|
||||
setFormat(Format.Alpha8, GL_ALPHA8, GL_ALPHA, GL_UNSIGNED_BYTE, false); |
||||
|
||||
// Luminance formats
|
||||
setFormat(Format.Luminance8, GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE, false); |
||||
setFormat(Format.Luminance16F, GL_LUMINANCE16F_ARB, GL_LUMINANCE, GL_HALF_FLOAT_ARB, false); |
||||
setFormat(Format.Luminance32F, GL_LUMINANCE32F_ARB, GL_LUMINANCE, GL_FLOAT, false); |
||||
|
||||
// Luminance alpha formats
|
||||
setFormat(Format.Luminance8Alpha8, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, false); |
||||
setFormat(Format.Luminance16FAlpha16F, GL_LUMINANCE_ALPHA16F_ARB, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_ARB, false); |
||||
|
||||
// Depth formats
|
||||
setFormat(Format.Depth, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, false); |
||||
setFormat(Format.Depth16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, false); |
||||
setFormat(Format.Depth24, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false); |
||||
setFormat(Format.Depth32, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false); |
||||
setFormat(Format.Depth32F, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, false); |
||||
|
||||
// Depth stencil formats
|
||||
setFormat(Format.Depth24Stencil8, GL_DEPTH24_STENCIL8_EXT, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, false); |
||||
|
||||
// RGB formats
|
||||
setFormat(Format.BGR8, GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE, false); |
||||
setFormat(Format.ARGB8, GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, false); |
||||
setFormat(Format.BGRA8, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, false); |
||||
setFormat(Format.RGB8, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, false); |
||||
setFormat(Format.RGB16F, GL_RGB16F_ARB, GL_RGB, GL_HALF_FLOAT_ARB, false); |
||||
setFormat(Format.RGB32F, GL_RGB32F_ARB, GL_RGB, GL_FLOAT, false); |
||||
|
||||
// Special RGB formats
|
||||
setFormat(Format.RGB111110F, GL_R11F_G11F_B10F_EXT, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV_EXT, false); |
||||
setFormat(Format.RGB9E5, GL_RGB9_E5_EXT, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV_EXT, false); |
||||
setFormat(Format.RGB16F_to_RGB111110F, GL_R11F_G11F_B10F_EXT, GL_RGB, GL_HALF_FLOAT_ARB, false); |
||||
setFormat(Format.RGB16F_to_RGB9E5, GL_RGB9_E5_EXT, GL_RGB, GL_HALF_FLOAT_ARB, false); |
||||
|
||||
// RGBA formats
|
||||
setFormat(Format.ABGR8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false); |
||||
setFormat(Format.RGB5A1, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, false); |
||||
setFormat(Format.RGBA8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false); |
||||
setFormat(Format.RGBA16F, GL_RGBA16F_ARB, GL_RGBA, GL_HALF_FLOAT_ARB, false); |
||||
setFormat(Format.RGBA32F, GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT, false); |
||||
|
||||
// DXT formats
|
||||
setFormat(Format.DXT1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_BYTE, true); |
||||
setFormat(Format.DXT1A, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); |
||||
setFormat(Format.DXT3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); |
||||
setFormat(Format.DXT5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); |
||||
|
||||
// ETC1 support on regular OpenGL requires ES3 compatibility extension.
|
||||
// NOTE: ETC2 is backwards compatible with ETC1, so we can
|
||||
// upload ETC1 textures as ETC2.
|
||||
setFormat(Format.ETC1, GL_COMPRESSED_RGB8_ETC2, GL_RGB, GL_UNSIGNED_BYTE, true); |
||||
} |
||||
|
||||
//sRGB formats
|
||||
private static final GLImageFormat sRGB_RGB8 = new GLImageFormat(GL_SRGB8_EXT, GL_RGB, GL_UNSIGNED_BYTE, false); |
||||
private static final GLImageFormat sRGB_RGBA8 = new GLImageFormat(GL_SRGB8_ALPHA8_EXT, GL_RGBA, GL_UNSIGNED_BYTE, false); |
||||
private static final GLImageFormat sRGB_Luminance8 = new GLImageFormat(GL_SLUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE, false); |
||||
private static final GLImageFormat sRGB_LuminanceAlpha8 = new GLImageFormat(GL_SLUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, false); |
||||
private static final GLImageFormat sRGB_BGR8 = new GLImageFormat(GL_SRGB8_EXT, GL_BGR, GL_UNSIGNED_BYTE, false); |
||||
private static final GLImageFormat sRGB_ABGR8 = new GLImageFormat(GL_SRGB8_ALPHA8_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false); |
||||
private static final GLImageFormat sRGB_ARGB8 = new GLImageFormat(GL_SRGB8_ALPHA8_EXT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, false); |
||||
private static final GLImageFormat sRGB_BGRA8 = new GLImageFormat(GL_SRGB8_ALPHA8_EXT, GL_BGRA, GL_UNSIGNED_BYTE, false); |
||||
private static final GLImageFormat sRGB_DXT1 = new GLImageFormat(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,GL_RGB, GL_UNSIGNED_BYTE, true); |
||||
private static final GLImageFormat sRGB_DXT1A = new GLImageFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); |
||||
private static final GLImageFormat sRGB_DXT3 = new GLImageFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); |
||||
private static final GLImageFormat sRGB_DXT5 = new GLImageFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); |
||||
|
||||
public static GLImageFormat getImageFormat(EnumSet<Caps> caps, Format fmt, boolean isSrgb){ |
||||
switch (fmt){ |
||||
case ETC1: |
||||
if (!caps.contains(Caps.TextureCompressionETC1)) { |
||||
return null; |
||||
} |
||||
break; |
||||
case DXT1: |
||||
case DXT1A: |
||||
case DXT3: |
||||
case DXT5: |
||||
if (!caps.contains(Caps.TextureCompressionS3TC)) { |
||||
return null; |
||||
} |
||||
break; |
||||
case Depth24Stencil8: |
||||
if (!caps.contains(Caps.PackedDepthStencilBuffer)){ |
||||
return null; |
||||
} |
||||
break; |
||||
case Luminance16F: |
||||
case Luminance16FAlpha16F: |
||||
case Luminance32F: |
||||
case RGB16F: |
||||
case RGB32F: |
||||
case RGBA16F: |
||||
case RGBA32F: |
||||
if (!caps.contains(Caps.FloatTexture)){ |
||||
return null; |
||||
} |
||||
break; |
||||
case Depth32F: |
||||
if (!caps.contains(Caps.FloatDepthBuffer)){ |
||||
return null; |
||||
} |
||||
break; |
||||
case RGB9E5: |
||||
case RGB16F_to_RGB9E5: |
||||
if (!caps.contains(Caps.SharedExponentTexture)){ |
||||
return null; |
||||
} |
||||
break; |
||||
case RGB111110F: |
||||
case RGB16F_to_RGB111110F: |
||||
if (!caps.contains(Caps.PackedFloatTexture)){ |
||||
return null; |
||||
} |
||||
break; |
||||
} |
||||
if (isSrgb) { |
||||
return getSrgbFormat(fmt); |
||||
} else { |
||||
return formatToGL[fmt.ordinal()]; |
||||
} |
||||
} |
||||
|
||||
public static GLImageFormat getImageFormatWithError(EnumSet<Caps> caps, Format fmt, boolean isSrgb) { |
||||
GLImageFormat glFmt = getImageFormat(caps, fmt, isSrgb); |
||||
if (glFmt == null) { |
||||
throw new RendererException("Image format '" + fmt + "' is unsupported by the video hardware."); |
||||
} |
||||
return glFmt; |
||||
} |
||||
|
||||
private static GLImageFormat getSrgbFormat(Format fmt){ |
||||
switch (fmt) { |
||||
case RGB8: |
||||
return sRGB_RGB8; |
||||
case RGBA8: |
||||
return sRGB_RGBA8; |
||||
case BGR8: |
||||
return sRGB_BGR8; |
||||
case ABGR8: |
||||
return sRGB_ABGR8; |
||||
case ARGB8: |
||||
return sRGB_ARGB8; |
||||
case BGRA8: |
||||
return sRGB_BGRA8; |
||||
case Luminance8: |
||||
return sRGB_Luminance8; |
||||
case Luminance8Alpha8: |
||||
return sRGB_LuminanceAlpha8; |
||||
case DXT1: |
||||
return sRGB_DXT1; |
||||
case DXT1A: |
||||
return sRGB_DXT1A; |
||||
case DXT3: |
||||
return sRGB_DXT3; |
||||
case DXT5: |
||||
return sRGB_DXT5; |
||||
default: |
||||
Logger.getLogger(TextureUtil.class.getName()).log(Level.WARNING, "Format {0} has no sRGB equivalent, using linear format.", fmt.toString()); |
||||
return formatToGL[fmt.ordinal()]; |
||||
} |
||||
} |
||||
|
||||
public static void uploadTexture(EnumSet<Caps> caps, |
||||
Image image, |
||||
int target, |
||||
int index, |
||||
int border, |
||||
boolean linearizeSrgb){ |
||||
|
||||
Image.Format fmt = image.getFormat(); |
||||
GLImageFormat glFmt = getImageFormatWithError(caps, fmt, image.getColorSpace() == ColorSpace.sRGB && linearizeSrgb); |
||||
|
||||
ByteBuffer data; |
||||
if (index >= 0 && image.getData() != null && image.getData().size() > 0){ |
||||
data = image.getData(index); |
||||
}else{ |
||||
data = null; |
||||
} |
||||
|
||||
int width = image.getWidth(); |
||||
int height = image.getHeight(); |
||||
int depth = image.getDepth(); |
||||
|
||||
if (data != null) { |
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
||||
} |
||||
|
||||
int[] mipSizes = image.getMipMapSizes(); |
||||
int pos = 0; |
||||
// TODO: Remove unneccessary allocation
|
||||
if (mipSizes == null){ |
||||
if (data != null) |
||||
mipSizes = new int[]{ data.capacity() }; |
||||
else |
||||
mipSizes = new int[]{ width * height * fmt.getBitsPerPixel() / 8 }; |
||||
} |
||||
|
||||
boolean subtex = false; |
||||
int samples = image.getMultiSamples(); |
||||
|
||||
for (int i = 0; i < mipSizes.length; i++){ |
||||
int mipWidth = Math.max(1, width >> i); |
||||
int mipHeight = Math.max(1, height >> i); |
||||
int mipDepth = Math.max(1, depth >> i); |
||||
|
||||
if (data != null){ |
||||
data.position(pos); |
||||
data.limit(pos + mipSizes[i]); |
||||
} |
||||
|
||||
if (glFmt.compressed && data != null){ |
||||
if (target == GL_TEXTURE_3D){ |
||||
glCompressedTexImage3D(target, |
||||
i, |
||||
glFmt.internalFormat, |
||||
mipWidth, |
||||
mipHeight, |
||||
mipDepth, |
||||
border, |
||||
data); |
||||
} else if (target == GL_TEXTURE_2D_ARRAY_EXT) { |
||||
// Upload compressed texture array slice
|
||||
glCompressedTexSubImage3D(target, |
||||
i, |
||||
0, |
||||
0, |
||||
index, |
||||
mipWidth, |
||||
mipHeight, |
||||
1, |
||||
glFmt.internalFormat, |
||||
data); |
||||
}else{ |
||||
//all other targets use 2D: array, cubemap, 2d
|
||||
glCompressedTexImage2D(target, |
||||
i, |
||||
glFmt.internalFormat, |
||||
mipWidth, |
||||
mipHeight, |
||||
border, |
||||
data); |
||||
} |
||||
}else{ |
||||
if (target == GL_TEXTURE_3D){ |
||||
glTexImage3D(target, |
||||
i, |
||||
glFmt.internalFormat, |
||||
mipWidth, |
||||
mipHeight, |
||||
mipDepth, |
||||
border, |
||||
glFmt.format, |
||||
glFmt.dataType, |
||||
data); |
||||
}else if (target == GL_TEXTURE_2D_ARRAY_EXT){ |
||||
// prepare data for 2D array
|
||||
// or upload slice
|
||||
if (index == -1){ |
||||
glTexImage3D(target, |
||||
i, |
||||
glFmt.internalFormat, |
||||
mipWidth, |
||||
mipHeight, |
||||
image.getData().size(), //# of slices
|
||||
border, |
||||
glFmt.format, |
||||
glFmt.dataType, |
||||
data); |
||||
}else{ |
||||
glTexSubImage3D(target, |
||||
i, // level
|
||||
0, // xoffset
|
||||
0, // yoffset
|
||||
index, // zoffset
|
||||
mipWidth, // width
|
||||
mipHeight, // height
|
||||
1, // depth
|
||||
glFmt.format, |
||||
glFmt.dataType, |
||||
data); |
||||
} |
||||
}else{ |
||||
if (subtex){ |
||||
if (samples > 1){ |
||||
throw new IllegalStateException("Cannot update multisample textures"); |
||||
} |
||||
|
||||
glTexSubImage2D(target, |
||||
i, |
||||
0, 0, |
||||
mipWidth, mipHeight, |
||||
glFmt.format, |
||||
glFmt.dataType, |
||||
data); |
||||
}else{ |
||||
if (samples > 1){ |
||||
glTexImage2DMultisample(target, |
||||
samples, |
||||
glFmt.internalFormat, |
||||
mipWidth, |
||||
mipHeight, |
||||
true); |
||||
}else{ |
||||
glTexImage2D(target, |
||||
i, |
||||
glFmt.internalFormat, |
||||
mipWidth, |
||||
mipHeight, |
||||
border, |
||||
glFmt.format, |
||||
glFmt.dataType, |
||||
data); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
pos += mipSizes[i]; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Update the texture currently bound to target at with data from the given Image at position x and y. The parameter |
||||
* index is used as the zoffset in case a 3d texture or texture 2d array is being updated. |
||||
* |
||||
* @param image Image with the source data (this data will be put into the texture) |
||||
* @param target the target texture |
||||
* @param index the mipmap level to update |
||||
* @param x the x position where to put the image in the texture |
||||
* @param y the y position where to put the image in the texture |
||||
*/ |
||||
public static void uploadSubTexture( |
||||
EnumSet<Caps> caps, |
||||
Image image, |
||||
int target, |
||||
int index, |
||||
int x, |
||||
int y, |
||||
boolean linearizeSrgb) { |
||||
Image.Format fmt = image.getFormat(); |
||||
GLImageFormat glFmt = getImageFormatWithError(caps, fmt, image.getColorSpace() == ColorSpace.sRGB && linearizeSrgb); |
||||
|
||||
ByteBuffer data = null; |
||||
if (index >= 0 && image.getData() != null && image.getData().size() > 0) { |
||||
data = image.getData(index); |
||||
} |
||||
|
||||
int width = image.getWidth(); |
||||
int height = image.getHeight(); |
||||
int depth = image.getDepth(); |
||||
|
||||
if (data != null) { |
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
||||
} |
||||
|
||||
int[] mipSizes = image.getMipMapSizes(); |
||||
int pos = 0; |
||||
|
||||
// TODO: Remove unneccessary allocation
|
||||
if (mipSizes == null){ |
||||
if (data != null) { |
||||
mipSizes = new int[]{ data.capacity() }; |
||||
} else { |
||||
mipSizes = new int[]{ width * height * fmt.getBitsPerPixel() / 8 }; |
||||
} |
||||
} |
||||
|
||||
int samples = image.getMultiSamples(); |
||||
|
||||
for (int i = 0; i < mipSizes.length; i++){ |
||||
int mipWidth = Math.max(1, width >> i); |
||||
int mipHeight = Math.max(1, height >> i); |
||||
int mipDepth = Math.max(1, depth >> i); |
||||
|
||||
if (data != null){ |
||||
data.position(pos); |
||||
data.limit(pos + mipSizes[i]); |
||||
} |
||||
|
||||
// to remove the cumbersome if/then/else stuff below we'll update the pos right here and use continue after each
|
||||
// gl*Image call in an attempt to unclutter things a bit
|
||||
pos += mipSizes[i]; |
||||
|
||||
int glFmtInternal = glFmt.internalFormat; |
||||
int glFmtFormat = glFmt.format; |
||||
int glFmtDataType = glFmt.dataType; |
||||
|
||||
if (glFmt.compressed && data != null){ |
||||
if (target == GL_TEXTURE_3D){ |
||||
glCompressedTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtInternal, data); |
||||
continue; |
||||
} |
||||
|
||||
// all other targets use 2D: array, cubemap, 2d
|
||||
glCompressedTexSubImage2D(target, i, x, y, mipWidth, mipHeight, glFmtInternal, data); |
||||
continue; |
||||
} |
||||
|
||||
if (target == GL_TEXTURE_3D){ |
||||
glTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtFormat, glFmtDataType, data); |
||||
continue; |
||||
} |
||||
|
||||
if (target == GL_TEXTURE_2D_ARRAY_EXT){ |
||||
// prepare data for 2D array or upload slice
|
||||
if (index == -1){ |
||||
glTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtFormat, glFmtDataType, data); |
||||
continue; |
||||
} |
||||
|
||||
glTexSubImage3D(target, i, x, y, index, width, height, 1, glFmtFormat, glFmtDataType, data); |
||||
continue; |
||||
} |
||||
|
||||
if (samples > 1){ |
||||
throw new IllegalStateException("Cannot update multisample textures"); |
||||
} |
||||
|
||||
glTexSubImage2D(target, i, x, y, mipWidth, mipHeight, glFmtFormat, glFmtDataType, data); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1 @@ |
||||
sdk.dir=C:\\AndroidSDK |
@ -1,204 +0,0 @@ |
||||
/* |
||||
* To change this template, choose Tools | Templates |
||||
* and open the template in the editor. |
||||
*/ |
||||
package com.jme3.gde.scenecomposer.tools; |
||||
|
||||
import com.jme3.bullet.control.CharacterControl; |
||||
import com.jme3.bullet.control.RigidBodyControl; |
||||
import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; |
||||
import com.jme3.gde.scenecomposer.SceneEditTool; |
||||
import com.jme3.math.FastMath; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.Camera; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import com.jme3.scene.shape.Quad; |
||||
import org.openide.util.lookup.ServiceProvider; |
||||
|
||||
/** |
||||
* |
||||
* @author Nehon |
||||
*/ |
||||
@ServiceProvider(service = MoveManager.class) |
||||
public class MoveManager { |
||||
|
||||
private Vector3f startLoc; |
||||
private Vector3f startWorldLoc; |
||||
private Vector3f lastLoc; |
||||
private Vector3f offset; |
||||
private Node alternativePickTarget = null; |
||||
private Node plane; |
||||
private Spatial spatial; |
||||
protected static final Quaternion XY = new Quaternion().fromAngleAxis(0, new Vector3f(1, 0, 0)); |
||||
protected static final Quaternion YZ = new Quaternion().fromAngleAxis(-FastMath.PI / 2, new Vector3f(0, 1, 0)); |
||||
protected static final Quaternion XZ = new Quaternion().fromAngleAxis(FastMath.PI / 2, new Vector3f(1, 0, 0)); |
||||
//temp vars
|
||||
private Quaternion rot = new Quaternion(); |
||||
private Vector3f newPos = new Vector3f(); |
||||
|
||||
public MoveManager() { |
||||
float size = 1000; |
||||
Geometry g = new Geometry("plane", new Quad(size, size)); |
||||
g.setLocalTranslation(-size / 2, -size / 2, 0); |
||||
plane = new Node(); |
||||
plane.attachChild(g); |
||||
} |
||||
|
||||
public Vector3f getOffset() { |
||||
return offset; |
||||
} |
||||
|
||||
public void reset() { |
||||
offset = null; |
||||
startLoc = null; |
||||
startWorldLoc = null; |
||||
lastLoc = null; |
||||
spatial = null; |
||||
alternativePickTarget = null; |
||||
} |
||||
|
||||
public void initiateMove(Spatial selectedSpatial, Quaternion planeRotation, boolean local) { |
||||
spatial = selectedSpatial; |
||||
startLoc = selectedSpatial.getLocalTranslation().clone(); |
||||
startWorldLoc = selectedSpatial.getWorldTranslation().clone(); |
||||
if (local) { |
||||
rot.set(selectedSpatial.getWorldRotation()); |
||||
plane.setLocalRotation(rot.multLocal(planeRotation)); |
||||
} else { |
||||
rot.set(planeRotation); |
||||
} |
||||
|
||||
plane.setLocalRotation(rot); |
||||
plane.setLocalTranslation(startWorldLoc); |
||||
|
||||
} |
||||
|
||||
public void updatePlaneRotation(Quaternion planeRotation) { |
||||
plane.setLocalRotation(rot); |
||||
} |
||||
|
||||
public boolean move(Camera camera, Vector2f screenCoord) { |
||||
return move(camera, screenCoord, Vector3f.UNIT_XYZ, false); |
||||
} |
||||
|
||||
public boolean move(Camera camera, Vector2f screenCoord, Vector3f constraintAxis, boolean gridSnap) { |
||||
Node toPick = alternativePickTarget == null ? plane : alternativePickTarget; |
||||
|
||||
Vector3f planeHit = SceneEditTool.pickWorldLocation(camera, screenCoord, toPick, alternativePickTarget == null ? null : spatial); |
||||
if (planeHit == null) { |
||||
return false; |
||||
} |
||||
|
||||
Spatial parent = spatial.getParent(); |
||||
//we are moving the root node, there is a slight chance that something went wrong.
|
||||
if (parent == null) { |
||||
return false; |
||||
} |
||||
|
||||
//offset in world space
|
||||
if (offset == null) { |
||||
offset = planeHit.subtract(spatial.getWorldTranslation()); // get the offset when we start so it doesn't jump
|
||||
} |
||||
|
||||
newPos.set(planeHit).subtractLocal(offset); |
||||
|
||||
//constraining the translation with the contraintAxis.
|
||||
Vector3f tmp = startWorldLoc.mult(Vector3f.UNIT_XYZ.subtract(constraintAxis)); |
||||
newPos.multLocal(constraintAxis).addLocal(tmp); |
||||
worldToLocalMove(gridSnap); |
||||
return true; |
||||
} |
||||
|
||||
private void worldToLocalMove(boolean gridSnap) { |
||||
//snap to grid (grid is assumed 1 WU per cell)
|
||||
if (gridSnap) { |
||||
newPos.set(Math.round(newPos.x), Math.round(newPos.y), Math.round(newPos.z)); |
||||
} |
||||
|
||||
//computing the inverse world transform to get the new localtranslation
|
||||
newPos.subtractLocal(spatial.getParent().getWorldTranslation()); |
||||
newPos = spatial.getParent().getWorldRotation().inverse().normalizeLocal().multLocal(newPos); |
||||
newPos.divideLocal(spatial.getParent().getWorldScale()); |
||||
|
||||
lastLoc = newPos; |
||||
spatial.setLocalTranslation(newPos); |
||||
|
||||
RigidBodyControl control = spatial.getControl(RigidBodyControl.class); |
||||
if (control != null) { |
||||
control.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
CharacterControl character = spatial.getControl(CharacterControl.class); |
||||
if (character != null) { |
||||
character.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
} |
||||
|
||||
public boolean moveAcross(Vector3f constraintAxis, float value, boolean gridSnap) { |
||||
newPos.set(startWorldLoc).addLocal(constraintAxis.mult(value)); |
||||
Spatial parent = spatial.getParent(); |
||||
//we are moving the root node, there is a slight chance that something went wrong.
|
||||
if (parent == null) { |
||||
return false; |
||||
} |
||||
worldToLocalMove(gridSnap); |
||||
return true; |
||||
} |
||||
|
||||
public MoveUndo makeUndo() { |
||||
return new MoveUndo(spatial, startLoc, lastLoc); |
||||
} |
||||
|
||||
public void setAlternativePickTarget(Node alternativePickTarget) { |
||||
this.alternativePickTarget = alternativePickTarget; |
||||
} |
||||
|
||||
protected class MoveUndo extends AbstractUndoableSceneEdit { |
||||
|
||||
private Spatial spatial; |
||||
private Vector3f before = new Vector3f(), after = new Vector3f(); |
||||
|
||||
MoveUndo(Spatial spatial, Vector3f before, Vector3f after) { |
||||
this.spatial = spatial; |
||||
this.before.set(before); |
||||
if (after != null) { |
||||
this.after.set(after); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void sceneUndo() { |
||||
spatial.setLocalTranslation(before); |
||||
RigidBodyControl control = spatial.getControl(RigidBodyControl.class); |
||||
if (control != null) { |
||||
control.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
CharacterControl character = spatial.getControl(CharacterControl.class); |
||||
if (character != null) { |
||||
character.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
// toolController.selectedSpatialTransformed();
|
||||
} |
||||
|
||||
@Override |
||||
public void sceneRedo() { |
||||
spatial.setLocalTranslation(after); |
||||
RigidBodyControl control = spatial.getControl(RigidBodyControl.class); |
||||
if (control != null) { |
||||
control.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
CharacterControl character = spatial.getControl(CharacterControl.class); |
||||
if (character != null) { |
||||
character.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
//toolController.selectedSpatialTransformed();
|
||||
} |
||||
|
||||
public void setAfter(Vector3f after) { |
||||
this.after.set(after); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,123 @@ |
||||
/* |
||||
* To change this license header, choose License Headers in Project Properties. |
||||
* To change this template file, choose Tools | Templates |
||||
* and open the template in the editor. |
||||
*/ |
||||
package com.jme3.gde.scenecomposer.tools.shortcuts; |
||||
|
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; |
||||
import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent; |
||||
import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; |
||||
import com.jme3.gde.scenecomposer.SceneComposerToolController; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.event.KeyInputEvent; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import org.openide.loaders.DataObject; |
||||
import org.openide.util.Lookup; |
||||
|
||||
/** |
||||
* |
||||
* @author dokthar |
||||
*/ |
||||
public class DeleteShortcut extends ShortcutTool { |
||||
|
||||
@Override |
||||
public boolean isActivableBy(KeyInputEvent kie) { |
||||
if (kie.getKeyCode() == KeyInput.KEY_X && kie.isPressed()) { |
||||
if (Lookup.getDefault().lookup(ShortcutManager.class).isShiftDown()) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public void cancel() { |
||||
terminate(); |
||||
} |
||||
|
||||
@Override |
||||
public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { |
||||
super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates.
|
||||
hideMarker(); |
||||
if (selectedSpatial != null) { |
||||
delete(); |
||||
} |
||||
terminate(); |
||||
} |
||||
|
||||
private void delete() { |
||||
Spatial selected = toolController.getSelectedSpatial(); |
||||
|
||||
Node parent = selected.getParent(); |
||||
selected.removeFromParent(); |
||||
actionPerformed(new DeleteUndo(selected, parent)); |
||||
|
||||
selected = null; |
||||
toolController.updateSelection(selected); |
||||
|
||||
final JmeNode rootNode = toolController.getRootNode(); |
||||
refreshSelected(rootNode, parent); |
||||
} |
||||
|
||||
private void refreshSelected(final JmeNode jmeRootNode, final Node parent) { |
||||
java.awt.EventQueue.invokeLater(new Runnable() { |
||||
|
||||
@Override |
||||
public void run() { |
||||
jmeRootNode.getChild(parent).refresh(false); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void keyPressed(KeyInputEvent kie) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
} |
||||
|
||||
@Override |
||||
public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
} |
||||
|
||||
@Override |
||||
public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { |
||||
} |
||||
|
||||
@Override |
||||
public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
} |
||||
|
||||
@Override |
||||
public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
} |
||||
|
||||
private class DeleteUndo extends AbstractUndoableSceneEdit { |
||||
|
||||
private Spatial spatial; |
||||
private Node parent; |
||||
|
||||
DeleteUndo(Spatial spatial, Node parent) { |
||||
this.spatial = spatial; |
||||
this.parent = parent; |
||||
} |
||||
|
||||
@Override |
||||
public void sceneUndo() { |
||||
parent.attachChild(spatial); |
||||
} |
||||
|
||||
@Override |
||||
public void sceneRedo() { |
||||
spatial.removeFromParent(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,141 @@ |
||||
/* |
||||
* To change this license header, choose License Headers in Project Properties. |
||||
* To change this template file, choose Tools | Templates |
||||
* and open the template in the editor. |
||||
*/ |
||||
package com.jme3.gde.scenecomposer.tools.shortcuts; |
||||
|
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; |
||||
import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent; |
||||
import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; |
||||
import com.jme3.gde.scenecomposer.SceneComposerToolController; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.event.KeyInputEvent; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import org.openide.loaders.DataObject; |
||||
import org.openide.util.Lookup; |
||||
|
||||
/** |
||||
* |
||||
* @author dokthar |
||||
*/ |
||||
public class DuplicateShortcut extends ShortcutTool { |
||||
|
||||
@Override |
||||
public boolean isActivableBy(KeyInputEvent kie) { |
||||
if (kie.getKeyCode() == KeyInput.KEY_D && kie.isPressed()) { |
||||
if (Lookup.getDefault().lookup(ShortcutManager.class).isShiftDown()) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public void cancel() { |
||||
terminate(); |
||||
} |
||||
|
||||
@Override |
||||
public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { |
||||
super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates.
|
||||
hideMarker(); |
||||
if (selectedSpatial != null) { |
||||
duplicate(); |
||||
terminate(); |
||||
|
||||
//then enable move shortcut
|
||||
toolController.doKeyPressed(new KeyInputEvent(KeyInput.KEY_G, 'g', true, false)); |
||||
} else { |
||||
terminate(); |
||||
} |
||||
} |
||||
|
||||
private void duplicate() { |
||||
Spatial selected = toolController.getSelectedSpatial(); |
||||
|
||||
Spatial clone = selected.clone(); |
||||
clone.move(1, 0, 1); |
||||
|
||||
selected.getParent().attachChild(clone); |
||||
actionPerformed(new DuplicateUndo(clone, selected.getParent())); |
||||
selected = clone; |
||||
final Spatial cloned = clone; |
||||
final JmeNode rootNode = toolController.getRootNode(); |
||||
refreshSelected(rootNode, selected.getParent()); |
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() { |
||||
|
||||
@Override |
||||
public void run() { |
||||
if (cloned != null) { |
||||
SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{rootNode.getChild(cloned)}); |
||||
SceneExplorerTopComponent.findInstance().setSelectedNode(rootNode.getChild(cloned)); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
toolController.updateSelection(selected); |
||||
} |
||||
|
||||
private void refreshSelected(final JmeNode jmeRootNode, final Node parent) { |
||||
java.awt.EventQueue.invokeLater(new Runnable() { |
||||
|
||||
@Override |
||||
public void run() { |
||||
jmeRootNode.getChild(parent).refresh(false); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void keyPressed(KeyInputEvent kie) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
} |
||||
|
||||
@Override |
||||
public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
} |
||||
|
||||
@Override |
||||
public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { |
||||
} |
||||
|
||||
@Override |
||||
public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
} |
||||
|
||||
@Override |
||||
public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
} |
||||
|
||||
private class DuplicateUndo extends AbstractUndoableSceneEdit { |
||||
|
||||
private Spatial spatial; |
||||
private Node parent; |
||||
|
||||
DuplicateUndo(Spatial spatial, Node parent) { |
||||
this.spatial = spatial; |
||||
this.parent = parent; |
||||
} |
||||
|
||||
@Override |
||||
public void sceneUndo() { |
||||
spatial.removeFromParent(); |
||||
} |
||||
|
||||
@Override |
||||
public void sceneRedo() { |
||||
parent.attachChild(spatial); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,227 @@ |
||||
/* |
||||
* To change this license header, choose License Headers in Project Properties. |
||||
* To change this template file, choose Tools | Templates |
||||
* and open the template in the editor. |
||||
*/ |
||||
package com.jme3.gde.scenecomposer.tools.shortcuts; |
||||
|
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.bullet.control.CharacterControl; |
||||
import com.jme3.bullet.control.RigidBodyControl; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; |
||||
import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; |
||||
import com.jme3.gde.scenecomposer.SceneComposerToolController; |
||||
import com.jme3.gde.scenecomposer.tools.PickManager; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.event.KeyInputEvent; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import org.openide.loaders.DataObject; |
||||
import org.openide.util.Lookup; |
||||
|
||||
/** |
||||
* |
||||
* @author dokthar |
||||
*/ |
||||
public class MoveShortcut extends ShortcutTool { |
||||
|
||||
private Vector3f currentAxis; |
||||
private StringBuilder numberBuilder; |
||||
private Spatial spatial; |
||||
private PickManager pickManager; |
||||
private boolean pickEnabled; |
||||
private Vector3f startPosition; |
||||
private Vector3f finalPosition; |
||||
|
||||
@Override |
||||
|
||||
public boolean isActivableBy(KeyInputEvent kie) { |
||||
return kie.getKeyCode() == KeyInput.KEY_G; |
||||
} |
||||
|
||||
@Override |
||||
public void cancel() { |
||||
spatial.setLocalTranslation(startPosition); |
||||
terminate(); |
||||
} |
||||
|
||||
private void apply() { |
||||
actionPerformed(new MoveUndo(toolController.getSelectedSpatial(), startPosition, finalPosition)); |
||||
terminate(); |
||||
} |
||||
|
||||
private void init(Spatial selectedSpatial) { |
||||
spatial = selectedSpatial; |
||||
startPosition = spatial.getLocalTranslation().clone(); |
||||
currentAxis = Vector3f.UNIT_XYZ; |
||||
pickManager = Lookup.getDefault().lookup(PickManager.class); |
||||
pickEnabled = false; |
||||
} |
||||
|
||||
@Override |
||||
public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { |
||||
super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates.
|
||||
hideMarker(); |
||||
numberBuilder = new StringBuilder(); |
||||
if (selectedSpatial == null) { |
||||
terminate(); |
||||
} else { |
||||
init(selectedSpatial); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void keyPressed(KeyInputEvent kie) { |
||||
if (kie.isPressed()) { |
||||
Lookup.getDefault().lookup(ShortcutManager.class).activateShortcut(kie); |
||||
|
||||
Vector3f axis = new Vector3f(); |
||||
boolean axisChanged = ShortcutManager.checkAxisKey(kie, axis); |
||||
if (axisChanged) { |
||||
currentAxis = axis; |
||||
} |
||||
boolean numberChanged = ShortcutManager.checkNumberKey(kie, numberBuilder); |
||||
boolean enterHit = ShortcutManager.checkEnterHit(kie); |
||||
boolean escHit = ShortcutManager.checkEscHit(kie); |
||||
|
||||
if (escHit) { |
||||
cancel(); |
||||
} else if (enterHit) { |
||||
apply(); |
||||
} else if (axisChanged && pickEnabled) { |
||||
//update pick manager
|
||||
|
||||
if (currentAxis.equals(Vector3f.UNIT_X)) { |
||||
pickManager.setTransformation(PickManager.PLANE_XY, getTransformType(), camera); |
||||
} else if (currentAxis.equals(Vector3f.UNIT_Y)) { |
||||
pickManager.setTransformation(PickManager.PLANE_YZ, getTransformType(), camera); |
||||
} else if (currentAxis.equals(Vector3f.UNIT_Z)) { |
||||
pickManager.setTransformation(PickManager.PLANE_XZ, getTransformType(), camera); |
||||
} |
||||
} else if (axisChanged || numberChanged) { |
||||
//update transformation
|
||||
float number = ShortcutManager.getNumberKey(numberBuilder); |
||||
Vector3f translation = currentAxis.mult(number); |
||||
finalPosition = startPosition.add(translation); |
||||
spatial.setLocalTranslation(finalPosition); |
||||
|
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
if (pressed) { |
||||
apply(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
if (pressed) { |
||||
cancel(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { |
||||
|
||||
if (!pickEnabled) { |
||||
if (currentAxis.equals(Vector3f.UNIT_XYZ)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), camera.getRotation(), SceneComposerToolController.TransformationType.camera, camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else if (currentAxis.equals(Vector3f.UNIT_X)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XY, getTransformType(), camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else if (currentAxis.equals(Vector3f.UNIT_Y)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_YZ, getTransformType(), camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else if (currentAxis.equals(Vector3f.UNIT_Z)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XZ, getTransformType(), camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if (pickManager.updatePick(camera, screenCoord)) { |
||||
//pick update success
|
||||
Vector3f diff; |
||||
|
||||
if (currentAxis.equals(Vector3f.UNIT_XYZ)) { |
||||
diff = pickManager.getTranslation(); |
||||
} else { |
||||
diff = pickManager.getTranslation(currentAxis); |
||||
} |
||||
Vector3f position = startPosition.add(diff); |
||||
finalPosition = position; |
||||
toolController.getSelectedSpatial().setLocalTranslation(position); |
||||
updateToolsTransformation(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
if (pressed) { |
||||
apply(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
if (pressed) { |
||||
cancel(); |
||||
} |
||||
} |
||||
|
||||
private class MoveUndo extends AbstractUndoableSceneEdit { |
||||
|
||||
private Spatial spatial; |
||||
private Vector3f before = new Vector3f(), after = new Vector3f(); |
||||
|
||||
MoveUndo(Spatial spatial, Vector3f before, Vector3f after) { |
||||
this.spatial = spatial; |
||||
this.before.set(before); |
||||
if (after != null) { |
||||
this.after.set(after); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void sceneUndo() { |
||||
spatial.setLocalTranslation(before); |
||||
RigidBodyControl control = spatial.getControl(RigidBodyControl.class); |
||||
if (control != null) { |
||||
control.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
CharacterControl character = spatial.getControl(CharacterControl.class); |
||||
if (character != null) { |
||||
character.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
// toolController.selectedSpatialTransformed();
|
||||
} |
||||
|
||||
@Override |
||||
public void sceneRedo() { |
||||
spatial.setLocalTranslation(after); |
||||
RigidBodyControl control = spatial.getControl(RigidBodyControl.class); |
||||
if (control != null) { |
||||
control.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
CharacterControl character = spatial.getControl(CharacterControl.class); |
||||
if (character != null) { |
||||
character.setPhysicsLocation(spatial.getWorldTranslation()); |
||||
} |
||||
//toolController.selectedSpatialTransformed();
|
||||
} |
||||
|
||||
public void setAfter(Vector3f after) { |
||||
this.after.set(after); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,189 @@ |
||||
/* |
||||
* To change this license header, choose License Headers in Project Properties. |
||||
* To change this template file, choose Tools | Templates |
||||
* and open the template in the editor. |
||||
*/ |
||||
package com.jme3.gde.scenecomposer.tools.shortcuts; |
||||
|
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; |
||||
import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; |
||||
import com.jme3.gde.scenecomposer.SceneComposerToolController; |
||||
import com.jme3.gde.scenecomposer.tools.PickManager; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.event.KeyInputEvent; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import org.openide.loaders.DataObject; |
||||
import org.openide.util.Lookup; |
||||
|
||||
/** |
||||
* |
||||
* @author dokthar |
||||
*/ |
||||
public class RotateShortcut extends ShortcutTool { |
||||
|
||||
private Vector3f currentAxis; |
||||
private StringBuilder numberBuilder; |
||||
private Spatial spatial; |
||||
private PickManager pickManager; |
||||
private boolean pickEnabled; |
||||
private Quaternion startRotation; |
||||
private Quaternion finalRotation; |
||||
|
||||
@Override |
||||
|
||||
public boolean isActivableBy(KeyInputEvent kie) { |
||||
return kie.getKeyCode() == KeyInput.KEY_R; |
||||
} |
||||
|
||||
@Override |
||||
public void cancel() { |
||||
spatial.setLocalRotation(startRotation); |
||||
terminate(); |
||||
} |
||||
|
||||
private void apply() { |
||||
actionPerformed(new RotateUndo(toolController.getSelectedSpatial(), startRotation, finalRotation)); |
||||
terminate(); |
||||
} |
||||
|
||||
private void init(Spatial selectedSpatial) { |
||||
spatial = selectedSpatial; |
||||
startRotation = spatial.getLocalRotation().clone(); |
||||
currentAxis = Vector3f.UNIT_XYZ; |
||||
pickManager = Lookup.getDefault().lookup(PickManager.class); |
||||
pickEnabled = false; |
||||
} |
||||
|
||||
@Override |
||||
public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { |
||||
super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates.
|
||||
hideMarker(); |
||||
numberBuilder = new StringBuilder(); |
||||
if (selectedSpatial == null) { |
||||
terminate(); |
||||
} else { |
||||
init(selectedSpatial); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void keyPressed(KeyInputEvent kie) { |
||||
if (kie.isPressed()) { |
||||
Lookup.getDefault().lookup(ShortcutManager.class).activateShortcut(kie); |
||||
|
||||
Vector3f axis = new Vector3f(); |
||||
boolean axisChanged = ShortcutManager.checkAxisKey(kie, axis); |
||||
if (axisChanged) { |
||||
currentAxis = axis; |
||||
} |
||||
boolean numberChanged = ShortcutManager.checkNumberKey(kie, numberBuilder); |
||||
boolean enterHit = ShortcutManager.checkEnterHit(kie); |
||||
boolean escHit = ShortcutManager.checkEscHit(kie); |
||||
|
||||
if (escHit) { |
||||
cancel(); |
||||
} else if (enterHit) { |
||||
apply(); |
||||
} else if (axisChanged && pickEnabled) { |
||||
pickEnabled = false; |
||||
spatial.setLocalRotation(startRotation.clone()); |
||||
} else if (axisChanged || numberChanged) { |
||||
//update transformation
|
||||
/* float number = ShortcutManager.getNumberKey(numberBuilder); |
||||
Vector3f translation = currentAxis.mult(number); |
||||
finalPosition = startPosition.add(translation); |
||||
spatial.setLocalTranslation(finalPosition); |
||||
*/ |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
if (pressed) { |
||||
apply(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
if (pressed) { |
||||
cancel(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { |
||||
|
||||
if (!pickEnabled) { |
||||
if (currentAxis.equals(Vector3f.UNIT_XYZ)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), camera.getRotation(), SceneComposerToolController.TransformationType.camera, camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else if (currentAxis.equals(Vector3f.UNIT_X)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_YZ, getTransformType(), camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else if (currentAxis.equals(Vector3f.UNIT_Y)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XZ, getTransformType(), camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else if (currentAxis.equals(Vector3f.UNIT_Z)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XY, getTransformType(), camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if (pickManager.updatePick(camera, screenCoord)) { |
||||
|
||||
Quaternion rotation = startRotation.mult(pickManager.getRotation(startRotation.inverse())); |
||||
toolController.getSelectedSpatial().setLocalRotation(rotation); |
||||
finalRotation = rotation; |
||||
updateToolsTransformation(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
if (pressed) { |
||||
apply(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
if (pressed) { |
||||
cancel(); |
||||
} |
||||
} |
||||
|
||||
private class RotateUndo extends AbstractUndoableSceneEdit { |
||||
|
||||
private Spatial spatial; |
||||
private Quaternion before, after; |
||||
|
||||
RotateUndo(Spatial spatial, Quaternion before, Quaternion after) { |
||||
this.spatial = spatial; |
||||
this.before = before; |
||||
this.after = after; |
||||
} |
||||
|
||||
@Override |
||||
public void sceneUndo() { |
||||
spatial.setLocalRotation(before); |
||||
toolController.selectedSpatialTransformed(); |
||||
} |
||||
|
||||
@Override |
||||
public void sceneRedo() { |
||||
spatial.setLocalRotation(after); |
||||
toolController.selectedSpatialTransformed(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,199 @@ |
||||
/* |
||||
* To change this license header, choose License Headers in Project Properties. |
||||
* To change this template file, choose Tools | Templates |
||||
* and open the template in the editor. |
||||
*/ |
||||
package com.jme3.gde.scenecomposer.tools.shortcuts; |
||||
|
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; |
||||
import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; |
||||
import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; |
||||
import com.jme3.gde.scenecomposer.SceneComposerToolController; |
||||
import com.jme3.gde.scenecomposer.tools.PickManager; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.event.KeyInputEvent; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import org.openide.loaders.DataObject; |
||||
import org.openide.util.Lookup; |
||||
|
||||
/** |
||||
* |
||||
* @author dokthar |
||||
*/ |
||||
public class ScaleShortcut extends ShortcutTool { |
||||
|
||||
private Vector3f currentAxis; |
||||
private StringBuilder numberBuilder; |
||||
private Spatial spatial; |
||||
private PickManager pickManager; |
||||
private boolean pickEnabled; |
||||
private Vector3f startScale; |
||||
private Vector3f finalScale; |
||||
|
||||
@Override |
||||
|
||||
public boolean isActivableBy(KeyInputEvent kie) { |
||||
return kie.getKeyCode() == KeyInput.KEY_S; |
||||
} |
||||
|
||||
@Override |
||||
public void cancel() { |
||||
spatial.setLocalScale(startScale); |
||||
terminate(); |
||||
} |
||||
|
||||
private void apply() { |
||||
actionPerformed(new ScaleUndo(toolController.getSelectedSpatial(), startScale, finalScale)); |
||||
terminate(); |
||||
} |
||||
|
||||
private void init(Spatial selectedSpatial) { |
||||
spatial = selectedSpatial; |
||||
startScale = spatial.getLocalScale().clone(); |
||||
currentAxis = Vector3f.UNIT_XYZ; |
||||
pickManager = Lookup.getDefault().lookup(PickManager.class); |
||||
pickEnabled = false; |
||||
} |
||||
|
||||
@Override |
||||
public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { |
||||
super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates.
|
||||
hideMarker(); |
||||
numberBuilder = new StringBuilder(); |
||||
if (selectedSpatial == null) { |
||||
terminate(); |
||||
} else { |
||||
init(selectedSpatial); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void keyPressed(KeyInputEvent kie) { |
||||
if (kie.isPressed()) { |
||||
Lookup.getDefault().lookup(ShortcutManager.class).activateShortcut(kie); |
||||
|
||||
Vector3f axis = new Vector3f(); |
||||
boolean axisChanged = ShortcutManager.checkAxisKey(kie, axis); |
||||
if (axisChanged) { |
||||
currentAxis = axis; |
||||
} |
||||
boolean numberChanged = ShortcutManager.checkNumberKey(kie, numberBuilder); |
||||
boolean enterHit = ShortcutManager.checkEnterHit(kie); |
||||
boolean escHit = ShortcutManager.checkEscHit(kie); |
||||
|
||||
if (escHit) { |
||||
cancel(); |
||||
} else if (enterHit) { |
||||
apply(); |
||||
} else if (axisChanged && pickEnabled) { |
||||
pickEnabled = false; |
||||
} else if (axisChanged || numberChanged) { |
||||
//update transformation
|
||||
/* float number = ShortcutManager.getNumberKey(numberBuilder); |
||||
Vector3f translation = currentAxis.mult(number); |
||||
finalPosition = startPosition.add(translation); |
||||
spatial.setLocalTranslation(finalPosition); |
||||
*/ |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
if (pressed) { |
||||
apply(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||
if (pressed) { |
||||
cancel(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { |
||||
|
||||
if (!pickEnabled) { |
||||
if (currentAxis.equals(Vector3f.UNIT_XYZ)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), camera.getRotation(), SceneComposerToolController.TransformationType.camera, camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else if (currentAxis.equals(Vector3f.UNIT_X)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XY, getTransformType(), camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else if (currentAxis.equals(Vector3f.UNIT_Y)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_YZ, getTransformType(), camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else if (currentAxis.equals(Vector3f.UNIT_Z)) { |
||||
pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XZ, getTransformType(), camera, screenCoord); |
||||
pickEnabled = true; |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if (pickManager.updatePick(camera, screenCoord)) { |
||||
Vector3f scale = startScale; |
||||
if (currentAxis.equals(Vector3f.UNIT_XYZ)) { |
||||
Vector3f constraintAxis = pickManager.getStartOffset().normalize(); |
||||
float diff = pickManager.getTranslation(constraintAxis).dot(constraintAxis); |
||||
diff *= 0.5f; |
||||
scale = startScale.add(new Vector3f(diff, diff, diff)); |
||||
} else { |
||||
// Get the translation in the spatial Space
|
||||
Quaternion worldToSpatial = toolController.getSelectedSpatial().getWorldRotation().inverse(); |
||||
Vector3f diff = pickManager.getTranslation(worldToSpatial.mult(currentAxis)); |
||||
diff.multLocal(0.5f); |
||||
scale = startScale.add(diff); |
||||
} |
||||
finalScale = scale; |
||||
toolController.getSelectedSpatial().setLocalScale(scale); |
||||
updateToolsTransformation(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
if (pressed) { |
||||
apply(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||
if (pressed) { |
||||
cancel(); |
||||
} |
||||
} |
||||
|
||||
private class ScaleUndo extends AbstractUndoableSceneEdit { |
||||
|
||||
private Spatial spatial; |
||||
private Vector3f before, after; |
||||
|
||||
ScaleUndo(Spatial spatial, Vector3f before, Vector3f after) { |
||||
this.spatial = spatial; |
||||
this.before = before; |
||||
this.after = after; |
||||
} |
||||
|
||||
@Override |
||||
public void sceneUndo() { |
||||
spatial.setLocalScale(before); |
||||
toolController.selectedSpatialTransformed(); |
||||
} |
||||
|
||||
@Override |
||||
public void sceneRedo() { |
||||
spatial.setLocalScale(after); |
||||
toolController.selectedSpatialTransformed(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,335 @@ |
||||
/* |
||||
* To change this license header, choose License Headers in Project Properties. |
||||
* To change this template file, choose Tools | Templates |
||||
* and open the template in the editor. |
||||
*/ |
||||
package com.jme3.gde.scenecomposer.tools.shortcuts; |
||||
|
||||
import com.jme3.gde.scenecomposer.SceneEditTool; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.event.KeyInputEvent; |
||||
import com.jme3.math.Vector3f; |
||||
import java.util.ArrayList; |
||||
import org.openide.util.Lookup; |
||||
import org.openide.util.lookup.ServiceProvider; |
||||
|
||||
/** |
||||
* |
||||
* @author dokthar |
||||
*/ |
||||
@ServiceProvider(service = ShortcutManager.class) |
||||
public class ShortcutManager { |
||||
|
||||
private ShortcutTool currentShortcut; |
||||
private ArrayList<ShortcutTool> shortcutList; |
||||
private boolean ctrlDown = false; |
||||
private boolean shiftDown = false; |
||||
private boolean altDown = false; |
||||
|
||||
public ShortcutManager() { |
||||
shortcutList = new ArrayList<ShortcutTool>(); |
||||
shortcutList.add(new MoveShortcut()); |
||||
shortcutList.add(new RotateShortcut()); |
||||
shortcutList.add(new ScaleShortcut()); |
||||
shortcutList.add(new DuplicateShortcut()); |
||||
shortcutList.add(new DeleteShortcut()); |
||||
} |
||||
|
||||
/* |
||||
Methodes |
||||
*/ |
||||
/** |
||||
* This MUST be called by the shortcut tool once the modifications are done. |
||||
*/ |
||||
public void terminate() { |
||||
currentShortcut = null; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @return true if a shortCutTool is active, else return false. |
||||
*/ |
||||
public boolean isActive() { |
||||
return currentShortcut != null; |
||||
} |
||||
|
||||
/** |
||||
* @return the ctrlDown |
||||
*/ |
||||
public boolean isCtrlDown() { |
||||
return ctrlDown; |
||||
} |
||||
|
||||
/** |
||||
* @return the shiftDown |
||||
*/ |
||||
public boolean isShiftDown() { |
||||
return shiftDown; |
||||
} |
||||
|
||||
/** |
||||
* @return the altDown |
||||
*/ |
||||
public boolean isAltDown() { |
||||
return altDown; |
||||
} |
||||
|
||||
/** |
||||
* Set the current shortcut to <code>shortcut</code>. cancel the current |
||||
* shortcut if it was still active |
||||
* |
||||
* @param shortcut the ShortCutTool to set |
||||
*/ |
||||
public void setShortCut(ShortcutTool shortcut) { |
||||
if (isActive()) { |
||||
currentShortcut.cancel(); |
||||
} |
||||
currentShortcut = shortcut; |
||||
} |
||||
|
||||
/** |
||||
* Get the shortcut that can be enable with the given kei, the current |
||||
* shortcut cannot be enable twice. This also check for command key used to |
||||
* provide isCtrlDown(), isShiftDown() and isAltDown(). |
||||
* |
||||
* @param kie the KeyInputEvent |
||||
* @return the activable shortcut else return null |
||||
*/ |
||||
public ShortcutTool getActivableShortcut(KeyInputEvent kie) { |
||||
if (checkCommandeKey(kie)) { |
||||
return null; |
||||
} |
||||
for (ShortcutTool s : shortcutList) { |
||||
if (s != currentShortcut) { |
||||
if (s.isActivableBy(kie)) { |
||||
return s; |
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @return the current active shortcut |
||||
*/ |
||||
public ShortcutTool getActiveShortcut() { |
||||
return currentShortcut; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @param kie the KeyInputEvent |
||||
* @return true if the given Kei can enable a sortcut, else false |
||||
*/ |
||||
public boolean canActivateShortcut(KeyInputEvent kie) { |
||||
return getActivableShortcut(kie) != null; |
||||
} |
||||
|
||||
/** |
||||
* Set the current shortcut with the shortcut one that can be enable with |
||||
* the given key |
||||
* |
||||
* @param kie the KeyInputEvent |
||||
* @return true is the shortcut changed, else false |
||||
*/ |
||||
public boolean activateShortcut(KeyInputEvent kie) { |
||||
ShortcutTool newShortcut = getActivableShortcut(kie); |
||||
if (newShortcut != null) { |
||||
currentShortcut = newShortcut; |
||||
} |
||||
return newShortcut != null; |
||||
} |
||||
|
||||
/** |
||||
* This should be called to trigger the currentShortcut.keyPressed() method. |
||||
* This also check for command key used to provide isCtrlDown(), |
||||
* isShiftDown() and isAltDown(). |
||||
* |
||||
* @param kie |
||||
*/ |
||||
public void doKeyPressed(KeyInputEvent kie) { |
||||
if (checkCommandeKey(kie)) { |
||||
//return;
|
||||
} else if (isActive()) { |
||||
currentShortcut.keyPressed(kie); |
||||
} |
||||
} |
||||
|
||||
private boolean checkCommandeKey(KeyInputEvent kie) { |
||||
if (checkCtrlHit(kie)) { |
||||
ctrlDown = kie.isPressed(); |
||||
return true; |
||||
} else if (checkAltHit(kie)) { |
||||
altDown = kie.isPressed(); |
||||
return true; |
||||
} else if (checkShiftHit(kie)) { |
||||
shiftDown = kie.isPressed(); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/* |
||||
STATIC |
||||
*/ |
||||
/** |
||||
* |
||||
* @param kie |
||||
* @return true if the given kie is KEY_RETURN |
||||
*/ |
||||
public static boolean checkEnterHit(KeyInputEvent kie) { |
||||
if (kie.getKeyCode() == KeyInput.KEY_RETURN) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @param kie |
||||
* @return true if the given kie is KEY_ESCAPE |
||||
*/ |
||||
public static boolean checkEscHit(KeyInputEvent kie) { |
||||
if (kie.getKeyCode() == KeyInput.KEY_ESCAPE) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @param kie |
||||
* @return true if the given kie is KEY_LCONTROL || KEY_RCONTROL |
||||
*/ |
||||
public static boolean checkCtrlHit(KeyInputEvent kie) { |
||||
if (kie.getKeyCode() == KeyInput.KEY_LCONTROL || kie.getKeyCode() == KeyInput.KEY_RCONTROL) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @param kie |
||||
* @return true if the given kie is KEY_LSHIFT || KEY_RSHIFT |
||||
*/ |
||||
public static boolean checkShiftHit(KeyInputEvent kie) { |
||||
if (kie.getKeyCode() == KeyInput.KEY_LSHIFT || kie.getKeyCode() == KeyInput.KEY_RSHIFT) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @param kie |
||||
* @return true if the given kie is KEY_LMENU || KEY_RMENU |
||||
*/ |
||||
public static boolean checkAltHit(KeyInputEvent kie) { |
||||
if (kie.getKeyCode() == KeyInput.KEY_LMENU || kie.getKeyCode() == KeyInput.KEY_RMENU) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* store the number kie into the numberBuilder |
||||
* |
||||
* @param kie |
||||
* @param numberBuilder |
||||
* @return true if the given kie is handled as a number key event |
||||
*/ |
||||
public static boolean checkNumberKey(KeyInputEvent kie, StringBuilder numberBuilder) { |
||||
if (kie.getKeyCode() == KeyInput.KEY_MINUS) { |
||||
if (numberBuilder.length() > 0) { |
||||
if (numberBuilder.charAt(0) == '-') { |
||||
numberBuilder.replace(0, 1, ""); |
||||
} else { |
||||
numberBuilder.insert(0, '-'); |
||||
} |
||||
} else { |
||||
numberBuilder.append('-'); |
||||
} |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_0 || kie.getKeyCode() == KeyInput.KEY_NUMPAD0) { |
||||
numberBuilder.append('0'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_1 || kie.getKeyCode() == KeyInput.KEY_NUMPAD1) { |
||||
numberBuilder.append('1'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_2 || kie.getKeyCode() == KeyInput.KEY_NUMPAD2) { |
||||
numberBuilder.append('2'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_3 || kie.getKeyCode() == KeyInput.KEY_NUMPAD3) { |
||||
numberBuilder.append('3'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_4 || kie.getKeyCode() == KeyInput.KEY_NUMPAD4) { |
||||
numberBuilder.append('4'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_5 || kie.getKeyCode() == KeyInput.KEY_NUMPAD5) { |
||||
numberBuilder.append('5'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_6 || kie.getKeyCode() == KeyInput.KEY_NUMPAD6) { |
||||
numberBuilder.append('6'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_7 || kie.getKeyCode() == KeyInput.KEY_NUMPAD7) { |
||||
numberBuilder.append('7'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_8 || kie.getKeyCode() == KeyInput.KEY_NUMPAD8) { |
||||
numberBuilder.append('8'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_9 || kie.getKeyCode() == KeyInput.KEY_NUMPAD9) { |
||||
numberBuilder.append('9'); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_PERIOD) { |
||||
if (numberBuilder.indexOf(".") == -1) { // if it doesn't exist yet
|
||||
if (numberBuilder.length() == 0 |
||||
|| (numberBuilder.length() == 1 && numberBuilder.charAt(0) == '-')) { |
||||
numberBuilder.append("0."); |
||||
} else { |
||||
numberBuilder.append("."); |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @param numberBuilder the StringBuilder storing the float number |
||||
* @return the float value created from the given StringBuilder |
||||
*/ |
||||
public static float getNumberKey(StringBuilder numberBuilder) { |
||||
if (numberBuilder.length() == 0) { |
||||
return 0; |
||||
} else { |
||||
return new Float(numberBuilder.toString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Check for axis input for key X,Y,Z and store the corresponding UNIT_ into |
||||
* the axisStore |
||||
* |
||||
* @param kie |
||||
* @param axisStore |
||||
* @return true if the given kie is handled as a Axis input |
||||
*/ |
||||
public static boolean checkAxisKey(KeyInputEvent kie, Vector3f axisStore) { |
||||
if (kie.getKeyCode() == KeyInput.KEY_X) { |
||||
axisStore.set(Vector3f.UNIT_X); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_Y) { |
||||
axisStore.set(Vector3f.UNIT_Y); |
||||
return true; |
||||
} else if (kie.getKeyCode() == KeyInput.KEY_Z) { |
||||
axisStore.set(Vector3f.UNIT_Z); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,29 @@ |
||||
/* |
||||
* To change this license header, choose License Headers in Project Properties. |
||||
* To change this template file, choose Tools | Templates |
||||
* and open the template in the editor. |
||||
*/ |
||||
package com.jme3.gde.scenecomposer.tools.shortcuts; |
||||
|
||||
import com.jme3.gde.scenecomposer.SceneEditTool; |
||||
import com.jme3.input.event.KeyInputEvent; |
||||
import org.openide.util.Lookup; |
||||
|
||||
/** |
||||
* |
||||
* @author dokthar |
||||
*/ |
||||
public abstract class ShortcutTool extends SceneEditTool { |
||||
|
||||
public abstract boolean isActivableBy(KeyInputEvent kie); |
||||
|
||||
public abstract void cancel(); |
||||
|
||||
protected final void terminate() { |
||||
Lookup.getDefault().lookup(ShortcutManager.class).terminate(); |
||||
} |
||||
|
||||
@Override |
||||
public abstract void keyPressed(KeyInputEvent kie); |
||||
|
||||
} |
Loading…
Reference in new issue