21 Commits
v1.0 ... master

Author SHA1 Message Date
William Hubbard
47a591032b Update README.md
Adds a note on the future of the project.
2022-03-11 22:50:58 +00:00
Markil3
b08fc29734 Updated for the 3.4 release. 2021-10-07 09:11:38 -06:00
Markil3
2adb2a3b87 Enables the features added in https://github.com/Markil3/jmonkeyengine/tree/joyAxisUpdate. 2021-02-26 17:21:37 -07:00
Markil3
c9e0fce4d2 Optimizes the build and prepares for a new version. 2021-02-26 16:47:16 -07:00
Markil3
5e32ac16bb Allows the calibration screen to record ranges.
This will take advantage of changes in 3.4.
2021-02-26 16:17:14 -07:00
Markil3
e5c2828848 Fixes some errors in how joystick positions were calculated. 2021-02-26 16:14:08 -07:00
Markil3
dbb9ee23be Made the default axis value displayed "0.0"
"-1.0" didn't seem right.
2021-02-26 16:11:04 -07:00
Markil3
6a2c444910 Gives the calibrator the option of rendering unused buttons useless.
This prevents them from accidentally interfering with buttons we want.
2021-02-26 11:31:14 -07:00
Markil3
399b5a2b81 Fixes a bug with how the calibrater handled button DPads. 2021-02-26 10:44:43 -07:00
Markil3
0fb384f1a9 Update README.md
Adds an instruction about changing the colors of the buttons.
2020-12-19 01:21:47 +00:00
Markil3
a42d7f4597 Update README.md
Updated the README for version 1.1.0.
2020-12-19 00:58:18 +00:00
Markil3
126a2e844d Adds support for Android 2020-12-18 17:14:16 -07:00
Markil3
8a6487f3bb Provides builds for both LWJGL2 and LWJGL3. 2020-12-18 12:31:25 -07:00
Markil3
d8726a4aa6 Migrated both screens to use the same API, merging both files into the same library. 2020-12-18 11:06:59 -07:00
Markil3
310356b1eb Moves many of the GUI tasks for CalibrateInputScreen to their own class.
I plan on reusing them in JoystickPreviewScreen.
2020-12-18 10:28:11 -07:00
Markil3
e2a8d1304b Removed the Lemur dependency (again).
Again, we want this to be as accessible to users as possible, and not everyone uses Lemur in their game.
2020-12-18 09:51:25 -07:00
Markil3
7ac6b8dd68 Adds a screen that prompts for the inputs needed for calibration.
We needed to add Lemur back in as a dependency in order to properly port this. We'll remove it again in a future commit.
2020-12-17 12:32:53 -07:00
Markil3
bd4242a79b Removes some repositories from the build.
We really didn't need those. Might as well keep it clean.
2020-12-16 09:08:40 -07:00
Markil3
19c57e53b7 Utilizes a new JoystickPreviewScreen that adds a "calibrate" button.
This will allow for extra buttons to be added to the demo application.
2020-12-15 22:50:07 -07:00
Markil3
c860efcfed Cleans up JoystickPreviewScreen a bit. 2020-12-15 22:44:41 -07:00
Markil3
aeef7b2e3f Update README.md 2020-12-14 20:31:53 +00:00
40 changed files with 2700 additions and 353 deletions

6
.gitignore vendored
View File

@@ -18,11 +18,15 @@
*.zip *.zip
*.tar.gz *.tar.gz
*.rar *.rar
*.so
*.dll
/*/*.so
/*/*.dll
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid* hs_err_pid*
/local.properties /local.properties
/build/ /build/
/library/build/ /*/build/
/.idea/ /.idea/
/.gradle/ /.gradle/

View File

@@ -1,8 +1,29 @@
# JMEControllerConfig # JMEControllerConfig
A simple application for JMonkeyEngine-based games that allow for the inclusion of a gamepad view to monitor how exactly the JMonkeyEngine is viewing the gamepad. It can easilly be implemented into any JME3-based application without the need for external dependencies. Derived from jMonkeyEngine's TestJoypad example, this is a simple utility library for JMonkeyEngine-based games that allow for the inclusion of in-game utilities to manage and configure game controllers in your game. The library can easily be implemented into any JME3-based application without the need for additional dependencies besides what you likely already have.
There are two screens included in the library. The JoystickPreviewScreen state will display the controllers currently connected to the computer (and update it as controllers are connected and disconnected on properly configured applications), as well as the values of all their inputs.
The CalibrateInputScreen state will show a series of prompts that will guide users through the process of creating a controller remapping properties file compatible with com.jme3.input.JoystickCompatibilityMappings.
# A message on the future of this project.
*Hello, everyone.*
*Ive recently taken on a new job, and, due to the demands of a full-time developer job, I will no longer be able to maintain this project. Ive had a lot of fun with it, but continuing it for the future is simply unfeasible.*
*With that said, this application is fully open-source, and anyone is available to freely use it, modify it, or maintain their own copy. The only thing I require is that the copyright and license is preserved. I hope that you find this useful.*
*I am archiving the repository at the moment. However, if anyone wishes to take over development, I will be willing to transfer full ownership of the project, copyright and all, to the new maintainer. If there is anyone who wishes to take ownership of this, message [markil3](https://hub.jmonkeyengine.org/u/markil3/summary) on the jmonkey forums and we can discuss it.*
*Thank you all for a great year. May God bless you all,*
*Markil 3*
## Getting started ## Getting started
Download the [latest release build](https://github.com/Markil3/JMEControllerConfig/releases) and store it in your project's library folder. Point your build tool to use the library. Then, ensure that your jMonkey application's settings (com.jme3.system.AppSettings#setUseJoysticks) are set to enable joypad support After that, just attach the markil3.controller.JoystickPreviewScreen to the jMonkey applications state manager to display the gamepad information. Simply detach the state to remove the information. Download the [latest release build](https://github.com/Markil3/JMEControllerConfig/releases) and store it in your project's library folder. Point your build tool to use the library. Then, ensure that your jMonkey application's settings (com.jme3.system.AppSettings#setUseJoysticks) are set to enable joypad support After that, just attach the markil3.controller.JoystickPreviewScreen to the jMonkey applications state manager to display the gamepad information, or attach CalibrateInputScreen with a link to the output file to configure gamepads. Simply detach the state you used to remove the information.
If you need examples as to how to implement these, see the :desktop submodule.
If you wish to change the colors of the buttons, simply change the color values in the markil3.controller.GUIUtils class.
### Requirements ### Requirements
* Java 8+ * Java 8+
@@ -13,7 +34,9 @@ Download the [latest release build](https://github.com/Markil3/JMEControllerConf
* "Interface/Joystick/gamepad-stick.png" from jme3-testdata * "Interface/Joystick/gamepad-stick.png" from jme3-testdata
* jme3-desktop (if running as standalone) * jme3-desktop (if running as standalone)
* jme3-lwjgl3 or jme3-lwjgl (if running as standalone) * jme3-lwjgl3 or jme3-lwjgl (if running as standalone)
* slf4j-api 1.7.15+ * jme3-android (if running on Android)
* jme3-android-natives (if running on Android)
* slf4j-api 1.7.30+
## Building from Source ## Building from Source
To build from source, start by downloading the source from github. If you have the [git command line tool](https://git-scm.com/downloads) installed, the following line will download the git repository from github: To build from source, start by downloading the source from github. If you have the [git command line tool](https://git-scm.com/downloads) installed, the following line will download the git repository from github:
@@ -31,15 +54,11 @@ This will create three .jar files in the library/build/libs directory, one binar
## Testing ## Testing
If you want to test this without implementing it in your software, simply download the source as outlined above and run If you want to test this without implementing it in your software, simply download the source as outlined above and run
<code>gradlew run</code> <code>gradlew desktop:run</code>
This will run a bare-bones version dedicated to the utility. This will run a bare-bones version dedicated to the utility using LWJGL3.
## FAQ Alternatively, you can use the :desktopLegacy subproject for LWJGL2, or the :android subproject for testing on Android.
### Can I use this library in Adroid/iOS?
While I haven't fully tested it out, I foresee no problems. Just be sure to enable joysticks.
Note that on Android at least, the accelerometer is treated as gamepad 0.
## Troubleshooting ## Troubleshooting
@@ -47,7 +66,7 @@ Note that on Android at least, the accelerometer is treated as gamepad 0.
There are two reasons that nothing would show up. First of all, the application state simply may not be attached properly to the state manager. Use a debugger to check this. Second, the application state may not detect any controllers in the com.jme3.input.InputManager#joysticks array. Ensure that your gamepads are connected and are registering in jMonkeyEngine. There are two reasons that nothing would show up. First of all, the application state simply may not be attached properly to the state manager. Use a debugger to check this. Second, the application state may not detect any controllers in the com.jme3.input.InputManager#joysticks array. Ensure that your gamepads are connected and are registering in jMonkeyEngine.
### Every time I disconnect a controller, its entry is still present in the tab bar ### Every time I disconnect a controller, its entry is still present in the tab bar
This is a result of the controller disconnect callback being called before the controller is actually removed from the engine. This is a result of the controller disconnect callback being called before the controller is actually removed from the engine. This is a limitation of the jMonkey API.
### My application crashes every time I attach it! ### My application crashes every time I attach it!
Be sure to enable joystick support in the application settings. Be sure to enable joystick support in the application settings.
@@ -63,3 +82,12 @@ Be sure to enable joystick support in the application settings.
app.setSettings(settings); app.setSettings(settings);
app.start(); app.start();
} }
### Connecting/Pressing some buttons on Android causes crashes
Support for gamepads on Android appear to be a little spotty. This again is a limitation of the jmonkey engine. https://github.com/jMonkeyEngine/jmonkeyengine/issues/1448
### Some buttons show up under two mappings
This is a quirk with some gamepads. At the moment, this can interfere with the automapper. Workarounds are forthcoming.
### The triggers are always active during remapping
Many triggers are set to -1.0 in their default position. This can sometimes cause confusion to the automapper. Workarounds are forthcoming.

1
android/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

59
android/build.gradle Normal file
View File

@@ -0,0 +1,59 @@
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.2'
}
}
apply plugin: 'com.android.application'
repositories {
jcenter()
google()
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "markil3.controller"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
api(project(":library")) {
exclude module: "slf4j-simple"
}
implementation "uk.uuid.slf4j:slf4j-android:1.7.30-0"
implementation "${jme3.g}:jme3-android:${jme3.version}"
implementation "${jme3.g}:jme3-android-native:${jme3.version}"
// implementation rootProject.files('libs/jme3-android.jar')
// implementation rootProject.files('libs/jme3-core.jar')
// implementation rootProject.files('libs/jme3-plugins.jar')
// implementation rootProject.files('libs/jme3-android-native.jar')
implementation "androidx.appcompat:appcompat:1.2.0"
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
}

21
android/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,28 @@
package markil3.controller;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest
{
@Test
public void useAppContext()
{
// Context of the app under test.
Context appContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("markil3.jmecontrollerconfig", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="markil3.jmecontrollerconfig">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.JMEControllerConfig">
<activity
android:name="markil3.controller.MainActivity"
android:configChanges="screenSize|orientation|screenLayout|navigation"
android:screenOrientation="sensorLandscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,276 @@
/*
* Copyright 2020 Markil 3. All rights reserved.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package markil3.controller;
import com.jme3.app.DebugKeysAppState;
import com.jme3.app.SimpleApplication;
import com.jme3.app.StatsAppState;
import com.jme3.font.BitmapText;
import com.jme3.input.JoystickCompatibilityMappings;
import com.jme3.input.controls.ActionListener;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeSystem;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
* Launch point for the application. This is primarily for demo purposes, and
* games using this as a library can safely ignore it.
*
* @author Markil 3
* @version 1.0
*/
public class Main extends SimpleApplication implements ActionListener
{
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.
getLogger(Main.class);
public static File GAME_FOLDER;
public static File CALIBRATION_FILE;
public static File getGameFolder()
{
return GAME_FOLDER;
}
private static void initializeJoystickMappings()
{
if (CALIBRATION_FILE == null)
{
CALIBRATION_FILE =
new File(GAME_FOLDER, "controllerCalibration.properties");
URL mappingUrl;
switch (JmeSystem.getPlatform())
{
case Windows32:
case Windows64:
mappingUrl = Main.class.
getResource("/joystick-mapping.windows.properties");
break;
case MacOSX32:
case MacOSX64:
case MacOSX_PPC32:
case MacOSX_PPC64:
mappingUrl = Main.class.
getResource("/joystick-mapping.osx.properties");
break;
case Linux32:
case Linux64:
case Linux_ARM32:
case Linux_ARM64:
mappingUrl = Main.class.
getResource("/joystick-mapping.linux.properties");
break;
case Android_ARM5:
case Android_ARM6:
case Android_ARM7:
case Android_ARM8:
case Android_X86:
case Android_Other:
mappingUrl = Main.class.
getResource("/joystick-mapping.android.properties");
break;
case iOS_ARM:
case iOS_X86:
mappingUrl = Main.class.
getResource("/joystick-mapping.ios.properties");
break;
default:
mappingUrl = null;
}
if (mappingUrl != null)
{
try
{
JoystickCompatibilityMappings
.loadMappingProperties(mappingUrl);
}
catch (IOException e)
{
logger.error("Unable to load joystick mappings for " +
mappingUrl, e);
}
}
mappingUrl = Main.class.
getResource("/joystick-mapping." +
JmeSystem.getPlatform().toString().toLowerCase() +
".properties");
if (mappingUrl != null)
{
try
{
JoystickCompatibilityMappings
.loadMappingProperties(mappingUrl);
}
catch (IOException e)
{
logger.error("Unable to load joystick mappings for " +
mappingUrl, e);
}
}
if (CALIBRATION_FILE.isFile())
{
try
{
JoystickCompatibilityMappings.loadMappingProperties(
CALIBRATION_FILE.toURI().toURL());
}
catch (IOException e)
{
logger.error("Unable to load joystick mappings.", e);
}
}
}
}
public static void main(String[] args)
{
Main app;
AppSettings settings;
app = new Main();
settings = new AppSettings(true);
settings.setTitle("Joystick Preview");
settings.setUseJoysticks(true);
settings.setEmulateMouse(true);
settings.setVSync(true);
settings.setWidth(1280);
settings.setHeight(720);
app.setSettings(settings);
app.start();
}
private Node calibrateButton;
public Main()
{
super(new StatsAppState(), new DebugKeysAppState(),
new JoystickPreviewScreen());
}
@Override
public void initialize()
{
final File[] possibleGameDirs =
new File[]{new File(System.getProperty("user.dir")),
new File(System.getProperty("user.home")),
JmeSystem.getStorageFolder(
JmeSystem.StorageFolderType.External)};
int i, l;
if (GAME_FOLDER == null)
{
for (i = 0, l = possibleGameDirs.length; i < l; i++)
{
GAME_FOLDER = possibleGameDirs[i];
if (!GAME_FOLDER.isDirectory())
{
if (!GAME_FOLDER.mkdir())
{
logger.warn("Cannot make " + GAME_FOLDER);
continue;
}
}
if (!GAME_FOLDER.canWrite())
{
logger.warn("Cannot write to " + GAME_FOLDER);
continue;
}
break;
}
if (i == l)
{
throw new RuntimeException(
"Could not create game directory folder.");
}
}
/*
* Add custom joystick mappings before the input manager is loaded.
*/
initializeJoystickMappings();
super.initialize();
}
@Override
public void simpleInitApp()
{
this.calibrateButton =
GUIUtils.createButton(this.getAssetManager(), this.guiFont,
this.getContext().getTouchInput() != null, "calibrate",
"Calibrate Gamepad");
}
@Override
public void simpleUpdate(float tpf)
{
JoystickPreviewScreen screen =
this.getStateManager().getState(JoystickPreviewScreen.class);
if (this.calibrateButton.getParent() == null && screen != null)
{
this.guiNode.attachChild(this.calibrateButton);
this.calibrateButton.setLocalTranslation(
(this.getCamera().getWidth() -
((BitmapText) this.calibrateButton.getChild(1))
.getLineWidth() - 10) / 2F,
this.getCamera().getHeight(), 0);
this.inputManager.addListener(this, screen.CLICK_MAPPING);
}
else if (this.calibrateButton.getParent() != null && screen == null)
{
this.guiNode.detachChild(this.calibrateButton);
this.inputManager.removeListener(this);
}
}
@Override
public void onAction(String name, boolean isPressed, float tpf)
{
String buttonId;
JoystickPreviewScreen screen =
this.getStateManager().getState(JoystickPreviewScreen.class);
if (screen != null && name.equals(screen.CLICK_MAPPING))
{
buttonId = GUIUtils.handleButtonPress(this.calibrateButton,
this.getInputManager().getCursorPosition(), isPressed);
if (!isPressed && "calibrate".equals(buttonId))
{
this.getStateManager().detach(screen);
this.getStateManager()
.attach(new CalibrateInputScreen(CALIBRATION_FILE));
}
}
}
@Override
public void restart()
{
super.restart();
this.enqueue(() -> {
JoystickPreviewScreen previewScreen = this.getStateManager()
.getState(JoystickPreviewScreen.class);
CalibrateInputScreen calibrateScreen =
this.getStateManager().getState(CalibrateInputScreen.class);
if (previewScreen != null)
{
previewScreen.resize();
}
if (calibrateScreen != null)
{
calibrateScreen.resize();
}
this.calibrateButton.setLocalTranslation(
(this.getCamera().getWidth() -
((BitmapText) this.calibrateButton.getChild(1))
.getLineWidth() - 10) / 2F,
this.getCamera().getHeight(), 0);
});
}
}

View File

@@ -0,0 +1,71 @@
package markil3.controller;
import android.os.Bundle;
import com.jme3.app.AndroidHarness;
import java.util.logging.Level;
import java.util.logging.LogManager;
public class MainActivity extends AndroidHarness
{
/*
* Note that you can ignore the errors displayed in this file, the android
* project will build regardless. Install the 'Android' plugin under
* Tools->Plugins->Available Plugins to get error checks and code completion
* for the Android project files.
*/
public MainActivity()
{
/*
* Set the default logging level (default=Level.INFO, Level.ALL=All
* Debug Info)
*/
LogManager.getLogManager().getLogger("").setLevel(Level.INFO);
this.appClass = Main.class.getName();
// Set the desired EGL configuration
eglBitsPerPixel = 24;
eglAlphaBits = 0;
eglDepthBits = 16;
eglSamples = 0;
eglStencilBits = 0;
// Set the maximum framerate
// (default = -1 for unlimited)
frameRate = -1;
// Set the maximum resolution dimension
// (the smaller side, height or width, is set automatically
// to maintain the original device screen aspect ratio)
// (default = -1 to match device screen resolution)
// maxResolutionDimension = -1;
// Set input configuration settings
joystickEventsEnabled = true;
keyEventsEnabled = true;
mouseEventsEnabled = true;
// Set application exit settings
finishOnAppStop = true;
handleExitHook = false;
exitDialogTitle = "Do you want to exit?";
exitDialogMessage =
"Use your home key to bring this app into the background " +
"or exit to terminate it.";
// Set splash screen resource id, if used
// (default = 0, no splash screen)
// For example, if the image file name is "splash"...
// splashPicID = R.drawable.splash;
splashPicID = 0;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setImmersive(true);
}
}

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,10 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.JMEControllerConfig" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryDark">@color/purple_700</item>
<item name="colorAccent">@color/teal_200</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">JMEControllerConfig</string>
</resources>

View File

@@ -0,0 +1,10 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.JMEControllerConfig" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryDark">@color/purple_700</item>
<item name="colorAccent">@color/teal_200</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -0,0 +1,19 @@
package markil3.controller;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest
{
@Test
public void addition_isCorrect()
{
assertEquals(4, 2 + 2);
}
}

View File

@@ -8,115 +8,24 @@
* limitations under the License. * limitations under the License.
*/ */
import org.apache.tools.ant.taskdefs.condition.Os ext {
jme3 = [version: '3.4.0-stable', g: 'org.jmonkeyengine']
versionNumber = 2
}
version = "1.2"
import java.nio.file.Files task run {
doFirst {
print "WARNING: This project has two methods of execution: with LWJGL 2 and with LWJGL 3. Run the task desktopLegacy:run for the former and desktop:run for the latter."
}
}
buildscript { allprojects {
repositories { repositories {
jcenter() jcenter()
google() maven {
url "https://dl.bintray.com/jmonkeyengine/org.jmonkeyengine"
}
} }
} }
plugins {
id "application"
id "distribution"
id "com.github.johnrengelman.shadow" version "5.0.0"
id "edu.sc.seis.launch4j" version "2.4.5"
id "edu.sc.seis.macAppBundle" version "2.3.0"
}
repositories {
google()
jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
maven {
url "https://dl.bintray.com/jmonkeyengine/org.jmonkeyengine"
}
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
ext {
jme3 = [version: '3.3.2-stable', g: 'org.jmonkeyengine']
versionNumber = 3
}
dependencies {
// Logging
implementation "org.slf4j:slf4j-api:1.7.15"
implementation "org.slf4j:slf4j-simple:1.7.5"
implementation project(':library')
implementation "${jme3.g}:jme3-core:${jme3.version}"
implementation "${jme3.g}:jme3-desktop:${jme3.version}"
implementation "${jme3.g}:jme3-lwjgl3:${jme3.version}"
}
// Define the main class for the application
mainClassName = 'markil3.controller.Main'
version = "1.0"
versionNumber = 1
processResources {
from (".") {
include "LICENSE"
include "JME3-LICENSE"
}
}
/*
* TODO - The default zipped distributions are a bit of a mess.
*/
jar {
baseName rootProject.name
version rootProject.version
manifest {
attributes "Main-Class": mainClassName,
"Class-Path": configurations.runtime.files.collect {
"lib/$it.name"
}.join(" "),
"Implementation-Title": rootProject.name,
"Implementation-Version": rootProject.version,
"Version-Code": versionNumber
}
}
shadowJar {
archivesBaseName = rootProject.name
archiveClassifier = "universal"
version = rootProject.version
mainClassName = project.mainClassName
}
launch4j {
mainClassName = project.mainClassName
outfile = rootProject.name + "-" + project.version + "-windows.exe"
copyConfigurable = shadowJar.outputs.files
jar = shadowJar.getArchiveFile()
bundledJrePath = "jre"
//icon = new File(sourceSets.main.resources.srcDirs[0], "icon256.ico")
}
createExe.doLast({
println project.tasks.installDist.outputs.files.getClass()
for (file in new File(installDist.outputs.files[0], "lib").listFiles()) {
println file
}
})
macAppBundle {
mainClassName = project.mainClassName
icon = "myIcon.icns"
if (Os.isFamily(Os.FAMILY_MAC) && (appStyle == 'Oracle' || appStyle == 'universalJavaApplicationStub')) {
bundleJRE = true
}
javaProperties.put("apple.laf.useScreenMenuBar", "true")
backgroundImage = "doc/macbackground.png"
jarTask = "shadowJar"
}

112
desktop/build.gradle Normal file
View File

@@ -0,0 +1,112 @@
/*
* Copyright 2020 Markil 3. All rights reserved.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.tools.ant.taskdefs.condition.Os
plugins {
id "application"
id "distribution"
id "com.github.johnrengelman.shadow" version "5.0.0"
id "edu.sc.seis.launch4j" version "2.4.5"
id "edu.sc.seis.macAppBundle" version "2.3.0"
}
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
//def lwjglVersion = '3.2.3'
dependencies {
// Logging
implementation "org.slf4j:slf4j-api:1.7.30"
implementation "org.slf4j:slf4j-simple:1.7.5"
implementation project(':library')
implementation "${jme3.g}:jme3-core:${jme3.version}"
implementation "${jme3.g}:jme3-desktop:${jme3.version}"
implementation "${jme3.g}:jme3-lwjgl3:${jme3.version}"
// implementation rootProject.files('libs/jme3-core.jar')
// implementation rootProject.files('libs/jme3-desktop.jar')
// implementation rootProject.files('libs/jme3-lwjgl3.jar')
// implementation "org.lwjgl:lwjgl:${lwjglVersion}"
// implementation "org.lwjgl:lwjgl-glfw:${lwjglVersion}"
// implementation "org.lwjgl:lwjgl-jemalloc:${lwjglVersion}"
// implementation "org.lwjgl:lwjgl-openal:${lwjglVersion}"
// implementation "org.lwjgl:lwjgl-opencl:${lwjglVersion}"
// implementation "org.lwjgl:lwjgl-opengl:${lwjglVersion}"
// runtime "org.lwjgl:lwjgl:${lwjglVersion}:natives-windows"
// runtime "org.lwjgl:lwjgl:${lwjglVersion}:natives-linux"
// runtime "org.lwjgl:lwjgl:${lwjglVersion}:natives-macos"
// runtime "org.lwjgl:lwjgl-glfw:${lwjglVersion}:natives-windows"
// runtime "org.lwjgl:lwjgl-glfw:${lwjglVersion}:natives-linux"
// runtime "org.lwjgl:lwjgl-glfw:${lwjglVersion}:natives-macos"
// runtime "org.lwjgl:lwjgl-jemalloc:${lwjglVersion}:natives-windows"
// runtime "org.lwjgl:lwjgl-jemalloc:${lwjglVersion}:natives-linux"
// runtime "org.lwjgl:lwjgl-jemalloc:${lwjglVersion}:natives-macos"
// runtime "org.lwjgl:lwjgl-opengl:${lwjglVersion}:natives-windows"
// runtime "org.lwjgl:lwjgl-opengl:${lwjglVersion}:natives-linux"
// runtime "org.lwjgl:lwjgl-opengl:${lwjglVersion}:natives-macos"
// runtime "org.lwjgl:lwjgl-openal:${lwjglVersion}:natives-windows"
// runtime "org.lwjgl:lwjgl-openal:${lwjglVersion}:natives-linux"
// runtime "org.lwjgl:lwjgl-openal:${lwjglVersion}:natives-macos"
}
// Define the main class for the application
mainClassName = 'markil3.controller.Main'
/*
* TODO - The default zipped distributions are a bit of a mess.
*/
jar {
baseName rootProject.name + "-desktop"
version rootProject.version
manifest {
attributes "Main-Class": mainClassName,
"Class-Path": configurations.runtime.files.collect {
"lib/$it.name"
}.join(" "),
"Implementation-Title": rootProject.name,
"Implementation-Version": rootProject.version,
"Version-Code": versionNumber
}
}
shadowJar {
archivesBaseName = rootProject.name
archiveClassifier = "universal-lwjgl3"
version = rootProject.version
mainClassName = project.mainClassName
}
launch4j {
mainClassName = project.mainClassName
outfile = rootProject.name + "-" + rootProject.version + "-windows-lwjgl3.exe"
copyConfigurable = shadowJar.outputs.files
jar = shadowJar.archiveFile.get()
bundledJrePath = "jre"
//icon = new File(sourceSets.main.resources.srcDirs[0], "icon256.ico")
}
createExe.doLast({
println project.tasks.installDist.outputs.files.getClass()
for (file in new File(installDist.outputs.files[0], "lib").listFiles()) {
println file
}
})
macAppBundle {
mainClassName = project.mainClassName
icon = "myIcon.icns"
if (Os.isFamily(Os.FAMILY_MAC) && (appStyle == 'Oracle' || appStyle == 'universalJavaApplicationStub')) {
bundleJRE = true
}
javaProperties.put("apple.laf.useScreenMenuBar", "true")
backgroundImage = "doc/macbackground.png"
jarTask = "shadowJar"
}

View File

@@ -0,0 +1,276 @@
/*
* Copyright 2020 Markil 3. All rights reserved.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package markil3.controller;
import com.jme3.app.DebugKeysAppState;
import com.jme3.app.SimpleApplication;
import com.jme3.app.StatsAppState;
import com.jme3.font.BitmapText;
import com.jme3.input.JoystickCompatibilityMappings;
import com.jme3.input.controls.ActionListener;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeSystem;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
* Launch point for the application. This is primarily for demo purposes, and
* games using this as a library can safely ignore it.
*
* @author Markil 3
* @version 1.0
*/
public class Main extends SimpleApplication implements ActionListener
{
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.
getLogger(Main.class);
public static File GAME_FOLDER;
public static File CALIBRATION_FILE;
public static File getGameFolder()
{
return GAME_FOLDER;
}
private static void initializeJoystickMappings()
{
if (CALIBRATION_FILE == null)
{
CALIBRATION_FILE =
new File(GAME_FOLDER, "controllerCalibration.properties");
URL mappingUrl;
switch (JmeSystem.getPlatform())
{
case Windows32:
case Windows64:
mappingUrl = Main.class.
getResource("/joystick-mapping.windows.properties");
break;
case MacOSX32:
case MacOSX64:
case MacOSX_PPC32:
case MacOSX_PPC64:
mappingUrl = Main.class.
getResource("/joystick-mapping.osx.properties");
break;
case Linux32:
case Linux64:
case Linux_ARM32:
case Linux_ARM64:
mappingUrl = Main.class.
getResource("/joystick-mapping.linux.properties");
break;
case Android_ARM5:
case Android_ARM6:
case Android_ARM7:
case Android_ARM8:
case Android_X86:
case Android_Other:
mappingUrl = Main.class.
getResource("/joystick-mapping.android.properties");
break;
case iOS_ARM:
case iOS_X86:
mappingUrl = Main.class.
getResource("/joystick-mapping.ios.properties");
break;
default:
mappingUrl = null;
}
if (mappingUrl != null)
{
try
{
JoystickCompatibilityMappings
.loadMappingProperties(mappingUrl);
}
catch (IOException e)
{
logger.error("Unable to load joystick mappings for " +
mappingUrl, e);
}
}
mappingUrl = Main.class.
getResource("/joystick-mapping." +
JmeSystem.getPlatform().toString().toLowerCase() +
".properties");
if (mappingUrl != null)
{
try
{
JoystickCompatibilityMappings
.loadMappingProperties(mappingUrl);
}
catch (IOException e)
{
logger.error("Unable to load joystick mappings for " +
mappingUrl, e);
}
}
if (CALIBRATION_FILE.isFile())
{
try
{
JoystickCompatibilityMappings.loadMappingProperties(
CALIBRATION_FILE.toURI().toURL());
}
catch (IOException e)
{
logger.error("Unable to load joystick mappings.", e);
}
}
}
}
public static void main(String[] args)
{
Main app;
AppSettings settings;
app = new Main();
settings = new AppSettings(true);
settings.setTitle("Joystick Preview");
settings.setUseJoysticks(true);
settings.setEmulateMouse(true);
settings.setVSync(true);
settings.setWidth(1280);
settings.setHeight(720);
app.setSettings(settings);
app.start();
}
private Node calibrateButton;
public Main()
{
super(new StatsAppState(), new DebugKeysAppState(),
new JoystickPreviewScreen());
}
@Override
public void initialize()
{
final File[] possibleGameDirs =
new File[]{new File(System.getProperty("user.dir")),
new File(System.getProperty("user.home")),
JmeSystem.getStorageFolder(
JmeSystem.StorageFolderType.External)};
int i, l;
if (GAME_FOLDER == null)
{
for (i = 0, l = possibleGameDirs.length; i < l; i++)
{
GAME_FOLDER = possibleGameDirs[i];
if (!GAME_FOLDER.isDirectory())
{
if (!GAME_FOLDER.mkdir())
{
logger.warn("Cannot make " + GAME_FOLDER);
continue;
}
}
if (!GAME_FOLDER.canWrite())
{
logger.warn("Cannot write to " + GAME_FOLDER);
continue;
}
break;
}
if (i == l)
{
throw new RuntimeException(
"Could not create game directory folder.");
}
}
/*
* Add custom joystick mappings before the input manager is loaded.
*/
initializeJoystickMappings();
super.initialize();
}
@Override
public void simpleInitApp()
{
this.calibrateButton =
GUIUtils.createButton(this.getAssetManager(), this.guiFont,
this.getContext().getTouchInput() != null, "calibrate",
"Calibrate Gamepad");
}
@Override
public void simpleUpdate(float tpf)
{
JoystickPreviewScreen screen =
this.getStateManager().getState(JoystickPreviewScreen.class);
if (this.calibrateButton.getParent() == null && screen != null)
{
this.guiNode.attachChild(this.calibrateButton);
this.calibrateButton.setLocalTranslation(
(this.getCamera().getWidth() -
((BitmapText) this.calibrateButton.getChild(1))
.getLineWidth() - 10) / 2F,
this.getCamera().getHeight(), 0);
this.inputManager.addListener(this, screen.CLICK_MAPPING);
}
else if (this.calibrateButton.getParent() != null && screen == null)
{
this.guiNode.detachChild(this.calibrateButton);
this.inputManager.removeListener(this);
}
}
@Override
public void onAction(String name, boolean isPressed, float tpf)
{
String buttonId;
JoystickPreviewScreen screen =
this.getStateManager().getState(JoystickPreviewScreen.class);
if (screen != null && name.equals(screen.CLICK_MAPPING))
{
buttonId = GUIUtils.handleButtonPress(this.calibrateButton,
this.getInputManager().getCursorPosition(), isPressed);
if (!isPressed && "calibrate".equals(buttonId))
{
this.getStateManager().detach(screen);
this.getStateManager()
.attach(new CalibrateInputScreen(CALIBRATION_FILE));
}
}
}
@Override
public void restart()
{
super.restart();
this.enqueue(() -> {
JoystickPreviewScreen previewScreen = this.getStateManager()
.getState(JoystickPreviewScreen.class);
CalibrateInputScreen calibrateScreen =
this.getStateManager().getState(CalibrateInputScreen.class);
if (previewScreen != null)
{
previewScreen.resize();
}
if (calibrateScreen != null)
{
calibrateScreen.resize();
}
this.calibrateButton.setLocalTranslation(
(this.getCamera().getWidth() -
((BitmapText) this.calibrateButton.getChild(1))
.getLineWidth() - 10) / 2F,
this.getCamera().getHeight(), 0);
});
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2020 Markil 3. All rights reserved.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.tools.ant.taskdefs.condition.Os
plugins {
id "application"
id "distribution"
id "com.github.johnrengelman.shadow" version "5.0.0"
id "edu.sc.seis.launch4j" version "2.4.5"
id "edu.sc.seis.macAppBundle" version "2.3.0"
}
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
dependencies {
implementation(project(':desktop')) {
exclude module: "jme3-lwjgl3"
exclude group: "org.lwjgl"
}
implementation "${jme3.g}:jme3-lwjgl:${jme3.version}"
// implementation rootProject.files('libs/jme3-lwjgl.jar')
// implementation 'org.lwjgl.lwjgl:lwjgl:2.9.3'
// /*
// * Upgrades the default jinput-2.0.5 to jinput-2.0.9 to fix a bug with gamepads on Linux.
// * See https://hub.jmonkeyengine.org/t/linux-gamepad-input-on-jme3-lwjgl-splits-input-between-two-logical-gamepads
// */
// implementation 'net.java.jinput:jinput:2.0.9'
// implementation 'net.java.jinput:jinput:2.0.9:natives-all'
}
// Define the main class for the application
mainClassName = 'markil3.controller.Main'
/*
* TODO - The default zipped distributions are a bit of a mess.
*/
jar {
baseName rootProject.name
version rootProject.version
manifest {
attributes "Main-Class": mainClassName,
"Class-Path": configurations.runtime.files.collect {
"lib/$it.name"
}.join(" "),
"Implementation-Title": rootProject.name,
"Implementation-Version": rootProject.version,
"Version-Code": versionNumber
}
}
shadowJar {
archivesBaseName = rootProject.name
archiveClassifier = "universal-lwjgl2"
version = rootProject.version
mainClassName = project.mainClassName
}
launch4j {
mainClassName = project.mainClassName
outfile = rootProject.name + "-" + rootProject.version + "-windows-lwjgl2.exe"
copyConfigurable = shadowJar.outputs.files
jar = shadowJar.archiveFile.get()
bundledJrePath = "jre"
//icon = new File(sourceSets.main.resources.srcDirs[0], "icon256.ico")
}
createExe.doLast({
println project.tasks.installDist.outputs.files.getClass()
for (file in new File(installDist.outputs.files[0], "lib").listFiles()) {
println file
}
})
macAppBundle {
mainClassName = project.mainClassName
icon = "myIcon.icns"
if (Os.isFamily(Os.FAMILY_MAC) && (appStyle == 'Oracle' || appStyle == 'universalJavaApplicationStub')) {
bundleJRE = true
}
javaProperties.put("apple.laf.useScreenMenuBar", "true")
backgroundImage = "doc/macbackground.png"
jarTask = "shadowJar"
}

15
gradle.properties Normal file
View File

@@ -0,0 +1,15 @@
## For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
#
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx1024m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Fri Dec 18 13:35:19 MST 2020
android.enableJetifier=true
android.useAndroidX=true

View File

@@ -8,46 +8,27 @@
* limitations under the License. * limitations under the License.
*/ */
import org.apache.tools.ant.taskdefs.condition.Os
import java.nio.file.Files
buildscript {
repositories {
jcenter()
google()
}
}
plugins { plugins {
id "java-library" id "java-library"
} }
repositories {
google()
jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
maven {
url "https://dl.bintray.com/jmonkeyengine/org.jmonkeyengine"
}
}
sourceCompatibility = "1.8" sourceCompatibility = "1.8"
targetCompatibility = "1.8" targetCompatibility = "1.8"
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8' [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
dependencies { dependencies {
// Logging // Logging
implementation "org.slf4j:slf4j-api:1.7.15" implementation "org.slf4j:slf4j-api:1.7.30"
implementation "org.slf4j:slf4j-simple:1.7.5" implementation "org.slf4j:slf4j-simple:1.7.5"
implementation "${jme3.g}:jme3-core:${jme3.version}" implementation "${jme3.g}:jme3-core:${jme3.version}"
implementation "${jme3.g}:jme3-testdata:${jme3.version}" implementation "${jme3.g}:jme3-testdata:${jme3.version}"
// implementation rootProject.files('libs/jme3-core.jar')
// implementation rootProject.files('libs/jme3-testdata.jar')
} }
processResources { processResources {
from ("..") { from(".") {
include "LICENSE" include "LICENSE"
include "JME3-LICENSE" include "JME3-LICENSE"
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,206 @@
package markil3.controller;
import com.jme3.asset.AssetManager;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.font.Rectangle;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Quad;
/**
* A collection of utility methods for the screens used here.
* @author Markil 3
* @version 1.1
*/
public class GUIUtils
{
/**
* The color that a button takes on when the mouse is down on it. Feel
* free to change it to suit your needs.
*/
static ColorRGBA BUTTON_COLOR_ON = new ColorRGBA(0F, 0.1F, 0F, 1F);
/**
* The default color that a button. Feel free to change it to suit your
* needs.
*/
static ColorRGBA BUTTON_COLOR_OFF = new ColorRGBA(0F, 0.75F, 0.25F, 1F);
private static final String BUTTON_ID = "button";
/**
* Creates a button. This button will have special user data fields that
* can be detected by {@link #handleButtonPress(Node, Vector2f, boolean)}
* to trigger events.
* @param assets - The application asset manager.
* @param guiFont - The font to use for the button.
* @param isMobile - Whether or not the mobile size increase should be used.
* @param id - The button ID. This is used to identify which button was
* pressed later on.
* @param content - The text that will display in the button.
* @return A node containing the button elements.
*/
public static Node createButton(AssetManager assets, BitmapFont guiFont,
boolean isMobile, String id, String content)
{
final float MOBILE_SIZE = 30F;
BitmapText buttonText;
Geometry buttonBackground;
Node button = new Node();
buttonText = guiFont.createLabel(content);
if (isMobile)
{
buttonText.setSize(MOBILE_SIZE);
}
buttonText.setUserData(BUTTON_ID, id);
buttonText.setBox(new Rectangle(0, 0, buttonText.getLineWidth(),
buttonText.getLineHeight()));
buttonText.setAlignment(BitmapFont.Align.Center);
buttonText.setVerticalAlignment(BitmapFont.VAlign.Center);
buttonBackground = new Geometry("button-" + id,
new Quad(buttonText.getLineWidth() + 10,
buttonText.getHeight() + 5));
buttonBackground.setMaterial(
new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md"));
buttonBackground.getMaterial().setColor("Color", BUTTON_COLOR_OFF);
buttonBackground.setUserData(BUTTON_ID, id);
buttonBackground
.setLocalTranslation(-2.5F, -buttonText.getLineHeight() - 2.5F,
0);
button.setUserData(BUTTON_ID, id);
button.attachChild(buttonBackground);
button.attachChild(buttonText);
return button;
}
/**
* Call this method from a mouse listener to search the provided node for
* any buttons created with
* {@link #createButton(AssetManager, BitmapFont, boolean, String, String)} and
* returns their ID.
* @param gui - The GUI to search.
* @param cursor - The position of the mouse cursor.
* @param isPressed - Whether or not the cursor is pressed. This will
* change how the button is displayed.
* @return The ID of the button that was clicked, or null if none were
* clicked.
*/
public static String handleButtonPress(Node gui, Vector2f cursor,
boolean isPressed)
{
final String KEY_CURRENT = "currentButton";
CollisionResults results;
Ray ray;
Geometry button;
String buttonId = null;
/*
* We generally mark buttons on mouse down, and trigger that same
* button on release. If we haven't even marked a button by the time
* we release the mouse, we just won't bother.
*/
if (!isPressed)
{
button = gui.getUserData(KEY_CURRENT);
if (button == null)
{
return null;
}
}
results = new CollisionResults();
ray = new Ray(new Vector3f(cursor.x, cursor.y, 0),
new Vector3f(0, 0, 1));
gui.collideWith(ray, results);
for (CollisionResult result : results)
{
button = result.getGeometry();
buttonId = button.getUserData(BUTTON_ID);
if (buttonId != null)
{
if (isPressed)
{
/*
* Trigger the press graphic
*/
button.getMaterial().setColor("Color", BUTTON_COLOR_ON);
gui.setUserData(KEY_CURRENT, button);
break;
}
else
{
/*
* If the button we released isn't the same as the button
* we originally pressed, don't trigger either.
*/
button = gui.getUserData(KEY_CURRENT);
if (button != null)
{
if (button.getUserData(BUTTON_ID).equals(buttonId))
{
break;
}
else
{
buttonId = null;
}
}
}
}
}
if (!isPressed)
{
/*
* Make sure the originally-clicked button was reset.
*/
button = gui.getUserData(KEY_CURRENT);
if (button != null)
{
button.getMaterial().setColor("Color", BUTTON_COLOR_OFF);
gui.setUserData(KEY_CURRENT, null);
}
}
return buttonId;
}
/**
* Aligns the contents in a container so that all {@link BitmapText} and
* button elements will align in a column.
* @param cont - The container to align.
* @param width - The width of the screen.
* @param height - The height of the screen.
* @return The total height of the container. This is useful in
* positioning the container itself.
*/
public static float alignContainer(Node cont, int width, int height)
{
float totalHeight = 0;
for (Spatial node : cont.getChildren())
{
if (node instanceof BitmapText)
{
node.setLocalTranslation(
-((BitmapText) node).getLineWidth() / 2F, -totalHeight,
0);
totalHeight += ((BitmapText) node).getHeight();
}
else if (node.getUserData(BUTTON_ID) != null)
{
Quad quad = ((Quad) ((Geometry) ((Node) node).getChild(0))
.getMesh());
node.setLocalTranslation(-quad.getWidth() / 2F,
-totalHeight - 10, 0);
totalHeight += quad.getHeight() + 10;
}
}
return totalHeight;
}
}

View File

@@ -14,15 +14,16 @@ import com.jme3.app.Application;
import com.jme3.app.SimpleApplication; import com.jme3.app.SimpleApplication;
import com.jme3.app.state.BaseAppState; import com.jme3.app.state.BaseAppState;
import com.jme3.asset.AssetManager; import com.jme3.asset.AssetManager;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapFont; import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText; import com.jme3.font.BitmapText;
import com.jme3.input.Joystick; import com.jme3.input.Joystick;
import com.jme3.input.JoystickAxis; import com.jme3.input.JoystickAxis;
import com.jme3.input.JoystickButton; import com.jme3.input.JoystickButton;
import com.jme3.input.JoystickConnectionListener; import com.jme3.input.JoystickConnectionListener;
import com.jme3.input.MouseInput;
import com.jme3.input.RawInputListener; import com.jme3.input.RawInputListener;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.input.event.JoyAxisEvent; import com.jme3.input.event.JoyAxisEvent;
import com.jme3.input.event.JoyButtonEvent; import com.jme3.input.event.JoyButtonEvent;
import com.jme3.input.event.KeyInputEvent; import com.jme3.input.event.KeyInputEvent;
@@ -33,9 +34,8 @@ import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode; import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f; import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.renderer.Camera;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
@@ -47,12 +47,12 @@ import java.util.Map;
/** /**
* Adding this app state will display a GUI screen showing the controllers * Adding this app state will display a GUI screen showing the controllers
* connected and information on what buttons are pressed. It is primarily * connected and information on what buttons are pressed. It is primarily useful
* useful for debugging controllers. * for debugging controllers.
* <p>Note that this class relies on three textures not found in the default * <p>Note that this class relies on three textures not found in the default
* JME core: "Interface/Joystick/gamepad-buttons.png", * JME core: "Interface/Joystick/gamepad-buttons.png",
* "Interface/Joystick/gamepad-frame.png," and * "Interface/Joystick/gamepad-frame.png,"
* "Interface/Joystick/gamepad-stick.png." These textures can be obtained * and "Interface/Joystick/gamepad-stick.png." These textures can be obtained
* from the org.jmonkeyengine:jme3-testdata library.</p> * from the org.jmonkeyengine:jme3-testdata library.</p>
* *
* @author Markil 3 * @author Markil 3
@@ -61,9 +61,10 @@ import java.util.Map;
* @author Paul Speed * @author Paul Speed
* @author dokthar * @author dokthar
* @author Stephen Gold * @author Stephen Gold
* @version 1.2
*/ */
public class JoystickPreviewScreen extends BaseAppState public class JoystickPreviewScreen extends BaseAppState
implements RawInputListener, JoystickConnectionListener implements RawInputListener, JoystickConnectionListener, ActionListener
{ {
private static final org.slf4j.Logger logger = private static final org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger(JoystickPreviewScreen.class); org.slf4j.LoggerFactory.getLogger(JoystickPreviewScreen.class);
@@ -87,13 +88,13 @@ public class JoystickPreviewScreen extends BaseAppState
public static final String L1 = JoystickButton.BUTTON_4; public static final String L1 = JoystickButton.BUTTON_4;
public static final String R1 = JoystickButton.BUTTON_5; public static final String R1 = JoystickButton.BUTTON_5;
/** /**
* Some gamepads (Xbox controllers notable) will use * Some gamepads (Xbox controllers notable) will use {@link
* {@link JoystickAxis#LEFT_TRIGGER} instead. * JoystickAxis#LEFT_TRIGGER} instead.
*/ */
public static final String L2 = JoystickButton.BUTTON_6; public static final String L2 = JoystickButton.BUTTON_6;
/** /**
* Some gamepads (Xbox controllers notable) will use * Some gamepads (Xbox controllers notable) will use {@link
* {@link JoystickAxis#RIGHT_TRIGGER} instead. * JoystickAxis#RIGHT_TRIGGER} instead.
*/ */
public static final String R2 = JoystickButton.BUTTON_7; public static final String R2 = JoystickButton.BUTTON_7;
public static final String SELECT = JoystickButton.BUTTON_8; public static final String SELECT = JoystickButton.BUTTON_8;
@@ -122,10 +123,11 @@ public class JoystickPreviewScreen extends BaseAppState
* Most gamepads may use {@link JoystickAxis#POV_Y} instead. * Most gamepads may use {@link JoystickAxis#POV_Y} instead.
*/ */
public static final String DPAD_DOWN = "15"; public static final String DPAD_DOWN = "15";
final String CLICK_MAPPING = "previewButtonClick";
/** /**
* This node serves as the center of logic for each gamepad connected to * This node serves as the center of logic for each gamepad connected to the
* the computer. * computer.
*/ */
static class GamepadView extends Node static class GamepadView extends Node
{ {
@@ -260,7 +262,7 @@ public class JoystickPreviewScreen extends BaseAppState
} }
else if (axis == axis.getJoystick().getYAxis()) else if (axis == axis.getJoystick().getYAxis())
{ {
setYAxis(-value); setYAxis(value);
} }
else if (axis == axis.getJoystick().getAxis(JoystickAxis.Z_AXIS)) else if (axis == axis.getJoystick().getAxis(JoystickAxis.Z_AXIS))
{ {
@@ -279,7 +281,7 @@ public class JoystickPreviewScreen extends BaseAppState
else if (axis == else if (axis ==
axis.getJoystick().getAxis(JoystickAxis.Z_ROTATION)) axis.getJoystick().getAxis(JoystickAxis.Z_ROTATION))
{ {
setZRotation(-value); setZRotation(value);
} }
else if (axis == else if (axis ==
axis.getJoystick().getAxis(JoystickAxis.LEFT_TRIGGER)) axis.getJoystick().getAxis(JoystickAxis.LEFT_TRIGGER))
@@ -466,8 +468,8 @@ public class JoystickPreviewScreen extends BaseAppState
float angle = dir.getAngle(); float angle = dir.getAngle();
float x = FastMath.cos(angle) * length * 10; float x = FastMath.cos(angle) * length * 10;
float y = FastMath.sin(angle) * length * 10; float y = FastMath.sin(-angle) * length * 10;
leftStick.setLocalTranslation(xBase + x, yBase + y, 0); leftStick.setLocalTranslation(xBase + x, yBase - y, 0);
xBase = 291; xBase = 291;
dir = new Vector2f(zAxis, zRotation); dir = new Vector2f(zAxis, zRotation);
@@ -476,8 +478,8 @@ public class JoystickPreviewScreen extends BaseAppState
angle = dir.getAngle(); angle = dir.getAngle();
x = FastMath.cos(angle) * length * 10; x = FastMath.cos(angle) * length * 10;
y = FastMath.sin(angle) * length * 10; y = FastMath.sin(-angle) * length * 10;
rightStick.setLocalTranslation(xBase + x, yBase + y, 0); rightStick.setLocalTranslation(xBase + x, yBase - y, 0);
} }
} }
@@ -530,8 +532,9 @@ public class JoystickPreviewScreen extends BaseAppState
/** /**
* Checks to see if the visual displays if the button is pressed. * Checks to see if the visual displays if the button is pressed.
* @return True if the visual displays that the button is pressed, *
* false otherwise. * @return True if the visual displays that the button is pressed, false
* otherwise.
*/ */
public boolean isDown() public boolean isDown()
{ {
@@ -540,6 +543,7 @@ public class JoystickPreviewScreen extends BaseAppState
/** /**
* Updates the button to display that it is pressed. * Updates the button to display that it is pressed.
*
* @see #up() * @see #up()
*/ */
public void down() public void down()
@@ -550,6 +554,7 @@ public class JoystickPreviewScreen extends BaseAppState
/** /**
* Updates the button to display that it is not pressed. * Updates the button to display that it is not pressed.
*
* @see #down() * @see #down()
*/ */
public void up() public void up()
@@ -559,12 +564,8 @@ public class JoystickPreviewScreen extends BaseAppState
} }
} }
final ColorRGBA BUTTON_COLOR = new ColorRGBA(0F, 0.1F, 0F, 1F);
final ColorRGBA HIGHLIGHTED_BUTTON_COLOR =
new ColorRGBA(0F, 0.75F, 0.25F, 1F);
protected Node gui; protected Node gui;
private BitmapFont guiFont; protected BitmapFont guiFont;
private Node[] gamepadCont; private Node[] gamepadCont;
@@ -588,15 +589,11 @@ public class JoystickPreviewScreen extends BaseAppState
this.updateGamepad(); this.updateGamepad();
this.setEnabled(true);
((SimpleApplication) this.getApplication()).getGuiNode() ((SimpleApplication) this.getApplication()).getGuiNode()
.attachChild(this.gui); .attachChild(this.gui);
this.resize(((SimpleApplication) this.getApplication()).getCamera()
.getWidth(), app.getInputManager().addMapping(CLICK_MAPPING,
((SimpleApplication) this.getApplication()).getCamera() new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
.getHeight());
this.setEnabled(true);
} }
/** /**
@@ -677,9 +674,6 @@ public class JoystickPreviewScreen extends BaseAppState
*/ */
private void addButtons() private void addButtons()
{ {
Node button;
BitmapText buttonText;
Geometry buttonBackground;
int i, l; int i, l;
/* /*
@@ -697,40 +691,21 @@ public class JoystickPreviewScreen extends BaseAppState
this.gamepadHeaders = new Node[l]; this.gamepadHeaders = new Node[l];
for (i = 0, l = this.gamepadCont.length; i < l; i++) for (i = 0, l = this.gamepadCont.length; i < l; i++)
{ {
button = new Node(); this.gamepadHeaders[i] = GUIUtils.createButton(
buttonText = this.guiFont.createLabel("Gamepad " + this.getApplication().getAssetManager(), this.guiFont,
this.getApplication().getInputManager().getJoysticks()[i] this.getApplication().getContext().getTouchInput() != null,
.getJoyId()); "gamepad" + i, "Gamepad " +
buttonText.setUserData("gamepad", i); this.getApplication().getInputManager()
buttonBackground = new Geometry("gamepad" + i, .getJoysticks()[i].getJoyId());
new Quad(buttonText.getLineWidth() + 10, this.gui.attachChild(this.gamepadHeaders[i]);
buttonText.getLineHeight() + 5));
buttonBackground.setMaterial(
new Material(this.getApplication().getAssetManager(),
"Common/MatDefs/Misc/Unshaded.j3md"));
if (this.gamepadCont[i].getParent() != null)
{
buttonBackground.getMaterial()
.setColor("Color", HIGHLIGHTED_BUTTON_COLOR);
}
else
{
buttonBackground.getMaterial().setColor("Color", BUTTON_COLOR);
}
buttonBackground.setUserData("gamepad", i);
buttonBackground
.setLocalTranslation(0, -buttonText.getLineHeight(), 0);
button.attachChild(buttonBackground);
button.attachChild(buttonText);
this.gui.attachChild(button);
this.gamepadHeaders[i] = button;
} }
} }
/** /**
* Obtain the size of the screen based on the game camera. * Obtain the size of the screen based on the game camera.
* @return The screen size in a two-dimensional float vector. Note that *
* the numbers will always be integers. * @return The screen size in a two-dimensional float vector. Note that the
* numbers will always be integers.
*/ */
private Vector2f getScreenSize() private Vector2f getScreenSize()
{ {
@@ -742,6 +717,7 @@ public class JoystickPreviewScreen extends BaseAppState
protected void cleanup(Application app) protected void cleanup(Application app)
{ {
this.gui.removeFromParent(); this.gui.removeFromParent();
app.getInputManager().deleteMapping(CLICK_MAPPING);
} }
@Override @Override
@@ -750,6 +726,9 @@ public class JoystickPreviewScreen extends BaseAppState
this.getApplication().getInputManager().addRawInputListener(this); this.getApplication().getInputManager().addRawInputListener(this);
this.getApplication().getInputManager() this.getApplication().getInputManager()
.addJoystickConnectionListener(this); .addJoystickConnectionListener(this);
this.resize();
this.getApplication().getInputManager()
.addListener(this, CLICK_MAPPING);
} }
@Override @Override
@@ -758,15 +737,21 @@ public class JoystickPreviewScreen extends BaseAppState
this.getApplication().getInputManager().removeRawInputListener(this); this.getApplication().getInputManager().removeRawInputListener(this);
this.getApplication().getInputManager() this.getApplication().getInputManager()
.removeJoystickConnectionListener(this); .removeJoystickConnectionListener(this);
this.getApplication().getInputManager().removeListener(this);
} }
/** /**
* Updates the values of the gamepad labels as buttons and axis are * Updates the values of the gamepad labels as buttons and axis are
* manipulated. * manipulated.
*
* @param joy - The gamepad to update. * @param joy - The gamepad to update.
*/ */
private void setLabels(Joystick joy) private void setLabels(Joystick joy)
{ {
int offset =
this.getApplication().getContext().getTouchInput() != null ?
10 :
0;
/* /*
* Removes the old labels. * Removes the old labels.
*/ */
@@ -787,19 +772,28 @@ public class JoystickPreviewScreen extends BaseAppState
/* /*
* The name of the gamepad. * The name of the gamepad.
*/ */
// this.labels[joy.getJoyId()][0] = this.guiFont.createLabel(
// "Gamepad " + joy.getJoyId() + ": " + joy.getName());
this.labels[joy.getJoyId()][0] = this.labels[joy.getJoyId()][0] =
this.guiFont.createLabel(joy.getName()); this.guiFont.createLabel(joy.getName());
this.labels[joy.getJoyId()][0].setLocalTranslation(20, -25, 0); this.labels[joy.getJoyId()][0].setLocalTranslation(20,
-25 - offset,
0);
this.gamepadCont[joy.getJoyId()] this.gamepadCont[joy.getJoyId()]
.attachChild(this.labels[joy.getJoyId()][0]); .attachChild(this.labels[joy.getJoyId()][0]);
/* /*
* The key for the axis. Each of the axis rows will display the * The key for the axis. Each of the axis rows will display the
* index of the axis, its given name, its logical ID after * index of the axis, its given name, its logical ID after
* joystick remapping has occurred, and the axis index again. * joystick remapping has occurred, and the axis index again.
* TODO - Whenever I add the " Gamepad X: " part to the previous
* label, this one displays all funky. Also, the lag gets really
* bad.
*/ */
this.labels[joy.getJoyId()][1] = this.guiFont this.labels[joy.getJoyId()][1] = this.guiFont
.createLabel("Axis Index: Axis Name (logical ID, axis ID)"); .createLabel("Axis Index: Axis Name (logical ID, axis ID)");
this.labels[joy.getJoyId()][1].setLocalTranslation(20, -50, 0); this.labels[joy.getJoyId()][1].setLocalTranslation(20,
-50 - offset,
0);
this.gamepadCont[joy.getJoyId()] this.gamepadCont[joy.getJoyId()]
.attachChild(this.labels[joy.getJoyId()][1]); .attachChild(this.labels[joy.getJoyId()][1]);
/* /*
@@ -817,13 +811,13 @@ public class JoystickPreviewScreen extends BaseAppState
(i) + ": " + axis.getName() + " (" + (i) + ": " + axis.getName() + " (" +
axis.getLogicalId() + ", " + axis.getLogicalId() + ", " +
axis.getAxisId() + "): "); axis.getAxisId() + "): ");
label.setLocalTranslation(20, -25 * (i + 3), 0); label.setLocalTranslation(20, -25 * (i + 3) - offset, 0);
this.labels[joy.getJoyId()][i * 2 + 1] = label; this.labels[joy.getJoyId()][i * 2 + 1] = label;
/* /*
* The current value of the axis. * The current value of the axis.
*/ */
BitmapText label2 = this.guiFont.createLabel("-1.0"); BitmapText label2 = this.guiFont.createLabel("0.0");
label2.setLocalTranslation(label.getLocalTranslation() label2.setLocalTranslation(label.getLocalTranslation()
.add(label.getLineWidth(), 0, 0)); .add(label.getLineWidth(), 0, 0));
this.labels[joy.getJoyId()][i * 2 + 2] = label2; this.labels[joy.getJoyId()][i * 2 + 2] = label2;
@@ -859,7 +853,7 @@ public class JoystickPreviewScreen extends BaseAppState
this.labels[joy.getJoyId()][firstButtonIndex].setLocalTranslation( this.labels[joy.getJoyId()][firstButtonIndex].setLocalTranslation(
this.getScreenSize().x - this.getScreenSize().x -
this.labels[joy.getJoyId()][firstButtonIndex] this.labels[joy.getJoyId()][firstButtonIndex]
.getLineWidth(), -50, 0); .getLineWidth(), -50 - offset, 0);
this.gamepadCont[joy.getJoyId()] this.gamepadCont[joy.getJoyId()]
.attachChild(this.labels[joy.getJoyId()][firstButtonIndex]); .attachChild(this.labels[joy.getJoyId()][firstButtonIndex]);
@@ -879,7 +873,7 @@ public class JoystickPreviewScreen extends BaseAppState
BitmapText label2 = this.guiFont.createLabel("false"); BitmapText label2 = this.guiFont.createLabel("false");
label2.setLocalTranslation( label2.setLocalTranslation(
this.getScreenSize().x - label2.getLineWidth(), this.getScreenSize().x - label2.getLineWidth(),
-25 * (i + 3), 0); -25 * (i + 3) - offset, 0);
/* /*
* The name and information for the button. * The name and information for the button.
@@ -915,11 +909,22 @@ public class JoystickPreviewScreen extends BaseAppState
} }
/** /**
* Repositions the screen elements. * Automatically scales and positions elements based on the camera
* @param width - The width of the screen. * dimensions.
* @param height - The height of the screen.
*/ */
public void resize(int width, int height) public void resize()
{
Camera camera = this.getApplication().getCamera();
this.resize(camera.getWidth(), camera.getHeight());
}
/**
* Scales and positions elements of this screen.
*
* @param width - The width to scale to.
* @param height - The height to scale to.
*/
protected void resize(int width, int height)
{ {
this.gui.setLocalTranslation(0, this.getScreenSize().y, 0); this.gui.setLocalTranslation(0, this.getScreenSize().y, 0);
if (this.gamepadHeaders != null) if (this.gamepadHeaders != null)
@@ -928,7 +933,11 @@ public class JoystickPreviewScreen extends BaseAppState
for (int i = 0, l = this.gamepadHeaders.length; i < l; i++) for (int i = 0, l = this.gamepadHeaders.length; i < l; i++)
{ {
button = this.gamepadHeaders[i]; button = this.gamepadHeaders[i];
button.setLocalTranslation(128 * i, 0, 0); button.setLocalTranslation((this.getApplication()
.getContext()
.getTouchInput() != null ?
192 :
128) * i, 0, 0);
} }
} }
if (this.gamepadView != null) if (this.gamepadView != null)
@@ -992,100 +1001,85 @@ public class JoystickPreviewScreen extends BaseAppState
{ {
} }
/** @Override
* A convenience method to discover what the mouse is currently over. public void onAction(String name, boolean isPressed, float tpf)
* @param x - The current X coordinate of the mouse.
* @param y - The current Y coordinate of the mouse.
* @return Collision results on the GUI.
*/
private CollisionResults checkMouse(int x, int y)
{ {
CollisionResults results = new CollisionResults(); String buttonId;
Ray ray = new Ray(new Vector3f(x, y, 0), new Vector3f(x, y, 1)); int gamepad;
this.gui.collideWith(ray, results); if (name.equals(CLICK_MAPPING))
return results; {
buttonId = GUIUtils.handleButtonPress(this.gui,
this.getApplication().getInputManager().getCursorPosition(),
isPressed);
if (!isPressed && buttonId != null)
{
if (buttonId.startsWith("gamepad"))
{
gamepad = Integer.parseInt(buttonId.substring(7));
for (int i = 0, l = this.gamepadCont.length; i < l; i++)
{
if (i == gamepad)
{
this.gui.attachChild(this.gamepadCont[i]);
}
else
{
this.gamepadCont[i].removeFromParent();
}
}
}
}
}
} }
/** /**
* Displays which button is which as the user hovers over the button. * Displays which button is which as the user hovers over the button. TODO -
* TODO - Doesn't trigger. * Doesn't trigger.
*
* @param evt - Input event data. * @param evt - Input event data.
*/ */
@Override @Override
public void onMouseMotionEvent(MouseMotionEvent evt) public void onMouseMotionEvent(MouseMotionEvent evt)
{ {
ButtonView button = null; // ButtonView button = null;
CollisionResults results = this.checkMouse(evt.getX(), evt.getY()); // CollisionResults results = this.checkMouse(evt.getX(), evt.getY());
if (results.size() > 0) // if (results.size() > 0)
{ // {
for (CollisionResult result : results) // for (CollisionResult result : results)
{ // {
if (result.getGeometry().getUserData("view") != null) // if (result.getGeometry().getUserData("view") != null)
{ // {
if (result.getGeometry() // if (result.getGeometry()
.getUserData("view") instanceof ButtonView) // .getUserData("view") instanceof ButtonView)
{ // {
button = result.getGeometry().getUserData("view"); // button = result.getGeometry().getUserData("view");
break; // break;
} // }
} // }
} // }
} // }
if (button != null) // if (button != null)
{ // {
this.refLabel.setText(button.getName().substring(8)); // this.refLabel.setText(button.getName().substring(8));
Vector2f size = this.getScreenSize(); // this.resize();
this.resize((int) size.x, (int) size.y); // }
} // else
else // {
{ // if (this.refLabel.getText().length() > 0)
if (this.refLabel.getText().length() > 0) // {
{ // this.refLabel.setText("");
this.refLabel.setText(""); // }
} // }
}
} }
/** /**
* Triggers the gamepad tab buttons. * Triggers the gamepad tab buttons.
*
* @param evt - Input event data. * @param evt - Input event data.
*/ */
@Override @Override
public void onMouseButtonEvent(MouseButtonEvent evt) public void onMouseButtonEvent(MouseButtonEvent evt)
{ {
Integer gamepad;
if (evt.isPressed() && evt.getButtonIndex() == 0)
{
CollisionResults results = this.checkMouse(evt.getX(), evt.getY());
if (results.size() > 0)
{
for (CollisionResult result : results)
{
if (result.getGeometry().getUserData("gamepad") != null)
{
gamepad = result.getGeometry().getUserData("gamepad");
for (int i = 0, l = this.gamepadCont.length; i < l; i++)
{
if (i == gamepad)
{
this.gui.attachChild(this.gamepadCont[i]);
((Geometry) this.gamepadHeaders[i].getChild(0))
.getMaterial().setColor("Color",
HIGHLIGHTED_BUTTON_COLOR);
}
else
{
this.gamepadCont[i].removeFromParent();
((Geometry) this.gamepadHeaders[i].getChild(0))
.getMaterial()
.setColor("Color", BUTTON_COLOR);
}
}
break;
}
}
}
}
} }
@Override @Override
@@ -1101,15 +1095,13 @@ public class JoystickPreviewScreen extends BaseAppState
@Override @Override
public void onConnected(Joystick joystick) public void onConnected(Joystick joystick)
{ {
Vector2f size = this.getScreenSize();
this.updateGamepad(); this.updateGamepad();
this.resize((int) size.x, (int) size.y); this.resize();
} }
@Override @Override
public void onDisconnected(Joystick joystick) public void onDisconnected(Joystick joystick)
{ {
Vector2f size = this.getScreenSize();
/* /*
* TODO - This callback will fire before the joystick is actually * TODO - This callback will fire before the joystick is actually
* removed. This is helpful at times, but it does mean we will have a * removed. This is helpful at times, but it does mean we will have a
@@ -1117,6 +1109,6 @@ public class JoystickPreviewScreen extends BaseAppState
* removed. * removed.
*/ */
this.updateGamepad(); this.updateGamepad();
this.resize((int) size.x, (int) size.y); this.resize();
} }
} }

View File

@@ -7,6 +7,7 @@
* Detailed information about configuring a multi-project build in Gradle can be found * Detailed information about configuring a multi-project build in Gradle can be found
* in the user guide at https://docs.gradle.org/4.4.1/userguide/multi_project_builds.html * in the user guide at https://docs.gradle.org/4.4.1/userguide/multi_project_builds.html
*/ */
include ':jmecontrollerconfig'
/* /*
// To declare projects as part of a multi-project build use the 'include' method // To declare projects as part of a multi-project build use the 'include' method
@@ -17,3 +18,6 @@ include 'services:webservice'
rootProject.name = 'JMEControllerConfig' rootProject.name = 'JMEControllerConfig'
include "library" include "library"
include "desktop"
include "desktopLegacy"
include "android"

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2020 Markil 3. All rights reserved.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package markil3.controller;
import com.jme3.app.DebugKeysAppState;
import com.jme3.app.SimpleApplication;
import com.jme3.app.StatsAppState;
import com.jme3.input.JoystickAxis;
import com.jme3.input.JoystickButton;
import com.jme3.system.AppSettings;
/**
* Launch point for the application. This is primarily for demo purposes, and
* games using this as a library can safely ignore it.
*
* @author Markil 3
* @version 1.0
*/
public class Main extends SimpleApplication
{
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.
getLogger(Main.class);
public static void main(String[] args)
{
Main app = new Main();
AppSettings settings = new AppSettings(true);
settings.setTitle("Joystick Preview");
settings.setUseJoysticks(true);
settings.setEmulateMouse(true);
settings.setVSync(true);
app.setSettings(settings);
app.start();
}
public Main()
{
super(new StatsAppState(), new DebugKeysAppState(), new JoystickPreviewScreen());
}
@Override
public void simpleInitApp()
{
}
}