Repository: MrCrayfish/ModelCreator Branch: master Commit: b85b0da614ef Files: 86 Total size: 471.1 KB Directory structure: gitextract_b14my70h/ ├── .gitignore ├── LICENSE ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src/ └── main/ ├── java/ │ └── com/ │ └── mrcrayfish/ │ └── modelcreator/ │ ├── Actions.java │ ├── Animation.java │ ├── Camera.java │ ├── Constants.java │ ├── Exporter.java │ ├── ExporterJavaCode.java │ ├── ExporterModel.java │ ├── Icons.java │ ├── Importer.java │ ├── ModelCreator.java │ ├── Processor.java │ ├── ProjectManager.java │ ├── PropertyIdentifiers.java │ ├── Settings.java │ ├── Start.java │ ├── StateManager.java │ ├── TexturePath.java │ ├── component/ │ │ ├── DisplayPropertiesDialog.java │ │ ├── JElementList.java │ │ ├── Menu.java │ │ ├── MenuAdapter.java │ │ ├── TextureEntryEditor.java │ │ └── TextureManager.java │ ├── dialog/ │ │ └── WelcomeDialog.java │ ├── display/ │ │ ├── CanvasRenderer.java │ │ ├── DisplayProperties.java │ │ └── render/ │ │ ├── DisplayPropertyRenderer.java │ │ ├── FirstPersonPropertyRenderer.java │ │ ├── FixedPropertyRenderer.java │ │ ├── GroundPropertyRenderer.java │ │ ├── GuiPropertyRenderer.java │ │ ├── HeadPropertyRenderer.java │ │ ├── StandardRenderer.java │ │ └── ThirdPersonPropertyRenderer.java │ ├── element/ │ │ ├── Element.java │ │ ├── ElementCellEntry.java │ │ ├── ElementCellRenderer.java │ │ ├── ElementManager.java │ │ ├── ElementManagerState.java │ │ └── Face.java │ ├── object/ │ │ └── FaceDimension.java │ ├── panels/ │ │ ├── CuboidTabbedPane.java │ │ ├── DisplayEntryPanel.java │ │ ├── ElementExtraPanel.java │ │ ├── FaceExtrasPanel.java │ │ ├── GlobalPanel.java │ │ ├── IElementUpdater.java │ │ ├── OriginPanel.java │ │ ├── PositionPanel.java │ │ ├── SidebarPanel.java │ │ ├── SizePanel.java │ │ ├── TexturePanel.java │ │ ├── UVPanel.java │ │ └── tabs/ │ │ ├── ElementPanel.java │ │ ├── FacePanel.java │ │ └── RotationPanel.java │ ├── screenshot/ │ │ ├── PendingScreenshot.java │ │ ├── Screenshot.java │ │ ├── ScreenshotCallback.java │ │ └── Uploader.java │ ├── sidebar/ │ │ ├── Sidebar.java │ │ └── UVSidebar.java │ ├── texture/ │ │ ├── Clipboard.java │ │ ├── TextureAnimation.java │ │ ├── TextureAtlas.java │ │ └── TextureEntry.java │ └── util/ │ ├── AssetsUtil.java │ ├── AtlasRenderUtil.java │ ├── ComponentUtil.java │ ├── FontManager.java │ ├── KeyboardUtil.java │ ├── OperatingSystem.java │ ├── Parser.java │ ├── SharedLibraryLoader.java │ ├── StreamUtils.java │ └── Util.java └── resources/ ├── bebas_neue.otf └── models/ ├── cauldron.model └── modern_chair.model ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msm *.msp # Windows shortcuts *.lnk # ========================= # Operating System Files # ========================= # OSX # ========================= .DS_Store .AppleDouble .LSOverride # Thumbnails ._* # Files that might appear on external disk .Spotlight-V100 .Trashes # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk /bin/ .project .classpath *.classpath .classpath test.json /bin1/ /bin1/ out/ .idea/ *.iml src/META-INF/MANIFEST.MF .metadata/ /.gradle/ /build/ .settings/ .project classes/ ================================================ FILE: LICENSE ================================================ Copyright © 2016 MrCrayfish Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 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. ================================================ FILE: build.gradle ================================================ apply plugin: "java" apply plugin: "application" version = "0.7.0" mainClassName = "com.mrcrayfish.modelcreator.Start" sourceCompatibility = targetCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile 'com.google.code.gson:gson:2.8.5' compile 'org.slick2d:slick2d-core:1.0.2' compile 'com.jtattoo:JTattoo:1.6.11' compile 'org.lwjgl.lwjgl:lwjgl:2.9.3' compile 'org.lwjgl.lwjgl:lwjgl_util:2.9.3' compile 'org.lwjgl.lwjgl:lwjgl-platform:2.9.3' } jar { manifest { attributes "Main-Class": mainClassName } from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: gradlew ================================================ #!/usr/bin/env sh ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn () { echo "$*" } die () { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Escape application args save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } APP_ARGS=$(save "$@") # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then cd "$(dirname "$0")" fi exec "$JAVACMD" "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Actions.java ================================================ package com.mrcrayfish.modelcreator; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; /** * Author: MrCrayfish */ public class Actions { public static int optimiseModel(ElementManager manager) { int count = 0; for(Element element : manager.getAllElements()) { for(Face face : element.getAllFaces()) { if(face.isEnabled() && !face.isVisible(manager)) { count++; face.setEnabled(false); } } } if(count > 0) { StateManager.pushState(manager); } return count; } public static void rotateModel(ElementManager manager, boolean clockwise) { manager.getAllElements().forEach(element -> rotateElement(element, clockwise)); manager.updateValues(); StateManager.pushState(manager); } private static void rotateElement(Element element, boolean clockwise) { /* Calculates and sets the new starting x and y position of the element */ double newX; double newZ; if(clockwise) { newX = element.getStartX() - 8 > 0 ? 16 - (element.getDepth() + element.getStartZ()) : 16 - element.getDepth() - element.getStartZ(); newZ = element.getStartX(); } else { newX = element.getStartZ(); newZ = element.getStartZ() - 8 > 0 ? 16 - (element.getWidth() + element.getStartX()) : 16 - element.getWidth() - element.getStartX(); } element.setStartX(newX); element.setStartZ(newZ); /* Swaps the width and depth of the element */ double width = element.getWidth(); element.setWidth(element.getDepth()); element.setDepth(width); /* Shifts the UVs of horizontal faces to the next target face */ Face[] faces = element.getAllFaces(); Face tempFace = new Face(faces[clockwise ? 3 : 0]); if(clockwise) { for(int i = 3; i >= 1; i--) { faces[i].copyProperties(faces[i - 1]); } } else { for(int i = 0; i < 3; i++) { faces[i].copyProperties(faces[i + 1]); } } faces[clockwise ? 0 : 3].copyProperties(tempFace); /* Rotates the textures on the top so they match the original when rotated */ faces[Face.UP].setRotation(getNextFaceRotation(element, Face.UP, clockwise)); faces[Face.DOWN].setRotation(getNextFaceRotation(element, Face.DOWN, clockwise)); /* Rotates the rotation axis. This only applies to horizontal axis */ if(element.getRotationAxis() == 0) { element.setRotationAxis(2); if(!clockwise) { element.setRotation(-element.getRotation()); } } else if(element.getRotationAxis() == 2) { element.setRotationAxis(0); if(clockwise) { element.setRotation(-element.getRotation()); } } /* Rotates the origin starting x and y */ double newOriginX; double newOriginZ; if(clockwise) { newOriginX = element.getOriginX() - 8 > 0 ? 16 - element.getOriginZ() : 16 - element.getOriginZ(); newOriginZ = element.getOriginX(); } else { newOriginX = element.getOriginZ(); newOriginZ = element.getOriginZ() - 8 > 0 ? 16 - element.getOriginX() : 16 - element.getOriginX(); } element.setOriginX(newOriginX); element.setOriginZ(newOriginZ); } private static int getNextFaceRotation(Element element, int side, boolean clockwise) { Face[] faces = element.getAllFaces(); if(clockwise) { return (faces[side].getRotation() + 1) % 4; } else if(faces[side].getRotation() - 1 >= 0) { return faces[side].getRotation() - 1; } return 3; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Animation.java ================================================ package com.mrcrayfish.modelcreator; /** * Author: MrCrayfish */ public class Animation { private static int counter; private static float partialTicks; public static void tick() { Animation.counter++; } public static void setPartialTicks(float partialTicks) { Animation.partialTicks = partialTicks; } public static int getCounter() { return Animation.counter; } public static float getPartialTicks() { return partialTicks; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Camera.java ================================================ package com.mrcrayfish.modelcreator; import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.util.glu.GLU.gluPerspective; public class Camera { private float x; private float y; private float z; private float rx; private float ry; private float rz; private float fov; private float aspect; private float near; private float far; public Camera(float fov, float aspect, float near, float far) { x = 0; y = 0; z = -20; rx = 30F; ry = 0F; rz = 0; this.fov = fov; this.aspect = aspect; this.near = near; this.far = far; initProjection(); } private void initProjection() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fov, aspect, near, far); glMatrixMode(GL_MODELVIEW); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEnable(GL_DEPTH_TEST); } public void useView() { glTranslatef(x, y, z); glRotatef(rx, 1, 0, 0); glRotatef(ry, 0, 1, 0); glRotatef(rz, 0, 0, 1); } public float getX() { return x; } public float getY() { return y; } public float getZ() { return z; } public void setX(float x) { this.x = x; } public void setY(float y) { this.y = y; } public void setZ(float z) { this.z = z; } public float getRX() { return rx; } public float getRY() { return ry; } public float getRZ() { return rz; } public void setRX(float rx) { this.rx = rx; } public void setRY(float ry) { this.ry = ry; } public void setRZ(float rz) { this.rz = rz; } public void move(float amt, float dir) { z += amt * Math.sin(Math.toRadians(ry + 90 * dir)); x += amt * Math.cos(Math.toRadians(ry + 90 * dir)); } public void addX(float amt) { x += amt; } public void addY(float amt) { y += amt; } public void addZ(float amt) { z += amt; } public void rotateX(float amt) { rx = ((rx + amt) % 360); } public void rotateY(float amt) { ry = ((ry + amt) % 360); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Constants.java ================================================ package com.mrcrayfish.modelcreator; public class Constants { public static final String NAME = "MrCrayfish's Model Creator"; public static final String VERSION = "0.7.0"; public static final String URL_DONATE = "https://www.patreon.com/mrcrayfish?ty=h"; public static final String URL_TWITTER = "https://www.twitter.com/MrCraayfish"; public static final String URL_FACEBOOK = "https://www.facebook.com/MrCrayfish"; public static final String URL_GITHUB = "https://github.com/MrCrayfish/ModelCreator"; } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Exporter.java ================================================ package com.mrcrayfish.modelcreator; import com.mrcrayfish.modelcreator.element.ElementManager; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; public abstract class Exporter { /** * decimalformatter for rounding */ public static final DecimalFormat FORMAT = new DecimalFormat("#.###"); private static final DecimalFormatSymbols SYMBOLS = new DecimalFormatSymbols(); static { SYMBOLS.setDecimalSeparator('.'); FORMAT.setDecimalFormatSymbols(SYMBOLS); } // Model Variables protected ElementManager manager; public Exporter(ElementManager manager) { this.manager = manager; } public File export(File file) { File path = file.getParentFile(); if(path.exists() && path.isDirectory()) { this.writeFile(file); } return file; } protected abstract void write(BufferedWriter writer) throws IOException; public File writeFile(File file) { try(BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { if(!file.exists()) { file.createNewFile(); } this.write(writer); return file; } catch(IOException e) { e.printStackTrace(); } return null; } protected String space(int size) { StringBuilder builder = new StringBuilder(); for(int i = 0; i < size; i++) { //TODO add setting to export with tabs instead builder.append(" "); } return builder.toString(); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/ExporterJavaCode.java ================================================ package com.mrcrayfish.modelcreator; import com.mrcrayfish.modelcreator.element.Element; import javax.swing.*; import java.awt.*; import java.awt.datatransfer.StringSelection; import java.io.BufferedWriter; import java.io.IOException; import java.io.StringWriter; public class ExporterJavaCode extends Exporter { private ModelCreator creator; private Version version = Version.V_1_12; private boolean includeFields, includeMethods, useBoundsHelper, generateRotatedBounds; public ExporterJavaCode(ModelCreator creator, boolean includeFields, boolean includeMethods, boolean useBoundsHelper, boolean generateRotatedBounds) { super(creator.getElementManager()); this.creator = creator; this.includeFields = includeFields; this.includeMethods = includeMethods; this.useBoundsHelper = useBoundsHelper; this.generateRotatedBounds = useBoundsHelper && generateRotatedBounds; } public void setVersion(Version version) { this.version = version; } public void writeCodeToClipboard() throws IOException { StringWriter writerFile = new StringWriter(); try(BufferedWriter writer = new BufferedWriter(writerFile)) { write(writer); writer.flush(); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(writerFile.toString()), null); } } @Override protected void write(BufferedWriter writer) throws IOException { if(version == Version.V_1_13) { if(includeFields) { /* Generates member fields */ writeNewLine(writer, "/* Member variables */"); if(generateRotatedBounds) { writeNewLine(writer, "public final ImmutableMap SHAPES;"); } else { writeNewLine(writer, "public final VoxelShape SHAPE;"); } writer.newLine(); /* Generates logic which is to be placed into the constructor */ writeNewLine(writer, "/* Place in Constructor */"); if(generateRotatedBounds) { writeNewLine(writer, "SHAPES = this.generateShapes(this.getStateContainer().getValidStates());"); } else { writeNewLine(writer, "SHAPE = this.generateShape();"); } writer.newLine(); } if(!includeMethods) { return; } writeNewLine(writer, "/* Methods */"); /* Creates method for generating voxel shapes for rotatable blocks */ if(generateRotatedBounds) { writeNewLine(writer, "private ImmutableMap generateShapes(ImmutableList states)"); writeNewLine(writer, "{"); for(Element element : manager.getAllElements()) { if(element.getRotation() == 0) { String name = element.getName().toUpperCase().replaceAll(" ", "_"); double x = element.getStartX(); double y = element.getStartY(); double z = element.getStartZ(); writer.write(" "); writeField(writer, null, name, x, y, z, x + element.getWidth(), y + element.getHeight(), z + element.getDepth()); } else { writer.write(String.format(" // Skipped '%s', as it has rotation", element.getName())); } writer.newLine(); } writer.newLine(); writeNewLine(writer, " ImmutableMap.Builder builder = new ImmutableMap.Builder<>();"); writeNewLine(writer, " for(IBlockState state : states)"); writeNewLine(writer, " {"); writeNewLine(writer, " EnumFacing facing = state.getValue(HORIZONTAL_FACING);"); writeNewLine(writer, " List shapes = new ArrayList<>();"); for(Element element : manager.getAllElements()) { if(element.getRotation() == 0) { String name = element.getName().toUpperCase().replaceAll(" ", "_"); writeNewLine(writer, String.format(" shapes.add(%s[facing.getHorizontalIndex()]);", name)); } } writeNewLine(writer, " builder.put(state, VoxelShapeHelper.combineAll(shapes));"); writeNewLine(writer, " }"); writeNewLine(writer, " return builder.build();"); writeNewLine(writer, "}"); writer.newLine(); } else { writeNewLine(writer, "private VoxelShape generateShape()"); writeNewLine(writer, "{"); writeNewLine(writer, " List shapes = new ArrayList<>();"); for(Element element : manager.getAllElements()) { if(element.getRotation() == 0) { String name = element.getName().toUpperCase().replaceAll(" ", "_"); double x = element.getStartX(); double y = element.getStartY(); double z = element.getStartZ(); writer.write(" "); writeField(writer, null, name, x, y, z, x + element.getWidth(), y + element.getHeight(), z + element.getDepth()); } else { writer.write(String.format(" // Skipped '%s', as it has rotation", element.getName())); } writer.newLine(); } if(useBoundsHelper) { writeNewLine(writer, " return VoxelShapeHelper.combineAll(shapes)"); } else { writer.newLine(); writeNewLine(writer, " VoxelShape result = ShapeUtils.empty();"); writeNewLine(writer, " for(VoxelShape shape : shapes)"); writeNewLine(writer, " {"); writeNewLine(writer, " result = ShapeUtils.combine(result, shape, IBooleanFunction.OR);"); writeNewLine(writer, " }"); writeNewLine(writer, " return result.simplify();"); } writeNewLine(writer, "}"); writer.newLine(); } /* Produces the method for selection box */ writeNewLine(writer, "@Override"); writeNewLine(writer, "public VoxelShape getShape(IBlockState state, IBlockReader reader, BlockPos pos)"); writeNewLine(writer, "{"); if(generateRotatedBounds) { writeNewLine(writer, " return SHAPES.get(state);"); } else { writeNewLine(writer, " return SHAPE;"); } writeNewLine(writer, "}"); writer.newLine(); /* Produces the method for collisions */ writeNewLine(writer, "@Override"); writeNewLine(writer, "public VoxelShape getCollisionShape(IBlockState state, IBlockReader reader, BlockPos pos)"); writeNewLine(writer, "{"); if(generateRotatedBounds) { writeNewLine(writer, " return SHAPES.get(state);"); } else { writeNewLine(writer, " return SHAPE;"); } writeNewLine(writer, "}"); } else if(version == Version.V_1_12) { if(includeFields) { StringBuilder boxList = new StringBuilder("private static final List"); boxList.append(generateRotatedBounds ? "[] COLLISION_BOXES = Bounds.getRotatedBoundLists(" : " COLLISION_BOXES = Lists.newArrayList("); ModelBounds bounds = useBoundsHelper ? null : new ModelBounds(); String name = null; double x, y, z; for(Element element : manager.getAllElements()) { if(element.getRotation() != 0) { writer.write(String.format("// Skipped '%s', as it has roatation", element.getName())); } else { if(name != null) { boxList.append(", "); } x = element.getStartX(); y = element.getStartY(); z = element.getStartZ(); name = element.getName(); name = name.toUpperCase().replaceAll(" ", "_"); boxList.append(name); writeField(writer, bounds, name, x, y, z, x + element.getWidth(), y + element.getHeight(), z + element.getDepth()); } writer.newLine(); } if(name == null) { JOptionPane.showMessageDialog(creator, "No non-rotated elements were found.", "None Found", JOptionPane.INFORMATION_MESSAGE); return; } if(useBoundsHelper) { writer.newLine(); } else { writeNewLine(writer, "/**"); writeNewLine(writer, String.format("* %s generated using MrCrayfish's Model Creator https://mrcrayfish.com/tools?id=mc", includeMethods ? "AxisAlignedBBs and methods getBoundingBox, collisionRayTrace, and collisionRayTrace" : "AxisAlignedBBs")); writeNewLine(writer, "*/"); } writer.write(boxList.append(");").toString()); writer.newLine(); if(bounds != null) { bounds.write(writer); } else if(generateRotatedBounds) { writer.write("private static final AxisAlignedBB[] BOUNDING_BOX = Bounds.getBoundingBoxes(COLLISION_BOXES);"); } else { writer.write("private static final AxisAlignedBB BOUNDING_BOX = Bounds.getBoundingBox(COLLISION_BOXES);"); } } if(!includeMethods) { return; } if(includeFields) { writer.newLine(); writer.newLine(); } writeNewLine(writer, "@Override"); writeNewLine(writer, "public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos)"); writeNewLine(writer, "{"); writeNewLine(writer, " return BOUNDING_BOX%s", generateRotatedBounds ? "[state.getValue(FACING).getHorizontalIndex()];" : ";"); writeNewLine(writer, "}"); if(useBoundsHelper) { writer.newLine(); writeNewLine(writer, "@Override"); writeNewLine(writer, "protected List getCollisionBoxes(IBlockState state, World world, BlockPos pos, @Nullable Entity entity, boolean isActualState)"); writeNewLine(writer, "{"); writeNewLine(writer, " return COLLISION_BOXES%s", generateRotatedBounds ? "[state.getValue(FACING).getHorizontalIndex()];" : ";"); writer.write("}"); return; } writer.newLine(); writeNewLine(writer, "@Override"); writeNewLine(writer, "public void addCollisionBoxToList(IBlockState state, World world, BlockPos pos, AxisAlignedBB entityBox, List collidingBoxes, @Nullable Entity entity, boolean isActualState)"); writeNewLine(writer, "{"); writeNewLine(writer, " entityBox = entityBox.offset(-pos.getX(), -pos.getY(), -pos.getZ());"); writeNewLine(writer, " for (AxisAlignedBB box : COLLISION_BOXES)"); writeNewLine(writer, " {"); writeNewLine(writer, " if (entityBox.intersects(box))"); writeNewLine(writer, " collidingBoxes.add(box.offset(pos));"); writeNewLine(writer, " }"); writeNewLine(writer, "}"); writer.newLine(); writeNewLine(writer, "@Override"); writeNewLine(writer, "@Nullable"); writeNewLine(writer, "public RayTraceResult collisionRayTrace(IBlockState state, World world, BlockPos pos, Vec3d start, Vec3d end)"); writeNewLine(writer, "{"); writeNewLine(writer, " double distanceSq;"); writeNewLine(writer, " double distanceSqShortest = Double.POSITIVE_INFINITY;"); writeNewLine(writer, " RayTraceResult resultClosest = null;"); writeNewLine(writer, " RayTraceResult result;"); writeNewLine(writer, " start = start.subtract(pos.getX(), pos.getY(), pos.getZ());"); writeNewLine(writer, " end = end.subtract(pos.getX(), pos.getY(), pos.getZ());"); writeNewLine(writer, " for (AxisAlignedBB box : COLLISION_BOXES)"); writeNewLine(writer, " {"); writeNewLine(writer, " result = box.calculateIntercept(start, end);"); writeNewLine(writer, " if (result == null)"); writeNewLine(writer, " continue;"); writer.newLine(); writeNewLine(writer, " distanceSq = result.hitVec.squareDistanceTo(start);"); writeNewLine(writer, " if (distanceSq < distanceSqShortest)"); writeNewLine(writer, " {"); writeNewLine(writer, " distanceSqShortest = distanceSq;"); writeNewLine(writer, " resultClosest = result;"); writeNewLine(writer, " }"); writeNewLine(writer, " }"); writeNewLine(writer, " return resultClosest == null ? null : new RayTraceResult(RayTraceResult.Type.BLOCK, resultClosest.hitVec.addVector(pos.getX(), pos.getY(), pos.getZ()), resultClosest.sideHit, pos);"); writer.write("}"); } } private String format(double value) { return FORMAT.format(useBoundsHelper ? value : value * 0.0625); } private void writeField(BufferedWriter writer, ModelBounds bounds, String name, double minX, double minY, double minZ, double maxX, double maxY, double maxZ) throws IOException { if(version == Version.V_1_13) { if(generateRotatedBounds) { writer.write(String.format("final VoxelShape[] %s = VoxelShapeHelper.getRotatedVoxelShapes(Block.makeCuboidShape(%s, %s, %s, %s, %s, %s));", name, format(minX), format(minY), format(minZ), format(maxX), format(maxY), format(maxZ))); } else { writer.write(String.format("shapes.add(Block.makeCuboidShape(%s, %s, %s, %s, %s, %s)); // %s", format(minX), format(minY), format(minZ), format(maxX), format(maxY), format(maxZ), name)); } } else if(version == Version.V_1_12) { StringBuilder builder = new StringBuilder("private static final AxisAlignedBB"); if(generateRotatedBounds) { builder.append("[]"); } builder.append(" %s = new ").append(useBoundsHelper ? "Bounds" : "AxisAlignedBB").append("(%s, %s, %s, %s, %s, %s)"); if(useBoundsHelper) { builder.append(generateRotatedBounds ? ".getRotatedBounds()" : ".toAABB()"); } writer.write(String.format(builder.append(";").toString(), name, format(minX), format(minY), format(minZ), format(maxX), format(maxY), format(maxZ))); } if(bounds != null) { bounds.union(minX, minY, minZ, maxX, maxY, maxZ); } } private void writeNewLine(BufferedWriter writer, String line, Object... args) throws IOException { writer.write(String.format(line, args)); writer.newLine(); } private class ModelBounds { private double minX, minY, minZ, maxX, maxY, maxZ; private ModelBounds() { minX = minY = minZ = Double.MAX_VALUE; maxX = maxY = maxZ = Double.MIN_VALUE; } public void write(BufferedWriter writer) throws IOException { writeField(writer, this, "BOUNDING_BOX", minX, minY, minZ, maxX, maxY, maxZ); } private void union(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { this.minX = Math.min(this.minX, minX); this.minY = Math.min(this.minY, minY); this.minZ = Math.min(this.minZ, minZ); this.maxX = Math.max(this.maxX, maxX); this.maxY = Math.max(this.maxY, maxY); this.maxZ = Math.max(this.maxZ, maxZ); } } public enum Version { V_1_12("1.12"), V_1_13("1.13"); private String label; Version(String label) { this.label = label; } @Override public String toString() { return label; } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/ExporterModel.java ================================================ package com.mrcrayfish.modelcreator; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.texture.TextureEntry; import java.io.BufferedWriter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ExporterModel extends Exporter { private static final String[] DISPLAY_PROPERTY_ORDER = {"gui", "ground", "fixed", "head", "firstperson_righthand", "thirdperson_righthand"}; private Map textureMap = new HashMap<>(); private boolean optimize = true; private boolean includeNames = true; private boolean displayProps = true; private boolean includeNonTexturedFaces = false; public ExporterModel(ElementManager manager) { super(manager); compileTextureList(); } public void setOptimize(boolean optimize) { this.optimize = optimize; } public void setIncludeNames(boolean includeNames) { this.includeNames = includeNames; } public void setDisplayProps(boolean displayProps) { this.displayProps = displayProps; } public void setIncludeNonTexturedFaces(boolean includeNonTexturedFaces) { this.includeNonTexturedFaces = includeNonTexturedFaces; } private void compileTextureList() { for(Element cuboid : manager.getAllElements()) { for(Face face : cuboid.getAllFaces()) { if(face.getTexture() != null && face.isEnabled() && (!optimize || face.isVisible(manager))) { TextureEntry entry = face.getTexture(); textureMap.put(entry.getKey(), entry.getTexturePath().toString()); } } } } @Override protected void write(BufferedWriter writer) throws IOException { writer.write("{"); writer.newLine(); writer.write(space(1) + "\"__comment\": \"Model generated using MrCrayfish's Model Creator (https://mrcrayfish.com/tools?id=mc)\","); writer.newLine(); if(!manager.getAmbientOcc()) { writer.write("\"ambientocclusion\": " + manager.getAmbientOcc() + ","); writer.newLine(); } writeTextures(writer); writer.newLine(); if(displayProps) { writeDisplayProperties(writer); writer.newLine(); } writer.write(space(1) + "\"elements\": ["); for(int i = 0; i < manager.getElementCount() - 1; i++) { Element element = manager.getElement(i); if(canWriteElement(element)) { writeElement(writer, manager.getElement(i)); writer.write(","); } } if(manager.getElementCount() > 0) { Element element = manager.getElement(manager.getElementCount() - 1); if(canWriteElement(element)) { writeElement(writer, manager.getElement(manager.getElementCount() - 1)); } } writer.newLine(); writer.write(space(1) + "]"); writer.newLine(); writer.write("}"); } private void writeTextures(BufferedWriter writer) throws IOException { writer.write(space(1) + "\"textures\": {"); writer.newLine(); if(manager.getParticle() != null) { TextureEntry entry = manager.getParticle(); writer.write(space(2) + "\"particle\": \"" + entry.getModId() + ":"); if(!entry.getDirectory().isEmpty()) { writer.write(entry.getDirectory() + "/"); } writer.write(entry.getName() + "\""); if(textureMap.size() > 0) { writer.write(","); } writer.newLine(); } List ids = new ArrayList<>(textureMap.keySet()); for(int i = 0; i < ids.size() - 1; i++) { String id = ids.get(i); String texture = textureMap.get(id); writer.write(space(2) + "\"" + id + "\": \"" + texture + "\""); writer.write(","); writer.newLine(); } if(ids.size() > 0) { String id = ids.get(ids.size() - 1); String texture = textureMap.get(id); writer.write(space(2) + "\"" + id + "\": \"" + texture + "\""); writer.newLine(); } writer.write(space(1) + "},"); } private void writeElement(BufferedWriter writer, Element cuboid) throws IOException { writer.newLine(); writer.write(space(2) + "{"); writer.newLine(); if(includeNames) { writer.write(space(3) + "\"name\": \"" + cuboid.getName() + "\","); writer.newLine(); } writeBounds(writer, cuboid); writer.newLine(); if(!cuboid.isShaded()) { writeShade(writer, cuboid); writer.newLine(); } if(cuboid.getRotation() != 0) { writeRotation(writer, cuboid); writer.newLine(); } writeFaces(writer, cuboid); writer.newLine(); writer.write(space(2) + "}"); } private void writeBounds(BufferedWriter writer, Element cuboid) throws IOException { writer.write(space(3) + "\"from\": [ " + FORMAT.format(cuboid.getStartX()) + ", " + FORMAT.format(cuboid.getStartY()) + ", " + FORMAT.format(cuboid.getStartZ()) + " ], "); writer.newLine(); writer.write(space(3) + "\"to\": [ " + FORMAT.format(cuboid.getStartX() + cuboid.getWidth()) + ", " + FORMAT.format(cuboid.getStartY() + cuboid.getHeight()) + ", " + FORMAT.format(cuboid.getStartZ() + cuboid.getDepth()) + " ], "); } private void writeShade(BufferedWriter writer, Element cuboid) throws IOException { writer.write(space(3) + "\"shade\": " + cuboid.isShaded() + ","); } private void writeRotation(BufferedWriter writer, Element cuboid) throws IOException { writer.write(space(3) + "\"rotation\": { "); writer.write("\"origin\": [ " + FORMAT.format(cuboid.getOriginX()) + ", " + FORMAT.format(cuboid.getOriginY()) + ", " + FORMAT.format(cuboid.getOriginZ()) + " ], "); writer.write("\"axis\": \"" + Element.parseAxis(cuboid.getRotationAxis()) + "\", "); writer.write("\"angle\": " + cuboid.getRotation()); if(cuboid.shouldRescale()) { writer.write(", \"rescale\": " + cuboid.shouldRescale()); } writer.write(" },"); } private void writeFaces(BufferedWriter writer, Element cuboid) throws IOException { writer.write(space(3) + "\"faces\": {"); writer.newLine(); /* Creates a list of all the valid faces to export */ List validFaces = new ArrayList<>(); for(Face face : cuboid.getAllFaces()) { if(face.isEnabled() && (includeNonTexturedFaces || face.getTexture() != null) && (!optimize || face.isVisible(manager))) { validFaces.add(face); } } /* Writes the valid faces to the writer */ for(int i = 0; i < validFaces.size() - 1; i++) { Face face = validFaces.get(i); writeFace(writer, face); writer.write(","); writer.newLine(); } if(validFaces.size() > 0) { writeFace(writer, validFaces.get(validFaces.size() - 1)); } writer.newLine(); writer.write(space(3) + "}"); } private void writeFace(BufferedWriter writer, Face face) throws IOException { writer.write(space(4) + "\"" + Face.getFaceName(face.getSide()) + "\": { "); if(face.getTexture() != null) { writer.write("\"texture\": \"#" + face.getTexture().getKey() + "\""); writer.write(", \"uv\": [ " + FORMAT.format(face.getStartU()) + ", " + FORMAT.format(face.getStartV()) + ", " + FORMAT.format(face.getEndU()) + ", " + FORMAT.format(face.getEndV()) + " ]"); if(face.getRotation() > 0) { writer.write(", \"rotation\": " + face.getRotation() * 90); } if(face.isCullfaced()) { writer.write(", \"cullface\": \"" + Face.getFaceName(face.getSide()) + "\""); } if(face.isTintIndexEnabled() && face.getTintIndex() >= 0) { writer.write(", \"tintindex\": " + face.getTintIndex()); } } writer.write(" }"); } private void writeDisplayProperties(BufferedWriter writer) throws IOException { Map entries = manager.getDisplayProperties().getEntries(); List ids = new ArrayList<>(); for(String id : DISPLAY_PROPERTY_ORDER) { DisplayProperties.Entry entry = entries.get(id); if(entry != null && entry.isEnabled()) { ids.add(id); } } writer.write(space(1) + "\"display\": {"); writer.newLine(); for(int i = 0; i < ids.size() - 1; i++) { String key = ids.get(i); writeDisplayEntry(writer, key, entries.get(key)); writer.write(","); writer.newLine(); } if(ids.size() > 0) { String key = ids.get(ids.size() - 1); writeDisplayEntry(writer, key, entries.get(key)); } writer.newLine(); writer.write(space(1) + "},"); } private void writeDisplayEntry(BufferedWriter writer, String id, DisplayProperties.Entry entry) throws IOException { writer.write(space(2) + "\"" + id + "\": {"); writer.newLine(); writer.write(space(3) + String.format("\"rotation\": [ %s, %s, %s ],", FORMAT.format(entry.getRotationX()), FORMAT.format(entry.getRotationY()), FORMAT.format(entry.getRotationZ()))); writer.newLine(); writer.write(space(3) + String.format("\"translation\": [ %s, %s, %s ],", FORMAT.format(entry.getTranslationX()), FORMAT.format(entry.getTranslationY()), FORMAT.format(entry.getTranslationZ()))); writer.newLine(); writer.write(space(3) + String.format("\"scale\": [ %s, %s, %s ]", FORMAT.format(entry.getScaleX()), FORMAT.format(entry.getScaleY()), FORMAT.format(entry.getScaleZ()))); writer.newLine(); writer.write(space(2) + "}"); } private boolean canWriteElement(Element element) { for(Face face : element.getAllFaces()) { if(face.isEnabled() && (includeNonTexturedFaces || face.getTexture() != null) && (!optimize || face.isVisible(manager))) { return true; } } return false; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Icons.java ================================================ package com.mrcrayfish.modelcreator; import javax.swing.*; public class Icons { public static Icon bin; public static Icon new_; public static Icon import_; public static Icon export; public static Icon texture; public static Icon clear_texture; public static Icon copy; public static Icon copy_small; public static Icon clipboard; public static Icon clipboard_texture; public static Icon transparent; public static Icon coin; public static Icon load; public static Icon disk; public static Icon exit; public static Icon settings; public static Icon cube; public static Icon light_off; public static Icon light_on; public static Icon arrow_up; public static Icon arrow_down; public static Icon facebook; public static Icon twitter; public static Icon reddit; public static Icon imgur; public static Icon patreon; public static Icon planet_minecraft; public static Icon minecraft_forum; public static Icon github; public static Icon model_cauldron; public static Icon model_chair; public static Icon extract; public static Icon mojang; public static Icon java; public static Icon undo; public static Icon redo; public static Icon optimize; public static Icon rotate; public static Icon rotate_clockwise; public static Icon rotate_counter_clockwise; public static Icon refresh; public static Icon gallery; public static Icon bin2; public static Icon edit; public static Icon edit_image; public static void init(Class clazz) { ClassLoader loader = clazz.getClassLoader(); cube = new ImageIcon(loader.getResource("icons/cube.png")); bin = new ImageIcon(loader.getResource("icons/bin.png")); new_ = new ImageIcon(loader.getResource("icons/new.png")); import_ = new ImageIcon(loader.getResource("icons/import.png")); export = new ImageIcon(loader.getResource("icons/export.png")); texture = new ImageIcon(loader.getResource("icons/texture.png")); clear_texture = new ImageIcon(loader.getResource("icons/clear_texture.png")); copy = new ImageIcon(loader.getResource("icons/copy.png")); copy_small = new ImageIcon(loader.getResource("icons/copy_small.png")); clipboard = new ImageIcon(loader.getResource("icons/clipboard.png")); clipboard_texture = new ImageIcon(loader.getResource("icons/paste_texture.png")); transparent = new ImageIcon(loader.getResource("icons/transparent.png")); coin = new ImageIcon(loader.getResource("icons/coin.png")); load = new ImageIcon(loader.getResource("icons/load.png")); disk = new ImageIcon(loader.getResource("icons/disk.png")); exit = new ImageIcon(loader.getResource("icons/exit.png")); settings = new ImageIcon(loader.getResource("icons/settings.png")); extract = new ImageIcon(loader.getResource("icons/extract.png")); light_off = new ImageIcon(loader.getResource("icons/box_off.png")); light_on = new ImageIcon(loader.getResource("icons/box_on.png")); arrow_up = new ImageIcon(loader.getResource("icons/arrow_up.png")); arrow_down = new ImageIcon(loader.getResource("icons/arrow_down.png")); facebook = new ImageIcon(loader.getResource("icons/facebook.png")); twitter = new ImageIcon(loader.getResource("icons/twitter.png")); reddit = new ImageIcon(loader.getResource("icons/reddit.png")); imgur = new ImageIcon(loader.getResource("icons/imgur.png")); patreon = new ImageIcon(loader.getResource("icons/patreon.png")); planet_minecraft = new ImageIcon(loader.getResource("icons/planet_minecraft.png")); minecraft_forum = new ImageIcon(loader.getResource("icons/minecraft_forum.png")); github = new ImageIcon(loader.getResource("icons/github.png")); model_cauldron = new ImageIcon(loader.getResource("icons/model_cauldron.png")); model_chair = new ImageIcon(loader.getResource("icons/model_chair.png")); mojang = new ImageIcon(loader.getResource("icons/mojang.png")); java = new ImageIcon(loader.getResource("icons/java.png")); undo = new ImageIcon(loader.getResource("icons/undo.png")); redo = new ImageIcon(loader.getResource("icons/redo.png")); optimize = new ImageIcon(loader.getResource("icons/optimize.png")); rotate = new ImageIcon(loader.getResource("icons/rotate.png")); rotate_clockwise = new ImageIcon(loader.getResource("icons/rotate_clockwise.png")); rotate_counter_clockwise = new ImageIcon(loader.getResource("icons/rotate_anticlockwise.png")); refresh = new ImageIcon(loader.getResource("icons/refresh.png")); gallery = new ImageIcon(loader.getResource("icons/gallery.png")); bin2 = new ImageIcon(loader.getResource("icons/bin2.png")); edit = new ImageIcon(loader.getResource("icons/edit.png")); edit_image = new ImageIcon(loader.getResource("icons/edit_image.png")); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Importer.java ================================================ package com.mrcrayfish.modelcreator; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mrcrayfish.modelcreator.component.TextureManager; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.texture.TextureEntry; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.ResourceBundle; public class Importer { private Map textureMap = new HashMap<>(); private String[] faceNames = {"north", "east", "south", "west", "up", "down"}; private String[] displayNames = {"gui", "ground", "fixed", "head", "firstperson_righthand", "firstperson_lefthand", "thirdperson_righthand", "thirdperson_lefthand"}; // Input File private String inputPath; // Model Variables private ElementManager manager; public Importer(ElementManager manager, String outputPath) { this.manager = manager; this.inputPath = outputPath; } public void importFromJSON() { File path = new File(inputPath); if(path.exists() && path.isFile()) { FileReader fr; BufferedReader reader; try { fr = new FileReader(path); reader = new BufferedReader(fr); readComponents(reader, manager, path.getParentFile()); reader.close(); fr.close(); } catch(IOException e) { e.printStackTrace(); } } } private void readComponents(BufferedReader reader, ElementManager manager, File dir) throws IOException { manager.clearElements(); manager.setParticle(null); manager.setDisplayProperties(DisplayProperties.MODEL_CREATOR_BLOCK); JsonParser parser = new JsonParser(); JsonElement read = parser.parse(reader); if(read.isJsonObject()) { JsonObject obj = read.getAsJsonObject(); if(obj.has("parent") && obj.get("parent").isJsonPrimitive()) { String parent = obj.get("parent").getAsString(); File file = new File(dir, parent + ".json"); if(!file.exists()) { parent = parent.substring(parent.lastIndexOf('/') + 1, parent.length()); file = new File(dir, parent + ".json"); } if(file.exists()) { // load textures loadTextures(dir, obj); // Load Parent FileReader fr = new FileReader(file); reader = new BufferedReader(fr); readComponents(reader, manager, file.getParentFile()); reader.close(); fr.close(); } return; } // load textures loadTextures(dir, obj); // load display properties if(obj.has("display") && obj.get("display").isJsonObject()) { readDisplayProperties(obj.getAsJsonObject("display"), manager); } // load elements if(obj.has("elements") && obj.get("elements").isJsonArray()) { JsonArray elements = obj.get("elements").getAsJsonArray(); for(int i = 0; i < elements.size(); i++) { if(elements.get(i).isJsonObject()) { readElement(elements.get(i).getAsJsonObject(), manager); } } } manager.setAmbientOcc(true); if(obj.has("ambientocclusion") && obj.get("ambientocclusion").isJsonPrimitive()) { manager.setAmbientOcc(obj.get("ambientocclusion").getAsBoolean()); } } } private void loadTextures(File file, JsonObject obj) { if(obj.has("textures") && obj.get("textures").isJsonObject()) { JsonObject textures = obj.get("textures").getAsJsonObject(); for(Entry entry : textures.entrySet()) { if(entry.getValue().isJsonPrimitive()) { String key = entry.getKey().trim().toLowerCase(Locale.ENGLISH); String value = entry.getValue().getAsString().trim().toLowerCase(Locale.ENGLISH); if(!textureMap.containsKey(key)) { if(key.equals("particle")) { manager.setParticle(this.loadTexture(file, key, value)); } else if(!value.startsWith("#")) { textureMap.put(key, value); this.loadTexture(file, key, value); } } } } } } private TextureEntry loadTexture(File project, String id, String texture) { TexturePath texturePath = new TexturePath(texture); /* Try loading textures as project format */ if(project != null) { File path = new File(project, "textures"); if(path.exists() && path.isDirectory()) { File textureFile = new File(path, texturePath.getName() + ".png"); if(textureFile.exists() && textureFile.isFile()) { return TextureManager.addImage(id, texturePath, textureFile); } } /* V2 of project file format uses assets folder */ File assets = new File(project, "assets"); if(assets.exists() && assets.isDirectory()) { File textureFile = new File(assets, texturePath.toRelativePath()); if(textureFile.exists() && textureFile.isFile()) { return TextureManager.addImage(id, texturePath, textureFile); } } } /* Try loading textures as if it was from assets */ File parent = project; if(parent != null) { while((parent = parent.getParentFile()) != null) { if(parent.getName().equals("assets")) { File textureFile = new File(parent, texturePath.toRelativePath()); if(textureFile.exists() && textureFile.isFile()) { return TextureManager.addImage(id, texturePath, textureFile); } } else if(parent.getName().equals(texturePath.getModId())) { File textureFile = new File(parent, "textures" + File.separator + texturePath.getDirectory() + File.separator + texturePath.getName() + ".png"); if(textureFile.exists() && textureFile.isFile()) { return TextureManager.addImage(id, texturePath, textureFile); } } } } /* Try loading textures from assets directory */ if(Settings.getAssetsDir() != null) { String path = Settings.getAssetsDir() + File.separator + texturePath.toRelativePath(); File textureFile = new File(path); if(textureFile.exists()) { return TextureManager.addImage(id, texturePath, textureFile); } } return null; } private void readDisplayProperties(JsonObject obj, ElementManager manager) { DisplayProperties properties = manager.getDisplayProperties(); properties.getEntries().forEach((s, entry) -> entry.setEnabled(false)); for(String displayName : displayNames) { if(obj.has(displayName) && obj.get(displayName).isJsonObject()) { readEntry(obj.getAsJsonObject(displayName), displayName, properties); } } } private void readEntry(JsonObject obj, String id, DisplayProperties properties) { DisplayProperties.Entry entry = new DisplayProperties.Entry(id, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0); if(obj.has("rotation") && obj.get("rotation").isJsonArray()) { JsonArray array = obj.get("rotation").getAsJsonArray(); if(array.size() == 3) { entry.setRotationX(array.get(0).getAsDouble()); entry.setRotationY(array.get(1).getAsDouble()); entry.setRotationZ(array.get(2).getAsDouble()); } } if(obj.has("translation") && obj.get("translation").isJsonArray()) { JsonArray array = obj.get("translation").getAsJsonArray(); if(array.size() == 3) { entry.setTranslationX(array.get(0).getAsDouble()); entry.setTranslationY(array.get(1).getAsDouble()); entry.setTranslationZ(array.get(2).getAsDouble()); } } if(obj.has("scale") && obj.get("scale").isJsonArray()) { JsonArray array = obj.get("scale").getAsJsonArray(); if(array.size() == 3) { entry.setScaleX(array.get(0).getAsDouble()); entry.setScaleY(array.get(1).getAsDouble()); entry.setScaleZ(array.get(2).getAsDouble()); } } properties.getEntries().put(id, entry); } private void readElement(JsonObject obj, ElementManager manager) { String name = "Element"; JsonArray from = null; JsonArray to = null; if(obj.has("name") && obj.get("name").isJsonPrimitive()) { name = obj.get("name").getAsString(); } else if(obj.has("comment") && obj.get("comment").isJsonPrimitive()) { name = obj.get("comment").getAsString(); } else if(obj.has("__comment") && obj.get("__comment").isJsonPrimitive()) { name = obj.get("__comment").getAsString(); } if(obj.has("from") && obj.get("from").isJsonArray()) { from = obj.get("from").getAsJsonArray(); } if(obj.has("to") && obj.get("to").isJsonArray()) { to = obj.get("to").getAsJsonArray(); } if(from != null && to != null) { double x = from.get(0).getAsDouble(); double y = from.get(1).getAsDouble(); double z = from.get(2).getAsDouble(); double w = to.get(0).getAsDouble() - x; double h = to.get(1).getAsDouble() - y; double d = to.get(2).getAsDouble() - z; Element element = new Element(w, h, d); element.setName(name); element.setStartX(x); element.setStartY(y); element.setStartZ(z); if(obj.has("rotation") && obj.get("rotation").isJsonObject()) { JsonObject rot = obj.get("rotation").getAsJsonObject(); if(rot.has("origin") && rot.get("origin").isJsonArray()) { JsonArray origin = rot.get("origin").getAsJsonArray(); double ox = origin.get(0).getAsDouble(); double oy = origin.get(1).getAsDouble(); double oz = origin.get(2).getAsDouble(); element.setOriginX(ox); element.setOriginY(oy); element.setOriginZ(oz); } if(rot.has("axis") && rot.get("axis").isJsonPrimitive()) { element.setRotationAxis(Element.parseAxisString(rot.get("axis").getAsString())); } if(rot.has("angle") && rot.get("angle").isJsonPrimitive()) { element.setRotation(rot.get("angle").getAsDouble()); } if(rot.has("rescale") && rot.get("rescale").isJsonPrimitive()) { element.setRescale(rot.get("rescale").getAsBoolean()); } } element.setShade(true); if(obj.has("shade") && obj.get("shade").isJsonPrimitive()) { element.setShade(obj.get("shade").getAsBoolean()); } for(Face face : element.getAllFaces()) { face.setEnabled(false); } if(obj.has("faces") && obj.get("faces").isJsonObject()) { JsonObject faces = obj.get("faces").getAsJsonObject(); for(String faceName : faceNames) { if(faces.has(faceName) && faces.get(faceName).isJsonObject()) { readFace(faces.get(faceName).getAsJsonObject(), faceName, element); } } } manager.addElement(element); } } private void readFace(JsonObject obj, String name, Element element) { Face face = null; for(Face f : element.getAllFaces()) { if(f.getSide() == Face.getFaceSide(name)) { face = f; } } if(face != null) { face.setEnabled(true); // automatically set uv if not specified face.setEndU(element.getFaceDimension(face.getSide()).getWidth()); face.setEndV(element.getFaceDimension(face.getSide()).getHeight()); face.setAutoUVEnabled(true); if(obj.has("uv") && obj.get("uv").isJsonArray()) { JsonArray uv = obj.get("uv").getAsJsonArray(); double uStart = uv.get(0).getAsDouble(); double vStart = uv.get(1).getAsDouble(); double uEnd = uv.get(2).getAsDouble(); double vEnd = uv.get(3).getAsDouble(); face.setStartU(uStart); face.setStartV(vStart); face.setEndU(uEnd); face.setEndV(vEnd); if(element.getFaceDimension(face.getSide()).getWidth() != face.getEndU() - face.getStartU() || element.getFaceDimension(face.getSide()).getHeight() != face.getEndV() - face.getStartV()) { face.setAutoUVEnabled(false); } } if(obj.has("texture") && obj.get("texture").isJsonPrimitive()) { String id = obj.get("texture").getAsString().replace("#", ""); TextureEntry entry = TextureManager.getTexture(id); if(entry != null) { face.setTexture(entry); } } if(obj.has("rotation") && obj.get("rotation").isJsonPrimitive()) { face.setRotation((int) obj.get("rotation").getAsDouble() / 90); } // TODO cullface with different direction than face,tintindex if(obj.has("cullface") && obj.get("cullface").isJsonPrimitive()) { String cullface = obj.get("cullface").getAsString(); if(cullface.equals(Face.getFaceName(face.getSide()))) { face.setCullface(true); } } if(obj.has("tintindex") && obj.get("tintindex").isJsonPrimitive()) { int tintIndex = obj.get("tintindex").getAsInt(); if(tintIndex >= 0) { face.setTintIndexEnabled(true); face.setTintIndex(tintIndex); } } } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/ModelCreator.java ================================================ package com.mrcrayfish.modelcreator; import com.mrcrayfish.modelcreator.component.TextureManager; import com.mrcrayfish.modelcreator.dialog.WelcomeDialog; import com.mrcrayfish.modelcreator.display.CanvasRenderer; import com.mrcrayfish.modelcreator.display.render.StandardRenderer; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementCellEntry; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.ElementManagerState; import com.mrcrayfish.modelcreator.panels.SidebarPanel; import com.mrcrayfish.modelcreator.screenshot.PendingScreenshot; import com.mrcrayfish.modelcreator.screenshot.Screenshot; import com.mrcrayfish.modelcreator.sidebar.Sidebar; import com.mrcrayfish.modelcreator.sidebar.UVSidebar; import com.mrcrayfish.modelcreator.texture.TextureAtlas; import com.mrcrayfish.modelcreator.texture.TextureEntry; import com.mrcrayfish.modelcreator.util.FontManager; import com.mrcrayfish.modelcreator.util.KeyboardUtil; import org.lwjgl.LWJGLException; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.AWTGLCanvas; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.PixelFormat; import org.lwjgl.util.glu.GLU; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import static org.lwjgl.opengl.GL11.*; public class ModelCreator extends JFrame { public static final Color BACKGROUND = new Color(227, 227, 234); // Canvas Variables private final static AtomicReference newCanvasSize = new AtomicReference<>(); private Canvas canvas; private int width = 990, height = 800; // Swing Components private JScrollPane scroll; private Camera camera; private SidebarPanel manager; private Element grabbed = null; // Texture Loading Cache private PendingScreenshot screenshot = null; private int lastMouseX, lastMouseY; private boolean grabbing = false; private boolean closeRequested = false; private boolean performedChange = false; private boolean grabbingInSidebar = false; /* Sidebar Variables */ private final int SIDEBAR_WIDTH = 130; private Sidebar activeSidebar = null; public static Sidebar uvSidebar; public static boolean isUVSidebarOpen = false; /* Key Events */ private Set keyDown = new HashSet<>(); private List keyActions = new ArrayList<>(); private static boolean changedCanvas = false; private static CanvasRenderer standardRenderer = new StandardRenderer(); private static CanvasRenderer canvasRenderer = standardRenderer; private boolean debugMode = false; public ModelCreator(String title) { super(title); setPreferredSize(new Dimension(1200, 815)); setMinimumSize(new Dimension(1200, 500)); setLayout(new BorderLayout(10, 0)); setIconImages(getIcons()); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(e -> { if(e.getID() == KeyEvent.KEY_PRESSED && !keyDown.contains(e.getKeyCode())) { keyDown.add(e.getKeyCode()); ModelCreator.this.handleKeyAction(e.getKeyCode(), e.getModifiers(), true, true); } else if(e.getID() == KeyEvent.KEY_RELEASED) { keyDown.remove(e.getKeyCode()); ModelCreator.this.handleKeyAction(e.getKeyCode(), e.getModifiers(), true, false); } return false; }); try { canvas = new AWTGLCanvas(); canvas.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { newCanvasSize.set(canvas.getSize()); } }); addWindowFocusListener(new WindowAdapter() { @Override public void windowGainedFocus(WindowEvent e) { canvas.requestFocusInWindow(); } }); } catch(LWJGLException e) { e.printStackTrace(); System.exit(1); } initComponents(); registerShortcuts(); uvSidebar = new UVSidebar("UV Editor", manager); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { closeRequested = true; } }); manager.updateValues(); pack(); setVisible(true); setLocationRelativeTo(null); SwingUtilities.invokeLater(() -> WelcomeDialog.show(ModelCreator.this)); createDisplay(); loop(); Display.destroy(); dispose(); System.exit(0); } private void initComponents() { Icons.init(this.getClass()); setupMenuBar(); canvas.setFocusable(true); add(canvas, BorderLayout.CENTER); manager = new SidebarPanel(this); scroll = new JScrollPane(manager); scroll.setBorder(BorderFactory.createEmptyBorder()); scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); add(scroll, BorderLayout.EAST); StateManager.pushState(manager); } private void registerShortcuts() { this.keyActions.add(new KeyAction(KeyEvent.VK_E, Keyboard.KEY_E, (modifiers, pressed) -> { if(pressed && modifiers == InputEvent.CTRL_MASK) { manager.newElement(); } })); this.keyActions.add(new KeyAction(KeyEvent.VK_D, Keyboard.KEY_D, (modifiers, pressed) -> { if(pressed && (modifiers & InputEvent.CTRL_MASK) != 0 && (modifiers & InputEvent.SHIFT_MASK) != 0 && (modifiers & InputEvent.ALT_MASK) != 0) { debugMode = !debugMode; } })); this.keyActions.add(new KeyAction(KeyEvent.VK_F, Keyboard.KEY_F, (modifiers, pressed) -> { if(pressed && modifiers == InputEvent.CTRL_MASK) { ElementCellEntry entry = manager.getSelectedElementEntry(); if(entry != null) { entry.toggleVisibility(); manager.getList().repaint(); } } })); this.keyActions.add(new KeyAction(KeyEvent.VK_D, Keyboard.KEY_D, (modifiers, pressed) -> { if(pressed && modifiers == InputEvent.CTRL_MASK) { manager.deleteElement(); } })); } private List getIcons() { List icons = new ArrayList<>(); icons.add(Toolkit.getDefaultToolkit().getImage("res/icons/set/icon_16x.png")); icons.add(Toolkit.getDefaultToolkit().getImage("res/icons/set/icon_32x.png")); icons.add(Toolkit.getDefaultToolkit().getImage("res/icons/set/icon_64x.png")); icons.add(Toolkit.getDefaultToolkit().getImage("res/icons/set/icon_128x.png")); return icons; } public int getCanvasWidth() { return width; } public int getCanvasHeight() { return height; } public int getCanvasOffset() { return activeSidebar == null ? 0 : getHeight() < 805 ? SIDEBAR_WIDTH * 2 : SIDEBAR_WIDTH; } private void setupMenuBar() { JPopupMenu.setDefaultLightWeightPopupEnabled(false); setJMenuBar(new com.mrcrayfish.modelcreator.component.Menu(this)); } private void createDisplay() { try { Display.setVSyncEnabled(true); Display.setInitialBackground(0.92F, 0.92F, 0.93F); Display.setParent(canvas); } catch(LWJGLException e) { e.printStackTrace(); } try { Display.create((new PixelFormat(8, 0, 0, 4)).withDepthBits(24)); return; } catch(LWJGLException e) { e.printStackTrace(); } try { Thread.sleep(1000L); } catch(InterruptedException ignored) { } try { Display.create(); } catch(LWJGLException e) { e.printStackTrace(); } } private void loop() { TextureAtlas.load(); camera = new Camera(60F, (float) Display.getWidth() / (float) Display.getHeight(), 0.3F, 1000F); long lastTime = System.nanoTime(); double delta = 0.0; double ns = 1000000000.0 / 60.0; long timer = System.currentTimeMillis(); int updates = 0; int frames = 0; while(!Display.isCloseRequested() && !getCloseRequested()) { long now = System.nanoTime(); delta += (now - lastTime) / ns; lastTime = now; if(delta >= 1.0) { tick(); updates++; delta--; } render(frames / 60.0F); frames++; if(System.currentTimeMillis() - timer > 1000) { timer += 1000; updates = 0; frames = 0; } } } private void tick() { Animation.tick(); } private void render(float partialTicks) { Animation.setPartialTicks(partialTicks); TextureManager.processPendingTextures(); Dimension newDim = newCanvasSize.getAndSet(null); if (newDim != null) { width = newDim.width; height = newDim.height; } this.handleKeyboardInput(); GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); this.draw(); Display.update(); if(screenshot != null) { if(screenshot.getFile() != null) { Screenshot.getScreenshot(width, height, screenshot.getCallback(), screenshot.getFile()); } else { Screenshot.getScreenshot(width, height, screenshot.getCallback()); } screenshot = null; } } private void handleKeyboardInput() { while(Keyboard.next()) { int modifiers = 0; if(KeyboardUtil.isCtrlKeyDown()) { modifiers += InputEvent.CTRL_MASK; } if(KeyboardUtil.isShiftKeyDown()) { modifiers += InputEvent.SHIFT_MASK; } if(KeyboardUtil.isAltKeyDown()) { modifiers += InputEvent.ALT_MASK; } int code = Keyboard.getEventKey(); int finalModifiers = modifiers; if(Keyboard.getEventKeyState()) { SwingUtilities.invokeLater(() -> this.handleKeyAction(code, finalModifiers, false, true)); } else { SwingUtilities.invokeLater(() -> this.handleKeyAction(code, finalModifiers, false, false)); } } } private void draw() { if(changedCanvas) { canvasRenderer.onInit(camera); changedCanvas = false; } int offset = activeSidebar == null ? 0 : getHeight() < 805 ? SIDEBAR_WIDTH * 2 : SIDEBAR_WIDTH; glViewport(offset, 0, width - offset, height); this.handleInput(offset); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLU.gluPerspective(60F, (float) (width - offset) / (float) height, 0.3F, 1000F); canvasRenderer.onRenderPerspective(this, manager, camera); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLU.gluOrtho2D(0, width, height, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); canvasRenderer.onRenderOverlay(manager, camera, this); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLU.gluOrtho2D(0, width, height, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); drawOverlay(offset); } private void drawOverlay(int offset) { glDisable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glPushMatrix(); { glColor3f(0.58F, 0.58F, 0.58F); glLineWidth(2F); glBegin(GL_LINES); { glVertex2i(offset, 0); glVertex2i(width, 0); glVertex2i(width, 0); glVertex2i(width, height); glVertex2i(offset, height); glVertex2i(offset, 0); glVertex2i(offset, height); glVertex2i(width, height); } glEnd(); } glPopMatrix(); if(debugMode) { glPushMatrix(); { List states = StateManager.getStates(); for(int i = 0; i < states.size(); i++) { ElementManagerState managerState = states.get(i); String text = "No Elements"; if(managerState.getElements().size() > 0) { text = managerState.getElements().toString(); } if(StateManager.getTailIndex() == i) { text = text + " <<<"; } GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); FontManager.BEBAS_NEUE_20.drawString(10, 10 + i * 20, text, new org.newdawn.slick.Color(1, 1, 1)); GL11.glDisable(GL11.GL_BLEND); } } glPopMatrix(); } if(activeSidebar != null) { activeSidebar.draw(offset, width, height, getHeight()); } if(canvasRenderer == standardRenderer) { glPushMatrix(); { glTranslatef(width - 80, height - 80, 0); glLineWidth(2F); glRotated(-camera.getRY(), 0, 0, 1); GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); FontManager.BEBAS_NEUE_20.drawString(-5, -75, "N", new org.newdawn.slick.Color(1, 1, 1)); GL11.glDisable(GL11.GL_BLEND); glColor3d(0.6, 0.6, 0.6); glBegin(GL_LINES); { glVertex2i(0, -50); glVertex2i(0, 50); glVertex2i(-50, 0); glVertex2i(50, 0); } glEnd(); glColor3d(0.3, 0.3, 0.6); glBegin(GL_TRIANGLES); { glVertex2i(-5, -45); glVertex2i(0, -50); glVertex2i(5, -45); glVertex2i(-5, 45); glVertex2i(0, 50); glVertex2i(5, 45); glVertex2i(-45, -5); glVertex2i(-50, 0); glVertex2i(-45, 5); glVertex2i(45, -5); glVertex2i(50, 0); glVertex2i(45, 5); } glEnd(); } glPopMatrix(); } /*glColor3f(1.0F, 1.0F, 1.0F); glBindTexture(GL_TEXTURE_2D, 6); glBegin(GL_QUADS); { glTexCoord2d(0.0, 0.0); glVertex2f(0, 0); glTexCoord2d(1.0, 0.0); glVertex2f(300, 0); glTexCoord2d(1.0, 1.0); glVertex2f(300, 300); glTexCoord2d(0.0, 1.0); glVertex2f(0, 300); } glEnd();*/ } private void handleInput(int offset) { final float cameraMod = Math.abs(camera.getZ()); if(Mouse.isButtonDown(0) || Mouse.isButtonDown(1)) { if(!grabbingInSidebar) { if(!grabbing && Mouse.getX() < offset) { grabbingInSidebar = true; } if(!grabbing) { lastMouseX = Mouse.getX(); lastMouseY = Mouse.getY(); grabbing = true; uvSidebar.handleMouseInput(0, Mouse.getX(), Mouse.getY(), true); } } } else if(grabbing) { if(grabbed != null && performedChange) { StateManager.pushState(manager); performedChange = false; } grabbing = false; grabbed = null; } else if(grabbingInSidebar) { uvSidebar.handleMouseInput(0, Mouse.getX(), Mouse.getY(), false); grabbingInSidebar = false; } if(grabbingInSidebar) { activeSidebar.handleInput(getHeight()); } else { if(Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && canvasRenderer == standardRenderer) { if(grabbed == null) { if(Mouse.isButtonDown(0) || Mouse.isButtonDown(1)) { int sel = select(Mouse.getX(), Mouse.getY()); if(sel >= 0) { grabbed = manager.getAllElements().get(sel); manager.setSelectedElement(sel); } else { grabbed = null; manager.setSelectedElement(-1); } } } else { Element element = grabbed; int state = getCameraState(camera); int newMouseX = Mouse.getX(); int newMouseY = Mouse.getY(); int xMovement = (newMouseX - lastMouseX) / 20; int yMovement = (newMouseY - lastMouseY) / 20; if(xMovement != 0 | yMovement != 0) { if(Mouse.isButtonDown(0)) { switch(state) { case 0: element.addStartX(xMovement); element.addStartY(yMovement); break; case 1: element.addStartZ(xMovement); element.addStartY(yMovement); break; case 2: element.addStartX(-xMovement); element.addStartY(yMovement); break; case 3: element.addStartZ(-xMovement); element.addStartY(yMovement); break; case 4: element.addStartX(xMovement); element.addStartZ(-yMovement); break; case 5: element.addStartX(yMovement); element.addStartZ(xMovement); break; case 6: element.addStartX(-xMovement); element.addStartZ(yMovement); break; case 7: element.addStartX(-yMovement); element.addStartZ(-xMovement); break; } } else if(Mouse.isButtonDown(1)) { switch(state) { case 0: element.addHeight(yMovement); element.addWidth(xMovement); break; case 1: element.addHeight(yMovement); element.addDepth(xMovement); break; case 2: element.addHeight(yMovement); element.addWidth(-xMovement); break; case 3: element.addHeight(yMovement); element.addDepth(-xMovement); break; case 4: element.addDepth(-yMovement); element.addWidth(xMovement); break; case 5: element.addDepth(xMovement); element.addWidth(yMovement); break; case 6: element.addDepth(yMovement); element.addWidth(-xMovement); break; case 7: element.addDepth(-xMovement); element.addWidth(-yMovement); break; case 8: element.addDepth(-yMovement); element.addWidth(xMovement); break; } } if(xMovement != 0) { lastMouseX = newMouseX; } if(yMovement != 0) { lastMouseY = newMouseY; } manager.updateValues(); element.updateEndUVs(); performedChange = true; } } } else { if(Mouse.isButtonDown(0)) { final float modifier = (cameraMod * 0.05f); camera.addX(Mouse.getDX() * 0.01F * modifier); camera.addY(Mouse.getDY() * 0.01F * modifier); } else if(Mouse.isButtonDown(1)) { final float modifier = applyLimit(cameraMod * 0.1f); camera.rotateX(-(Mouse.getDY() * 0.5F) * modifier); final float rxAbs = Math.abs(camera.getRX()); camera.rotateY((rxAbs >= 90 && rxAbs < 270 ? -1 : 1) * Mouse.getDX() * 0.5F * modifier); } final float wheel = Mouse.getDWheel(); if(wheel != 0) { camera.addZ(wheel * (cameraMod / 5000F)); } } } } private int select(int x, int y) { IntBuffer selBuffer = ByteBuffer.allocateDirect(1024).order(ByteOrder.nativeOrder()).asIntBuffer(); int[] buffer = new int[256]; IntBuffer viewBuffer = ByteBuffer.allocateDirect(64).order(ByteOrder.nativeOrder()).asIntBuffer(); int[] viewport = new int[4]; int hits; GL11.glGetInteger(GL11.GL_VIEWPORT, viewBuffer); viewBuffer.get(viewport); GL11.glSelectBuffer(selBuffer); GL11.glRenderMode(GL11.GL_SELECT); GL11.glInitNames(); GL11.glPushName(0); GL11.glPushMatrix(); { GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glLoadIdentity(); GLU.gluPickMatrix(x, y, 1, 1, IntBuffer.wrap(viewport)); int offset = activeSidebar == null ? 0 : getHeight() < 805 ? SIDEBAR_WIDTH * 2 : SIDEBAR_WIDTH; GLU.gluPerspective(60F, (float) (width - offset) / (float) height, 0.3F, 1000F); canvasRenderer.onRenderPerspective(this, manager, camera); } GL11.glPopMatrix(); hits = GL11.glRenderMode(GL11.GL_RENDER); selBuffer.get(buffer); if(hits > 0) { int choose = buffer[3]; int depth = buffer[1]; for(int i = 1; i < hits; i++) { if((buffer[i * 4 + 1] < depth || choose == 0) && buffer[i * 4 + 3] != 0) { choose = buffer[i * 4 + 3]; depth = buffer[i * 4 + 1]; } } if(choose > 0) { return choose - 1; } } return -1; } private float applyLimit(float value) { if(value > 0.4F) { value = 0.4F; } else if(value < 0.15F) { value = 0.15F; } return value; } private int getCameraState(Camera camera) { int cameraRotY = (int) (camera.getRY() >= 0 ? camera.getRY() : 360 + camera.getRY()); int state = (int) ((cameraRotY * 4.0F / 360.0F) + 0.5D) & 3; if(camera.getRX() > 45) { state += 4; } if(camera.getRX() < -45) { state += 8; } return state; } public void startScreenshot(PendingScreenshot screenshot) { this.screenshot = screenshot; } public void setSidebar(Sidebar s) { activeSidebar = s; if(s == null) { isUVSidebarOpen = false; } } public Sidebar getActiveSidebar() { return activeSidebar; } public ElementManager getElementManager() { return manager; } public void close() { this.closeRequested = true; } private boolean getCloseRequested() { return closeRequested; } private void handleKeyAction(int code, int modifiers, boolean awt, boolean pressed) { if(!this.isActive()) return; keyActions.forEach(keyAction -> { if(awt) { if(keyAction.awtCode == code) { keyAction.handler.process(modifiers, pressed); } } else { if(keyAction.keyboardCode == code) { keyAction.handler.process(modifiers, pressed); } } }); } public static void setCanvasRenderer(CanvasRenderer displayRenderer) { canvasRenderer = displayRenderer; changedCanvas = true; } public static void restoreStandardRenderer() { setCanvasRenderer(standardRenderer); } public void registerKeyAction(KeyAction keyAction) { this.keyActions.add(keyAction); } public static class KeyAction { private final int awtCode; private final int keyboardCode; private final Handler handler; public KeyAction(int awtCode, int keyboardCode, Handler handler) { this.awtCode = awtCode; this.keyboardCode = keyboardCode; this.handler = handler; } public interface Handler { void process(int modifiers, boolean pressed); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Processor.java ================================================ package com.mrcrayfish.modelcreator; /** * Author: MrCrayfish */ public interface Processor { /** * Processes the given argument. * * @param t the object to process * @return if the object was processed successfully */ boolean run(T t); } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/ProjectManager.java ================================================ package com.mrcrayfish.modelcreator; import com.mrcrayfish.modelcreator.component.TextureManager; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.texture.TextureEntry; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Comparator; import java.util.HashSet; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; public class ProjectManager { private static final Pattern TEXTURE_FIX = Pattern.compile("\\d+$"); //Matches numbers at the end of line public static void loadProject(ElementManager manager, String modelFile) { TextureManager.clear(); manager.clearElements(); manager.setParticle(null); File projectFolder = extractFiles(modelFile); if(projectFolder != null) { Project project = new Project(projectFolder); Importer importer = new Importer(manager, project.getModel().getPath()); importer.importFromJSON(); } deleteFolder(projectFolder); } private static void deleteFolder(File file) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { Files.walk(file.toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); } catch(IOException e) { e.printStackTrace(); } })); } private static File extractFiles(String modelFile) { try { Path path = Files.createTempDirectory("ModelCreator"); File folder = path.toFile(); ZipInputStream zis = new ZipInputStream(new FileInputStream(modelFile)); ZipEntry ze; while((ze = zis.getNextEntry()) != null) { String fileName = ze.getName(); /* Fixes old project texture files extracting with numbers on the file name */ Matcher matcher = TEXTURE_FIX.matcher(ze.getName()); if(matcher.find()) { String numbers = matcher.group(0); fileName = fileName.replace(numbers, ""); } File file = new File(folder, fileName); file.getParentFile().mkdirs(); file.createNewFile(); byte[] buffer = new byte[1024]; FileOutputStream fos = new FileOutputStream(file); int len; while((len = zis.read(buffer)) > 0) { fos.write(buffer, 0, len); } fos.flush(); fos.close(); zis.closeEntry(); } zis.close(); return folder; } catch(IOException e) { e.printStackTrace(); } return null; } public static void saveProject(ElementManager manager, String name) { try { FileOutputStream fos = new FileOutputStream(name); ZipOutputStream zos = new ZipOutputStream(fos); File file = getSaveFile(manager); addToZipFile(file, zos, "model.json"); file.delete(); for(TextureEntry entry : getAllTextures(manager)) { File temp = File.createTempFile(entry.getName(), ""); BufferedImage image = entry.getSource(); ImageIO.write(image, "PNG", temp); addToZipFile(temp, zos, "assets/" + entry.getModId() + "/textures/" + entry.getDirectory() + "/", entry.getName() + ".png"); temp.delete(); } //TODO make output animation properties /*for(String metaLocation : getMetaLocations(manager)) { if(metaLocation != null) { File texture = new File(metaLocation); if(texture.exists()) { addToZipFile(texture, zos, "textures/", texture.getName()); } } }*/ zos.close(); fos.close(); } catch(IOException e) { e.printStackTrace(); } } private static Set getAllTextures(ElementManager manager) { Set textureEntries = new HashSet<>(); for(Element element : manager.getAllElements()) { for(Face face : element.getAllFaces()) { if(face.getTexture() != null) { textureEntries.add(face.getTexture()); } } } return textureEntries; } private static File getSaveFile(ElementManager manager) throws IOException { ExporterModel exporter = new ExporterModel(manager); exporter.setOptimize(false); exporter.setIncludeNonTexturedFaces(true); return exporter.writeFile(File.createTempFile("model.json", "")); } private static void addToZipFile(File file, ZipOutputStream zos, String name) throws IOException { addToZipFile(file, zos, "", name); } private static void addToZipFile(File file, ZipOutputStream zos, String folder, String name) throws IOException { FileInputStream fis = new FileInputStream(file); ZipEntry zipEntry = new ZipEntry(folder + name); zos.putNextEntry(zipEntry); byte[] bytes = new byte[1024]; int length; while((length = fis.read(bytes)) >= 0) { zos.write(bytes, 0, length); } zos.closeEntry(); fis.close(); } private static class Project { public File model; public File textures; public Project(File folder) { File[] files = folder.listFiles(); if(files != null) { for(File file : files) { String name = file.getName(); if(file.isFile() && name.equals("model.json")) { this.model = file; } else if(file.isDirectory() && name.equals("textures")) { this.textures = file; } } } } public File getModel() { return model; } public File getTextures() { return textures; } } private static class ProjectTexture { private File texture; private File meta; public ProjectTexture(File texture, File meta) { this.texture = texture; this.meta = meta; } public File getTexture() { return texture; } public File getMeta() { return meta; } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/PropertyIdentifiers.java ================================================ package com.mrcrayfish.modelcreator; /** * Author: MrCrayfish */ public class PropertyIdentifiers { public static final int SIZE_X = 0; public static final int SIZE_Y = 1; public static final int SIZE_Z = 2; public static final int POS_X = 3; public static final int POS_Y = 4; public static final int POS_Z = 5; public static final int ORIGIN_X = 6; public static final int ORIGIN_Y = 7; public static final int ORIGIN_Z = 8; public static final int START_U = 9; public static final int START_V = 10; public static final int END_U = 11; public static final int END_V = 12; } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Settings.java ================================================ package com.mrcrayfish.modelcreator; import java.util.prefs.Preferences; public class Settings { private static final String IMAGE_IMPORT_DIR = "image_import_dir"; private static final String SCREENSHOT_DIR = "screenshot_dir"; private static final String MODEL_DIR = "model_dir"; private static final String JSON_DIR = "json_dir"; private static final String EXPORT_JSON_DIR = "export_json_dir"; private static final String UNDO_LIMIT = "undo_limit"; private static final String RENDER_CARDINAL_POINTS = "cardinal_points"; private static final String ASSESTS_DIR = "assets_dir"; private static final String FACE_COLORS = "face_colors"; private static final String IMAGE_EDITOR = "image_editor"; private static final String IMAGE_EDITOR_ARGS = "image_editor_args"; public static final int[] DEFAULT_FACE_COLORS = {16711680, 65280, 255, 16776960, 16711935, 65535}; public static String getImageImportDir() { Preferences prefs = getPreferences(); return prefs.get(IMAGE_IMPORT_DIR, null); } public static void setImageImportDir(String dir) { Preferences prefs = getPreferences(); prefs.put(IMAGE_IMPORT_DIR, dir); } public static String getScreenshotDir() { Preferences prefs = getPreferences(); return prefs.get(SCREENSHOT_DIR, null); } public static void setScreenshotDir(String dir) { Preferences prefs = getPreferences(); prefs.put(SCREENSHOT_DIR, dir); } public static String getModelDir() { Preferences prefs = getPreferences(); return prefs.get(MODEL_DIR, null); } public static void setModelDir(String dir) { Preferences prefs = getPreferences(); prefs.put(MODEL_DIR, dir); } public static String getJSONDir() { Preferences prefs = getPreferences(); return prefs.get(JSON_DIR, null); } public static void setJSONDir(String dir) { Preferences prefs = getPreferences(); prefs.put(JSON_DIR, dir); } public static String getExportJSONDir() { Preferences prefs = getPreferences(); return prefs.get(EXPORT_JSON_DIR, null); } public static void setExportJSONDir(String dir) { Preferences prefs = getPreferences(); prefs.put(EXPORT_JSON_DIR, dir); } public static String getAssetsDir() { Preferences prefs = getPreferences(); return prefs.get(ASSESTS_DIR, null); } public static void setAssetsDir(String dir) { Preferences prefs = getPreferences(); prefs.put(ASSESTS_DIR, dir); } public static int getUndoLimit() { Preferences prefs = getPreferences(); String s = prefs.get(UNDO_LIMIT, null); try { return Math.max(1, Integer.parseInt(s)); } catch(NumberFormatException e) { return 50; } } public static void setUndoLimit(int limit) { Preferences prefs = getPreferences(); prefs.put(UNDO_LIMIT, Integer.toString(Math.max(1, limit))); } public static boolean getCardinalPoints() { Preferences prefs = getPreferences(); String s = prefs.get(RENDER_CARDINAL_POINTS, "true"); return Boolean.parseBoolean(s); } public static void setCardinalPoints(boolean renderCardinalPoints) { Preferences prefs = getPreferences(); prefs.put(RENDER_CARDINAL_POINTS, Boolean.toString(renderCardinalPoints)); } public static int[] getFaceColors() { Preferences prefs = getPreferences(); String s = prefs.get(FACE_COLORS, ""); String[] values = s.split(","); if(values.length == 6) { int[] colors = new int[6]; for(int i = 0; i < values.length; i++) { int color = Integer.parseInt(values[i]); colors[i] = color; } return colors; } return DEFAULT_FACE_COLORS; } public static void setFaceColors(int[] colors) { StringBuilder builder = new StringBuilder(); for(int value : colors) { builder.append(value); builder.append(","); } builder.setLength(builder.length() - 1); Preferences prefs = getPreferences(); prefs.put(FACE_COLORS, builder.toString()); } public static String getImageEditor() { Preferences prefs = getPreferences(); return prefs.get(IMAGE_EDITOR, null); } public static void setImageEditor(String file) { Preferences prefs = getPreferences(); prefs.put(IMAGE_EDITOR, file); } public static String getImageEditorArgs() { Preferences prefs = getPreferences(); return prefs.get(IMAGE_EDITOR_ARGS, "\"%s\""); } public static void setImageEditorArgs(String args) { Preferences prefs = getPreferences(); prefs.put(IMAGE_EDITOR_ARGS, args); } private static Preferences getPreferences() { return Preferences.userNodeForPackage(Settings.class); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/Start.java ================================================ package com.mrcrayfish.modelcreator; import com.jtattoo.plaf.fast.FastLookAndFeel; import com.mrcrayfish.modelcreator.util.SharedLibraryLoader; import javax.swing.*; import java.util.Properties; public class Start { public static void main(String[] args) { SharedLibraryLoader.load(false); Double version = Double.parseDouble(System.getProperty("java.specification.version")); if(version < 1.8) { JOptionPane.showMessageDialog(null, "You need Java 1.8 or higher to run this program."); return; } System.setProperty("org.lwjgl.util.Debug", "true"); try { Properties props = new Properties(); props.put("logoString", ""); props.put("centerWindowTitle", "on"); props.put("buttonBackgroundColor", "127 132 145"); props.put("buttonForegroundColor", "255 255 255"); props.put("windowTitleBackgroundColor", "97 102 115"); props.put("windowTitleForegroundColor", "255 255 255"); props.put("backgroundColor", "221 221 228"); props.put("menuBackgroundColor", "221 221 228"); props.put("controlForegroundColor", "120 120 120"); props.put("windowBorderColor", "97 102 110"); FastLookAndFeel.setTheme(props); UIManager.setLookAndFeel("com.jtattoo.plaf.fast.FastLookAndFeel"); } catch(Exception e) { e.printStackTrace(); } new ModelCreator(Constants.NAME + " v" + Constants.VERSION); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/StateManager.java ================================================ package com.mrcrayfish.modelcreator; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.ElementManagerState; import javax.swing.*; import java.awt.event.ActionListener; import java.util.Stack; /** * Author: MrCrayfish */ public class StateManager { /* Undo/Redo Stack */ private static Stack states = new Stack<>(); private static int tailIndex = -1; private static int lastId = -1; private static Timer timer; public static void pushState(ElementManager manager) { pushState(manager.createState()); } private static void pushState(ElementManagerState state) { if(timer != null && timer.isRunning()) { for(ActionListener listener : timer.getActionListeners()) { listener.actionPerformed(null); } timer.stop(); timer = null; } pushManagerState(state); } private static void pushManagerState(ElementManagerState state) { while(tailIndex < states.size() - 1) { states.pop(); } if(states.size() >= 50) //Make configurable { while(states.size() > 50) { states.remove(0); } } states.push(state); tailIndex = states.size() - 1; } public static void restorePreviousState(ElementManager manager) { if(canRestorePreviousState()) { ElementManagerState state = states.get(tailIndex - 1); manager.restoreState(state); tailIndex--; } } public static void restoreNextState(ElementManager manager) { if(canRestoreNextState()) { ElementManagerState state = states.get(tailIndex + 1); manager.restoreState(state); tailIndex++; } } public static boolean canRestorePreviousState() { return tailIndex > 0; } public static boolean canRestoreNextState() { return tailIndex < states.size() - 1; } public static void clear() { if(timer != null && timer.isRunning()) { timer.stop(); timer = null; } states.clear(); tailIndex = -1; } public static Stack getStates() { return states; } public static int getTailIndex() { return tailIndex; } public static void pushStateDelayed(ElementManager manager, int id) { if(lastId != id) { if(timer != null && timer.isRunning()) { for(ActionListener listener : timer.getActionListeners()) { listener.actionPerformed(null); } timer.stop(); } } else { if(timer != null && timer.isRunning()) { timer.stop(); } } ElementManagerState state = manager.createState(); ActionListener listener = e -> pushManagerState(state); timer = new Timer(400, listener); timer.setRepeats(false); timer.start(); lastId = id; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/TexturePath.java ================================================ package com.mrcrayfish.modelcreator; import com.mrcrayfish.modelcreator.util.AssetsUtil; import java.io.File; import java.util.regex.Pattern; /** * Author: MrCrayfish */ public class TexturePath { public static final Pattern PATTERN = Pattern.compile("([a-z_0-9]+:)?([a-z_0-9]+/)*[a-z_0-9]+"); private String modId = "minecraft"; private String directory; private String name; public TexturePath(String s) { String[] split = s.split(":"); if(split.length == 2) { this.modId = split[0]; } String assetPath = split[split.length - 1]; this.directory = assetPath.substring(0, Math.max(0, assetPath.lastIndexOf("/"))); this.name = assetPath.replace(this.directory, "").substring(1); } public TexturePath(File file) { this.modId = AssetsUtil.getModId(file); this.directory = AssetsUtil.getTextureDirectory(file); this.name = file.getName().substring(0, file.getName().indexOf(".")); } public String getModId() { return modId; } public String getDirectory() { return directory; } public String getName() { return name; } @Override public String toString() { return modId + ":" + directory + "/" + name; } public String toRelativePath() { return modId + File.separator + "textures" + File.separator + directory + File.separator + name + ".png"; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/component/DisplayPropertiesDialog.java ================================================ package com.mrcrayfish.modelcreator.component; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.display.CanvasRenderer; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.panels.DisplayEntryPanel; import com.mrcrayfish.modelcreator.util.ComponentUtil; import javax.swing.*; import java.awt.*; /** * Author: MrCrayfish */ public class DisplayPropertiesDialog extends JDialog { private ModelCreator creator; private JTabbedPane tabbedPane; public DisplayPropertiesDialog(ModelCreator creator) { super(creator, "Display Properties", Dialog.ModalityType.MODELESS); this.creator = creator; this.init(); this.pack(); this.setResizable(false); } private void init() { SpringLayout layout = new SpringLayout(); JPanel panel = new JPanel(layout); panel.setPreferredSize(new Dimension(400, 490)); this.add(panel); JLabel labelProperties = new JLabel("Presets"); panel.add(labelProperties); JComboBox comboBoxProperties = new JComboBox<>(); comboBoxProperties.addItem(DisplayProperties.MODEL_CREATOR_BLOCK); comboBoxProperties.addItem(DisplayProperties.DEFAULT_BLOCK); comboBoxProperties.addItem(DisplayProperties.DEFAULT_ITEM); comboBoxProperties.setPreferredSize(new Dimension(0, 24)); panel.add(comboBoxProperties); DisplayProperties properties = creator.getElementManager().getDisplayProperties(); tabbedPane = new JTabbedPane(); tabbedPane.addTab("GUI", new DisplayEntryPanel(properties.getEntry("gui"))); tabbedPane.addTab("Ground", new DisplayEntryPanel(properties.getEntry("ground"))); tabbedPane.addTab("Fixed", new DisplayEntryPanel(properties.getEntry("fixed"))); tabbedPane.addTab("Head", new DisplayEntryPanel(properties.getEntry("head"))); tabbedPane.addTab("First Person", new DisplayEntryPanel(properties.getEntry("firstperson_righthand"))); tabbedPane.addTab("Third Person", new DisplayEntryPanel(properties.getEntry("thirdperson_righthand"))); tabbedPane.addTab("First Person (Left)", new DisplayEntryPanel(properties.getEntry("firstperson_lefthand"))); tabbedPane.addTab("Third Person (Left)", new DisplayEntryPanel(properties.getEntry("thirdperson_lefthand"))); tabbedPane.addChangeListener(e -> { Component c = tabbedPane.getComponentAt(tabbedPane.getSelectedIndex()); if(c instanceof DisplayEntryPanel) { DisplayEntryPanel entryPanel = (DisplayEntryPanel) c; CanvasRenderer render = DisplayProperties.RENDER_MAP.get(entryPanel.getEntry().getId()); if(render != null) { ModelCreator.setCanvasRenderer(render); } else { ModelCreator.restoreStandardRenderer(); } } }); panel.add(tabbedPane); JButton btnApplyProperties = new JButton("Apply"); btnApplyProperties.setPreferredSize(new Dimension(80, 24)); btnApplyProperties.addActionListener(e -> { creator.getElementManager().setDisplayProperties((DisplayProperties) comboBoxProperties.getSelectedItem()); this.updateValues(creator.getElementManager().getDisplayProperties()); }); panel.add(btnApplyProperties); JCheckBox checkBoxShowGrid = ComponentUtil.createCheckBox("Show Grid", "Determines whether the grid should render", Menu.shouldRenderGrid); checkBoxShowGrid.addActionListener(e -> Menu.shouldRenderGrid = checkBoxShowGrid.isSelected()); panel.add(checkBoxShowGrid); layout.putConstraint(SpringLayout.WEST, labelProperties, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, labelProperties, 2, SpringLayout.NORTH, comboBoxProperties); layout.putConstraint(SpringLayout.EAST, comboBoxProperties, -10, SpringLayout.WEST, btnApplyProperties); layout.putConstraint(SpringLayout.NORTH, comboBoxProperties, 10, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.WEST, comboBoxProperties, 10, SpringLayout.EAST, labelProperties); layout.putConstraint(SpringLayout.NORTH, btnApplyProperties, 10, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.EAST, btnApplyProperties, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.WEST, checkBoxShowGrid, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, checkBoxShowGrid, 5, SpringLayout.SOUTH, comboBoxProperties); layout.putConstraint(SpringLayout.EAST, tabbedPane, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.NORTH, tabbedPane, 5, SpringLayout.SOUTH, checkBoxShowGrid); layout.putConstraint(SpringLayout.WEST, tabbedPane, 10, SpringLayout.WEST, panel); } public void updateValues(DisplayProperties displayProperties) { Component[] components = tabbedPane.getComponents(); for(Component c : components) { if(c instanceof DisplayEntryPanel) { DisplayEntryPanel entryPanel = (DisplayEntryPanel) c; DisplayProperties.Entry oldEntry = entryPanel.getEntry(); DisplayProperties.Entry newEntry = displayProperties.getEntry(oldEntry.getId()); if(newEntry != null) { entryPanel.updateValues(newEntry); } } } } public static void update(ModelCreator creator) { if(Menu.displayPropertiesDialog != null) { Menu.displayPropertiesDialog.updateValues(creator.getElementManager().getDisplayProperties()); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/component/JElementList.java ================================================ package com.mrcrayfish.modelcreator.component; import com.mrcrayfish.modelcreator.element.ElementCellEntry; import com.mrcrayfish.modelcreator.util.ComponentUtil; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; /** * Author: MrCrayfish */ public class JElementList extends JList { private boolean processInput; @Override protected void processMouseEvent(MouseEvent e) { if(e.getID() == MouseEvent.MOUSE_FIRST) { return; } if(e.getID() == MouseEvent.MOUSE_RELEASED) { processInput = true; return; } if(!processInput) { return; } if(e.getButton() == MouseEvent.BUTTON1) { int index = this.locationToIndex(e.getPoint()); if(index != -1) { Rectangle rectangle = this.getCellBounds(index, index); if(rectangle.contains(e.getPoint())) { Point relativePoint = new Point((int) e.getPoint().getX(), (int) (e.getPoint().getY() - rectangle.getY())); ElementCellEntry entry = this.getModel().getElementAt(index); Rectangle buttonBounds = ComponentUtil.expandRectangle(entry.getVisibility().getBounds(), 4); if(buttonBounds.contains(relativePoint)) { entry.toggleVisibility(); this.repaint(); e.consume(); processInput = false; return; } } } } super.processMouseEvent(e); } @Override protected void processMouseMotionEvent(MouseEvent e) { if(processInput) { super.processMouseMotionEvent(e); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/component/Menu.java ================================================ package com.mrcrayfish.modelcreator.component; import com.mrcrayfish.modelcreator.*; import com.mrcrayfish.modelcreator.display.CanvasRenderer; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.panels.DisplayEntryPanel; import com.mrcrayfish.modelcreator.screenshot.PendingScreenshot; import com.mrcrayfish.modelcreator.screenshot.Screenshot; import com.mrcrayfish.modelcreator.screenshot.Uploader; import com.mrcrayfish.modelcreator.util.ComponentUtil; import com.mrcrayfish.modelcreator.util.KeyboardUtil; import com.mrcrayfish.modelcreator.util.Util; import org.lwjgl.input.Keyboard; import javax.swing.*; import javax.swing.event.MenuEvent; import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.awt.datatransfer.StringSelection; import java.awt.event.*; import java.io.File; import java.io.IOException; import java.util.Set; public class Menu extends JMenuBar { private ModelCreator creator; /* File */ private JMenu menuFile; private JMenuItem itemNew; private JMenuItem itemLoad; private JMenuItem itemSave; private JMenuItem itemImport; private JMenuItem itemExport; private JMenuItem itemSettings; private JMenuItem itemExit; /* Edit */ private JMenu menuEdit; private JMenuItem itemUndo; private JMenuItem itemRedo; /* Model */ private JMenu menuModel; private JMenuItem itemTextureManager; private JMenuItem itemDisplayProps; private JMenuItem itemOptimise; private JMenu menuRotate; private JMenuItem itemRotateClockwise; private JMenuItem itemRotateCounterClockwise; /* Share */ private JMenu menuScreenshot; private JMenuItem itemSaveToDisk; private JMenuItem itemShareFacebook; private JMenuItem itemShareTwitter; private JMenuItem itemShareReddit; private JMenuItem itemImgurLink; /* Extras */ private JMenu menuMore; private JMenuItem itemExtractAssets; private JMenu menuDeveloper; private JMenuItem itemJavaCode; private JMenu menuExamples; private JMenuItem itemModelCauldron; private JMenuItem itemModelChair; private JMenuItem itemDonate; private JMenuItem itemGitHub; public static DisplayPropertiesDialog displayPropertiesDialog = null; public static boolean shouldRenderGrid = false; public Menu(ModelCreator creator) { this.creator = creator; this.initMenu(); } private void initMenu() { menuFile = new JMenu("File"); { itemNew = createMenuItem("New", "New Model", KeyEvent.VK_N, Icons.new_, KeyEvent.VK_N, Keyboard.KEY_N, InputEvent.CTRL_MASK); itemLoad = createMenuItem("Load Project...", "Load Project from File", KeyEvent.VK_S, Icons.load, KeyEvent.VK_O, Keyboard.KEY_O, InputEvent.CTRL_MASK); itemSave = createMenuItem("Save Project...", "Save Project to File", KeyEvent.VK_S, Icons.disk, KeyEvent.VK_S, Keyboard.KEY_S, InputEvent.CTRL_MASK); itemImport = createMenuItem("Import JSON...", "Import Model from JSON", KeyEvent.VK_I, Icons.import_); itemExport = createMenuItem("Export JSON...", "Export Model to JSON", KeyEvent.VK_E, Icons.export); itemSettings = createMenuItem("Settings", "Change the settings of the Model Creator", KeyEvent.VK_S, Icons.settings, KeyEvent.VK_S, Keyboard.KEY_S, InputEvent.CTRL_MASK + InputEvent.ALT_MASK); itemExit = createMenuItem("Exit", "Exit Application", KeyEvent.VK_E, Icons.exit); } menuEdit = new JMenu("Edit"); { itemUndo = createMenuItem("Undo", "Undos the previous action", KeyEvent.VK_U, Icons.undo, KeyEvent.VK_Z, Keyboard.KEY_Z, InputEvent.CTRL_MASK); itemRedo = createMenuItem("Redo", "Redos the previous action", KeyEvent.VK_R, Icons.redo, KeyEvent.VK_Y, Keyboard.KEY_Y, InputEvent.CTRL_MASK); } menuModel = new JMenu("Model"); { itemTextureManager = createMenuItem("Texture Manager", "Manage the textures entries for the model", KeyEvent.VK_T, Icons.texture, KeyEvent.VK_T, Keyboard.KEY_T, InputEvent.CTRL_MASK + InputEvent.SHIFT_MASK); itemDisplayProps = createMenuItem("Display Properties", "Change the display properties of the model", KeyEvent.VK_D, Icons.gallery, KeyEvent.VK_D, Keyboard.KEY_D, InputEvent.CTRL_MASK + InputEvent.ALT_MASK); itemOptimise = createMenuItem("Optimize", "Performs basic optimizion by disabling faces that aren't visible", KeyEvent.VK_O, Icons.optimize, KeyEvent.VK_N, Keyboard.KEY_N, InputEvent.CTRL_MASK + InputEvent.SHIFT_MASK); menuRotate = new JMenu("Rotate"); menuRotate.setMnemonic(KeyEvent.VK_R); menuRotate.setIcon(Icons.rotate); { itemRotateClockwise = createMenuItem("90\u00B0 Clockwise", "Rotates all elements clockwise by 90\u00B0", KeyEvent.VK_C, Icons.rotate_clockwise, KeyEvent.VK_RIGHT, Keyboard.KEY_RIGHT, InputEvent.CTRL_MASK); itemRotateCounterClockwise = createMenuItem("90\u00B0 Counter Clockwise", "Rotates all elements counter clockwise by 90\u00B0", KeyEvent.VK_C, Icons.rotate_counter_clockwise, KeyEvent.VK_LEFT, Keyboard.KEY_LEFT, InputEvent.CTRL_MASK); } } menuScreenshot = new JMenu("Screenshot"); { itemSaveToDisk = createMenuItem("Save to Disk...", "Save screenshot to disk.", KeyEvent.VK_D, Icons.disk); itemShareFacebook = createMenuItem("Share to Facebook", "Share a screenshot of your model Facebook.", KeyEvent.VK_S, Icons.facebook); itemShareTwitter = createMenuItem("Share to Twitter", "Share a screenshot of your model to Twitter.", KeyEvent.VK_S, Icons.twitter); itemShareReddit = createMenuItem("Share to Minecraft Subreddit", "Share a screenshot of your model to Minecraft Reddit.", KeyEvent.VK_S, Icons.reddit); itemImgurLink = createMenuItem("Get Imgur Link", "Get an Imgur link of your screenshot to share.", KeyEvent.VK_I, Icons.imgur); } menuMore = new JMenu("More"); { itemExtractAssets = createMenuItem("Extract Assets...", "Extract Minecraft assets so you can get access to block and item textures", KeyEvent.VK_E, Icons.extract); menuDeveloper = new JMenu("Mod Developer"); menuDeveloper.setMnemonic(KeyEvent.VK_M); menuDeveloper.setIcon(Icons.mojang); { itemJavaCode = createMenuItem("Generate Java Code...", "Generate Java code for selection and collisions boxes", KeyEvent.VK_J, Icons.java); } menuExamples = new JMenu("Examples"); menuExamples.setMnemonic(KeyEvent.VK_E); menuExamples.setIcon(Icons.new_); { itemModelCauldron = createMenuItem("Cauldron", "Model by MrCrayfish
Private use only", KeyEvent.VK_C, Icons.model_cauldron); itemModelChair = createMenuItem("Chair", "Model by MrCrayfish
Private use only", KeyEvent.VK_C, Icons.model_chair); } itemDonate = createMenuItem("Donate (Patreon)", "Pledge to MrCrayfish", KeyEvent.VK_D, Icons.patreon); itemGitHub = createMenuItem("Source Code", "View Source Code", KeyEvent.VK_S, Icons.github); } this.initActions(); /* Menu File */ menuFile.add(itemNew); menuFile.addSeparator(); menuFile.add(itemLoad); menuFile.add(itemSave); menuFile.addSeparator(); menuFile.add(itemImport); menuFile.add(itemExport); menuFile.addSeparator(); menuFile.add(itemSettings); menuFile.addSeparator(); menuFile.add(itemExit); this.add(menuFile); /* Menu Edit */ menuEdit.add(itemUndo); menuEdit.add(itemRedo); menuEdit.addMenuListener(new MenuAdapter() { @Override public void menuSelected(MenuEvent e) { itemRedo.setEnabled(StateManager.canRestoreNextState()); itemUndo.setEnabled(StateManager.canRestorePreviousState()); } }); this.add(menuEdit); /* Menu Model Sub Menus */ menuRotate.add(itemRotateClockwise); menuRotate.add(itemRotateCounterClockwise); /* Menu Model */ menuModel.add(itemTextureManager); menuModel.add(itemDisplayProps); menuModel.add(itemOptimise); menuModel.addSeparator(); menuModel.add(menuRotate); this.add(menuModel); /* Menu Screenshots */ menuScreenshot.add(itemSaveToDisk); menuScreenshot.add(itemShareFacebook); menuScreenshot.add(itemShareTwitter); menuScreenshot.add(itemShareReddit); menuScreenshot.add(itemImgurLink); this.add(menuScreenshot); /* Menu More Sub Menus */ menuDeveloper.add(itemJavaCode); menuExamples.add(itemModelCauldron); menuExamples.add(itemModelChair); /* Menu More */ menuMore.add(itemExtractAssets); menuMore.add(menuDeveloper); menuMore.addSeparator(); menuMore.add(menuExamples); menuMore.addSeparator(); menuMore.add(itemGitHub); menuMore.add(itemDonate); this.add(menuMore); } private void initActions() { itemNew.addActionListener(a -> newProject(creator)); itemLoad.addActionListener(a -> loadProject(creator)); itemSave.addActionListener(a -> saveProject(creator)); itemImport.addActionListener(a -> showImportJson(creator)); itemExport.addActionListener(a -> showExportJson(creator)); itemJavaCode.addActionListener(a -> showExportJavaCode(creator, a)); itemSettings.addActionListener(a -> showSettings(creator)); itemExit.addActionListener(a -> creator.close()); itemTextureManager.addActionListener(a -> { TextureManager manager = new TextureManager(creator, creator.getElementManager(), Dialog.ModalityType.APPLICATION_MODAL, false); manager.setLocationRelativeTo(null); manager.setVisible(true); }); itemDisplayProps.addActionListener(a -> showDisplayProperties(creator)); itemOptimise.addActionListener(a -> optimizeModel(creator)); itemRotateClockwise.addActionListener(a -> Actions.rotateModel(creator.getElementManager(), true)); itemRotateCounterClockwise.addActionListener(a -> Actions.rotateModel(creator.getElementManager(), false)); itemSaveToDisk.addActionListener(a -> { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Output Directory"); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setApproveButtonText("Save"); FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG (.png)", "png"); chooser.setFileFilter(filter); String dir = Settings.getScreenshotDir(); if(dir != null) { chooser.setCurrentDirectory(new File(dir)); } int returnVal = chooser.showSaveDialog(null); if(returnVal == JFileChooser.APPROVE_OPTION) { if(chooser.getSelectedFile().exists()) { returnVal = JOptionPane.showConfirmDialog(null, "A file already exists with that name, are you sure you want to override?", "Warning", JOptionPane.YES_NO_OPTION); } if(returnVal != JOptionPane.NO_OPTION && returnVal != JOptionPane.CLOSED_OPTION) { File location = chooser.getSelectedFile().getParentFile(); Settings.setScreenshotDir(location.toString()); String filePath = chooser.getSelectedFile().getAbsolutePath(); if(!filePath.endsWith(".png")) { chooser.setSelectedFile(new File(filePath + ".png")); } creator.setSidebar(null); creator.startScreenshot(new PendingScreenshot(chooser.getSelectedFile(), null)); } } }); itemShareFacebook.addActionListener(a -> { creator.setSidebar(null); creator.startScreenshot(new PendingScreenshot(null, file -> { try { String url = Uploader.upload(file); Screenshot.shareToFacebook(url); } catch(Exception e) { e.printStackTrace(); } })); }); itemShareTwitter.addActionListener(a -> { creator.setSidebar(null); creator.startScreenshot(new PendingScreenshot(null, file -> { try { String url = Uploader.upload(file); Screenshot.shareToTwitter(url); } catch(Exception e) { e.printStackTrace(); } })); }); itemShareReddit.addActionListener(a -> { creator.setSidebar(null); creator.startScreenshot(new PendingScreenshot(null, file -> { try { String url = Uploader.upload(file); Screenshot.shareToReddit(url); } catch(Exception e) { e.printStackTrace(); } })); }); itemImgurLink.addActionListener(a -> { creator.setSidebar(null); creator.startScreenshot(new PendingScreenshot(null, file -> SwingUtilities.invokeLater(() -> { try { String url = Uploader.upload(file); JOptionPane message = new JOptionPane(); String title; if(url != null && !url.equals("null")) { StringSelection text = new StringSelection(url); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(text, null); title = "Success"; message.setMessage("" + url + " has been copied to your clipboard."); } else { title = "Error"; message.setMessage("Failed to upload screenshot. Check your internet connection then try again."); } JDialog dialog = message.createDialog(this, title); dialog.setLocationRelativeTo(null); dialog.setModal(false); dialog.setVisible(true); } catch(Exception e) { e.printStackTrace(); } }))); }); itemGitHub.addActionListener(a -> Util.openUrl(Constants.URL_GITHUB)); itemDonate.addActionListener(a -> Util.openUrl(Constants.URL_DONATE)); itemExtractAssets.addActionListener(a -> showExtractAssets(creator)); itemModelCauldron.addActionListener(a -> { StateManager.clear(); Util.loadModelFromJar(creator.getElementManager(), getClass(), "models/cauldron"); StateManager.pushState(creator.getElementManager()); }); itemModelChair.addActionListener(a -> { StateManager.clear(); Util.loadModelFromJar(creator.getElementManager(), getClass(), "models/modern_chair"); StateManager.pushState(creator.getElementManager()); }); itemUndo.addActionListener(a -> StateManager.restorePreviousState(creator.getElementManager())); itemRedo.addActionListener(a -> StateManager.restoreNextState(creator.getElementManager())); } private JMenuItem createMenuItem(String name, String tooltip, int mnemonic, Icon icon) { return createMenuItem(name, tooltip, mnemonic, icon, -1, -1, -1); } private JMenuItem createMenuItem(String name, String tooltip, int mnemonic, Icon icon, int awtCode, int keyCode, int modifiers) { JMenuItem item = new JMenuItem(name); item.setToolTipText(tooltip); item.setMnemonic(mnemonic); item.setIcon(icon); if(awtCode != -1 && keyCode != -1 && modifiers != -1) { KeyStroke shortcut = KeyStroke.getKeyStroke(awtCode, modifiers); if(shortcut != null) { String shortcutText = KeyboardUtil.convertKeyStokeToString(shortcut); item.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0)); JLabel label = new JLabel("

" + shortcutText + "

"); item.add(label); Dimension size = new Dimension((int) Math.ceil(item.getPreferredSize().getWidth() + label.getPreferredSize().getWidth()) + 10, 20); item.setPreferredSize(size); } if(shortcut != null) { creator.registerKeyAction(new ModelCreator.KeyAction(awtCode, keyCode, (modifier, pressed) -> { if(pressed && modifier == modifiers) { for(ActionListener listener : item.getActionListeners()) { listener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, item.getActionCommand(), modifier)); } } })); } } return item; } public static void newProject(ModelCreator creator) { int returnVal = JOptionPane.showConfirmDialog(creator, "You current work will be cleared, are you sure?", "Note", JOptionPane.YES_NO_OPTION); if(returnVal == JOptionPane.YES_OPTION) { TextureManager.clear(); StateManager.clear(); creator.getElementManager().reset(); creator.getElementManager().updateValues(); DisplayPropertiesDialog.update(creator); StateManager.pushState(creator.getElementManager()); } } public static void loadProject(ModelCreator creator) { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Load Project"); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setApproveButtonText("Load"); FileNameExtensionFilter filter = new FileNameExtensionFilter("Model (.model)", "model"); chooser.setFileFilter(filter); String dir = Settings.getModelDir(); if(dir != null) { chooser.setCurrentDirectory(new File(dir)); } int returnVal = chooser.showOpenDialog(null); if(returnVal == JFileChooser.APPROVE_OPTION) { if(creator.getElementManager().getElementCount() > 0) { returnVal = JOptionPane.showConfirmDialog(null, "Your current project will be cleared, are you sure you want to continue?", "Warning", JOptionPane.YES_NO_OPTION); } if(returnVal != JOptionPane.NO_OPTION && returnVal != JOptionPane.CLOSED_OPTION) { File location = chooser.getSelectedFile().getParentFile(); Settings.setModelDir(location.toString()); TextureManager.clear(); StateManager.clear(); ProjectManager.loadProject(creator.getElementManager(), chooser.getSelectedFile().getAbsolutePath()); DisplayPropertiesDialog.update(creator); StateManager.pushState(creator.getElementManager()); } } } public static void saveProject(ModelCreator creator) { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Save Project"); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setApproveButtonText("Save"); FileNameExtensionFilter filter = new FileNameExtensionFilter("Model (.model)", "model"); chooser.setFileFilter(filter); String dir = Settings.getModelDir(); if(dir != null) { chooser.setCurrentDirectory(new File(dir)); } int returnVal = chooser.showSaveDialog(null); if(returnVal == JFileChooser.APPROVE_OPTION) { if(chooser.getSelectedFile().exists()) { returnVal = JOptionPane.showConfirmDialog(null, "A file already exists with that name, are you sure you want to override?", "Warning", JOptionPane.YES_NO_OPTION); } if(returnVal != JOptionPane.NO_OPTION && returnVal != JOptionPane.CLOSED_OPTION) { File location = chooser.getSelectedFile().getParentFile(); Settings.setModelDir(location.toString()); String filePath = chooser.getSelectedFile().getAbsolutePath(); if(!filePath.endsWith(".model")) { filePath += ".model"; } ProjectManager.saveProject(creator.getElementManager(), filePath); } } } public static void optimizeModel(ModelCreator creator) { int result = JOptionPane.showConfirmDialog(null, "Are you sure you want to optimize the model?
It is recommended you save the project before running this
action, otherwise you will have to re-enable the disabled faces.", "Optimize Confirmation", JOptionPane.YES_NO_OPTION); if(result == JOptionPane.YES_OPTION) { int count = Actions.optimiseModel(creator.getElementManager()); JOptionPane.showMessageDialog(null, "Optimizing the model disabled " + count + " faces", "Optimization Success", JOptionPane.INFORMATION_MESSAGE); } } public static void showImportJson(ModelCreator creator) { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Import JSON Model"); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setApproveButtonText("Import"); FileNameExtensionFilter filter = new FileNameExtensionFilter("JSON (.json)", "json"); chooser.setFileFilter(filter); String dir = Settings.getJSONDir(); if(dir != null) { chooser.setCurrentDirectory(new File(dir)); } int returnVal = chooser.showOpenDialog(null); if(returnVal == JFileChooser.APPROVE_OPTION) { if(creator.getElementManager().getElementCount() > 0) { returnVal = JOptionPane.showConfirmDialog(null, "Your current project will be cleared, are you sure you want to continue?", "Warning", JOptionPane.YES_NO_OPTION); } if(returnVal != JOptionPane.NO_OPTION && returnVal != JOptionPane.CLOSED_OPTION) { File location = chooser.getSelectedFile().getParentFile(); Settings.setJSONDir(location.toString()); TextureManager.clear(); StateManager.clear(); Importer importer = new Importer(creator.getElementManager(), chooser.getSelectedFile().getAbsolutePath()); importer.importFromJSON(); StateManager.pushState(creator.getElementManager()); } creator.getElementManager().updateValues(); } } public static void showExportJson(ModelCreator creator) { JDialog dialog = new JDialog(creator, "Export JSON Model", Dialog.ModalityType.APPLICATION_MODAL); JPanel panel = new JPanel(new BorderLayout()); panel.setPreferredSize(new Dimension(500, 225)); SpringLayout springLayout = new SpringLayout(); JPanel exportDir = new JPanel(springLayout); JLabel labelName = new JLabel("Name"); labelName.setHorizontalAlignment(SwingConstants.RIGHT); exportDir.add(labelName); JTextField textFieldName = new JTextField(); textFieldName.setPreferredSize(new Dimension(100, 24)); textFieldName.setCaretPosition(0); exportDir.add(textFieldName); JTextField textFieldDestination = new JTextField(); textFieldDestination.setPreferredSize(new Dimension(100, 24)); String exportJsonDir = Settings.getExportJSONDir(); if(exportJsonDir != null) { textFieldDestination.setText(exportJsonDir); } else { String userHome = System.getProperty("user.home", "."); textFieldDestination.setText(userHome); } textFieldDestination.setEditable(false); textFieldDestination.setFocusable(false); textFieldDestination.setCaretPosition(0); exportDir.add(textFieldDestination); JButton btnBrowserDir = new JButton("Browse"); btnBrowserDir.setPreferredSize(new Dimension(80, 24)); btnBrowserDir.setIcon(Icons.load); btnBrowserDir.addActionListener(e -> { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Export Destination"); chooser.setCurrentDirectory(new File(textFieldDestination.getText())); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setApproveButtonText("Select"); int returnVal = chooser.showOpenDialog(dialog); if(returnVal == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); if(file != null) { textFieldDestination.setText(file.getAbsolutePath()); } } }); exportDir.add(btnBrowserDir); JLabel labelExportDir = new JLabel("Destination"); exportDir.add(labelExportDir); //JComponent optionSeparator = DefaultComponentFactory.getInstance().createSeparator("Export Options"); JComponent optionSeparator = new JSeparator(); exportDir.add(optionSeparator); JCheckBox checkBoxOptimize = ComponentUtil.createCheckBox("Optimize Model", "Removes unnecessary faces that can't been seen in the model", true); exportDir.add(checkBoxOptimize); JCheckBox checkBoxDisplayProps = ComponentUtil.createCheckBox("Include Display Properties", "Adds the display definitions (first-person, third-person, etc) to the model file", true); exportDir.add(checkBoxDisplayProps); JCheckBox checkBoxElementNames = ComponentUtil.createCheckBox("Include Element Names", "The name of each element will be added to it's entry in the json model elements array. Useful for identifying elements, and when importing back into Model Creator, it will use those names", true); exportDir.add(checkBoxElementNames); JSeparator separator = new JSeparator(); exportDir.add(separator); /* Constraints */ springLayout.putConstraint(SpringLayout.NORTH, labelName, 3, SpringLayout.NORTH, textFieldName); springLayout.putConstraint(SpringLayout.WEST, labelName, 10, SpringLayout.WEST, exportDir); springLayout.putConstraint(SpringLayout.EAST, labelName, -5, SpringLayout.WEST, textFieldDestination); springLayout.putConstraint(SpringLayout.NORTH, textFieldName, 10, SpringLayout.NORTH, exportDir); springLayout.putConstraint(SpringLayout.WEST, textFieldName, 0, SpringLayout.WEST, textFieldDestination); springLayout.putConstraint(SpringLayout.EAST, textFieldName, 0, SpringLayout.EAST, textFieldDestination); springLayout.putConstraint(SpringLayout.WEST, optionSeparator, 10, SpringLayout.WEST, exportDir); springLayout.putConstraint(SpringLayout.EAST, optionSeparator, -10, SpringLayout.EAST, exportDir); springLayout.putConstraint(SpringLayout.NORTH, optionSeparator, 10, SpringLayout.SOUTH, textFieldDestination); springLayout.putConstraint(SpringLayout.NORTH, btnBrowserDir, 0, SpringLayout.NORTH, textFieldDestination); springLayout.putConstraint(SpringLayout.EAST, btnBrowserDir, -10, SpringLayout.EAST, exportDir); springLayout.putConstraint(SpringLayout.NORTH, textFieldDestination, 10, SpringLayout.SOUTH, textFieldName); springLayout.putConstraint(SpringLayout.WEST, textFieldDestination, 5, SpringLayout.EAST, labelExportDir); springLayout.putConstraint(SpringLayout.EAST, textFieldDestination, -10, SpringLayout.WEST, btnBrowserDir); springLayout.putConstraint(SpringLayout.NORTH, labelExportDir, 3, SpringLayout.NORTH, textFieldDestination); springLayout.putConstraint(SpringLayout.WEST, labelExportDir, 10, SpringLayout.WEST, exportDir); springLayout.putConstraint(SpringLayout.NORTH, checkBoxOptimize, 5, SpringLayout.SOUTH, optionSeparator); springLayout.putConstraint(SpringLayout.WEST, checkBoxOptimize, 10, SpringLayout.WEST, exportDir); springLayout.putConstraint(SpringLayout.NORTH, checkBoxDisplayProps, 0, SpringLayout.SOUTH, checkBoxOptimize); springLayout.putConstraint(SpringLayout.WEST, checkBoxDisplayProps, 10, SpringLayout.WEST, exportDir); springLayout.putConstraint(SpringLayout.NORTH, checkBoxElementNames, 0, SpringLayout.SOUTH, checkBoxDisplayProps); springLayout.putConstraint(SpringLayout.WEST, checkBoxElementNames, 10, SpringLayout.WEST, exportDir); springLayout.putConstraint(SpringLayout.WEST, separator, 10, SpringLayout.WEST, exportDir); springLayout.putConstraint(SpringLayout.EAST, separator, -10, SpringLayout.EAST, exportDir); springLayout.putConstraint(SpringLayout.NORTH, separator, 5, SpringLayout.SOUTH, checkBoxElementNames); springLayout.putConstraint(SpringLayout.SOUTH, separator, 5, SpringLayout.SOUTH, exportDir); panel.setPreferredSize(panel.getPreferredSize()); panel.add(exportDir, BorderLayout.CENTER); JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 10)); JButton btnCancel = new JButton("Cancel"); btnCancel.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { dialog.dispose(); } }); buttons.add(btnCancel); JButton btnExport = new JButton("Export"); btnExport.addActionListener(e -> { String name = textFieldName.getText().trim(); if(!textFieldDestination.getText().isEmpty() && !name.isEmpty()) { File destination = new File(textFieldDestination.getText()); destination.mkdirs(); File modelFile = new File(destination, textFieldName.getText() + ".json"); if(modelFile.exists()) { int returnVal = JOptionPane.showConfirmDialog(dialog, "A file for that name already exists in the directory. Are you sure you want to override it?", "Warning", JOptionPane.YES_NO_OPTION); if(returnVal != JOptionPane.YES_OPTION) { return; } } try { modelFile.createNewFile(); } catch(IOException e1) { JOptionPane.showMessageDialog(dialog, "Unable to create the file. Check that your destination folder is writable", "Error", JOptionPane.ERROR_MESSAGE); } dialog.dispose(); ExporterModel exporter = new ExporterModel(creator.getElementManager()); exporter.setOptimize(checkBoxOptimize.isSelected()); exporter.setDisplayProps(checkBoxDisplayProps.isSelected()); exporter.setIncludeNames(checkBoxElementNames.isSelected()); if(exporter.writeFile(modelFile) == null) { modelFile.delete(); JOptionPane.showMessageDialog(dialog, "An error occured while exporting the model. Please try again", "Error", JOptionPane.ERROR_MESSAGE); } else { Settings.setExportJSONDir(textFieldDestination.getText()); int returnVal = JOptionPane.showOptionDialog(dialog, "Model exported successfully!", "Success", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, null, new Object[]{"Open Folder", "Close"}, "Close"); if(returnVal == 0) { Desktop desktop = Desktop.getDesktop(); try { desktop.open(destination); } catch(IOException e1) { e1.printStackTrace(); } } } } }); buttons.add(btnExport); panel.add(buttons, BorderLayout.SOUTH); dialog.add(panel); dialog.pack(); dialog.setResizable(false); dialog.setLocationRelativeTo(null); dialog.setVisible(true); } private static void showExportJavaCode(ModelCreator creator, ActionEvent actionEvent) { JCheckBox includeFields = ComponentUtil.createCheckBox("Generate Fields", "Include decelerations of the AABBs fields that represent the model's elements", true); JCheckBox includeMethods = ComponentUtil.createCheckBox("Generate Methods", "Include bounds, raytracing, & collision methods", true); JCheckBox useBoundsHelper = ComponentUtil.createCheckBox("Use Bounds Helper", "Fields and methods use MrCrayfish's Bounds helper class, and target his code-base", false); JCheckBox generateRotatedBounds = ComponentUtil.createCheckBox("Make Rotatable", "Use Bounds helper class to create AABB rotation arrays for each element", false); useBoundsHelper.addActionListener(e -> generateRotatedBounds.setEnabled(useBoundsHelper.isSelected())); String mcTooltip = "Select Minecraft version"; JPanel panelMC = new JPanel(new FlowLayout(FlowLayout.LEFT)); JLabel mcLabel = new JLabel("MC Version"); mcLabel.setToolTipText(mcTooltip); panelMC.add(mcLabel); JComboBox mcVersion = new JComboBox<>(ExporterJavaCode.Version.values()); mcVersion.setToolTipText(mcTooltip); mcVersion.setPreferredSize(new Dimension(60, 24)); mcVersion.addActionListener(e -> { ExporterJavaCode.Version version = (ExporterJavaCode.Version) mcVersion.getSelectedItem(); switch(version) { case V_1_12: useBoundsHelper.setText("Use Bounds Helper"); break; default: useBoundsHelper.setText("Use VoxelShapeHelper"); break; } }); panelMC.add(mcVersion); JPanel panelMain = new JPanel(); panelMain.setLayout(new GridLayout(1, 2)); panelMain.add(includeFields); panelMain.add(includeMethods); JPanel parent = new JPanel(); parent.setLayout(new BoxLayout(parent, BoxLayout.Y_AXIS)); parent.add(panelMC); JPanel controls = new JPanel(new GridLayout(1, 1)); controls.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "Options")); controls.add(panelMain); parent.add(controls); if((actionEvent.getModifiers() & ActionEvent.SHIFT_MASK) > 0 && (actionEvent.getModifiers() & ActionEvent.CTRL_MASK) > 0) { includeMethods.setToolTipText(includeMethods.getToolTipText().replace(", raytracing", "")); useBoundsHelper.setForeground(Color.BLACK); useBoundsHelper.setSelected(true); generateRotatedBounds.setSelected(true); JPanel panelCray = new JPanel(); panelCray.setLayout(new GridLayout(1, 2)); panelCray.add(useBoundsHelper); panelCray.add(generateRotatedBounds); controls.setLayout(new GridLayout(2, 1)); controls.add(panelCray); } JLabel infoLabel = new JLabel("

" + "Use this tool to generate Java code for selection and collision boxes. " + "This includes AxisAlignedBB fields and the required methods for the " + "Block class to apply them. It should be noted that elements in the model " + "that have been rotated will be ignored when generating." + "

"); JLabel questionLabel = new JLabel("

" + "Would you like the code to be copied to your clipboard or saved to a text file?" + "

"); int returnValDestination = JOptionPane.showOptionDialog(creator, new Object[] {infoLabel, Box.createHorizontalStrut(20), Box.createHorizontalStrut(20), new JSeparator(), parent, new JSeparator(), Box.createHorizontalStrut(20), Box.createHorizontalStrut(20), questionLabel}, "Generate Java Code", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, null, new String[] {"Clipboard", "Text File"}, "Clipboard"); if (!includeFields.isSelected() && !includeMethods.isSelected()) { JOptionPane.showMessageDialog(creator, "Either AxisAlignedBBs or methods must be selected.", "None Selected", JOptionPane.INFORMATION_MESSAGE); return; } ExporterJavaCode exporter = new ExporterJavaCode(creator, includeFields.isSelected(), includeMethods.isSelected(), useBoundsHelper.isSelected(), generateRotatedBounds.isSelected()); exporter.setVersion((ExporterJavaCode.Version) mcVersion.getSelectedItem()); if (returnValDestination == JOptionPane.CLOSED_OPTION) return; if (returnValDestination == JOptionPane.OK_OPTION) { try { exporter.writeCodeToClipboard(); } catch (Exception exception) { JOptionPane.showMessageDialog(creator, "An error occured while copying code to your clipboard.", "Error", JOptionPane.ERROR_MESSAGE); } return; } JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Output Directory"); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setApproveButtonText("Export"); FileNameExtensionFilter filter = new FileNameExtensionFilter("TXT (.txt)", "txt"); chooser.setFileFilter(filter); String dir = Settings.getJSONDir(); if (dir != null) { chooser.setCurrentDirectory(new File(dir)); } int returnVal = chooser.showSaveDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { if (chooser.getSelectedFile().exists()) { returnVal = JOptionPane.showConfirmDialog(null, "A file already exists with that name, are you sure you want to override?", "Warning", JOptionPane.YES_NO_OPTION); } if (returnVal != JOptionPane.NO_OPTION && returnVal != JOptionPane.CLOSED_OPTION) { File location = chooser.getSelectedFile().getParentFile(); Settings.setJSONDir(location.toString()); String filePath = chooser.getSelectedFile().getAbsolutePath(); if (!filePath.endsWith(".txt")) chooser.setSelectedFile(new File(filePath + ".txt")); exporter.export(chooser.getSelectedFile()); } } } public static void showSettings(ModelCreator creator) { JDialog dialog = new JDialog(creator, "Settings", Dialog.ModalityType.APPLICATION_MODAL); JPanel panel = new JPanel(new BorderLayout()); panel.setPreferredSize(new Dimension(500, 300)); dialog.add(panel); JTabbedPane tabbedPane = new JTabbedPane(); panel.add(tabbedPane, BorderLayout.CENTER); SpringLayout generalSpringLayout = new SpringLayout(); JPanel generalPanel = new JPanel(generalSpringLayout); tabbedPane.addTab("General", generalPanel); JPanel optionsPanel = new JPanel(new GridLayout(1, 2)); generalPanel.add(optionsPanel); JPanel undoPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); optionsPanel.add(undoPanel); JLabel labelUndoLimit = new JLabel("Undo / Redo Limit"); undoPanel.add(labelUndoLimit); final Boolean[] changed = {false}; SpinnerNumberModel undoSpinnerNumberModel = new SpinnerNumberModel(); undoSpinnerNumberModel.setMinimum(1); JSpinner undoLimitSpinner = new JSpinner(undoSpinnerNumberModel); undoLimitSpinner.setPreferredSize(new Dimension(40, 24)); undoLimitSpinner.setValue(Settings.getUndoLimit()); undoLimitSpinner.addChangeListener(e -> { if(!changed[0]) { JOptionPane.showMessageDialog(dialog, "Increasing the undo/redo limit will increase the amount of memory the program use. Change this setting with caution.", "Warning", JOptionPane.WARNING_MESSAGE); changed[0] = true; } }); undoPanel.add(undoLimitSpinner); JCheckBox checkBoxCardinalPoints = ComponentUtil.createCheckBox("Show Cardinal Points", "", Settings.getCardinalPoints()); optionsPanel.add(checkBoxCardinalPoints); JSeparator separator = new JSeparator(); generalPanel.add(separator); String assetsPath = Settings.getAssetsDir() != null ? Settings.getAssetsDir() : ""; JPanel texturePathPanel = createDirectorySelector("Assets Path", dialog, assetsPath); generalPanel.add(texturePathPanel); JSeparator separator2 = new JSeparator(); generalPanel.add(separator2); String imageEditorPath = Settings.getImageEditor() != null ? Settings.getImageEditor() : ""; JPanel imageEditorPanel = ComponentUtil.createFileSelector("Image Editor", dialog, imageEditorPath, null, null); generalPanel.add(imageEditorPanel); JLabel labelArguments = new JLabel("Arguments"); generalPanel.add(labelArguments); String imageEditorArgs = Settings.getImageEditorArgs() != null ? Settings.getImageEditorArgs() : "\"%s\""; JTextField textFieldArguments = new JTextField(imageEditorArgs); textFieldArguments.setPreferredSize(new Dimension(0, 24)); generalPanel.add(textFieldArguments); generalSpringLayout.putConstraint(SpringLayout.WEST, optionsPanel, 5, SpringLayout.WEST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.NORTH, optionsPanel, 5, SpringLayout.NORTH, generalPanel); generalSpringLayout.putConstraint(SpringLayout.EAST, optionsPanel, 5, SpringLayout.EAST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.WEST, separator, 0, SpringLayout.WEST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.EAST, separator, 0, SpringLayout.EAST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.NORTH, separator, 5, SpringLayout.SOUTH, optionsPanel); generalSpringLayout.putConstraint(SpringLayout.EAST, texturePathPanel, -10, SpringLayout.EAST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.WEST, texturePathPanel, 10, SpringLayout.WEST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.NORTH, texturePathPanel, 10, SpringLayout.SOUTH, separator); generalSpringLayout.putConstraint(SpringLayout.EAST, separator2, 0, SpringLayout.EAST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.WEST, separator2, 0, SpringLayout.WEST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.NORTH, separator2, 10, SpringLayout.SOUTH, texturePathPanel); generalSpringLayout.putConstraint(SpringLayout.EAST, imageEditorPanel, -10, SpringLayout.EAST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.WEST, imageEditorPanel, 10, SpringLayout.WEST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.NORTH, imageEditorPanel, 10, SpringLayout.SOUTH, separator2); generalSpringLayout.putConstraint(SpringLayout.WEST, labelArguments, 10, SpringLayout.WEST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.NORTH, labelArguments, 2, SpringLayout.NORTH, textFieldArguments); generalSpringLayout.putConstraint(SpringLayout.EAST, textFieldArguments, -10, SpringLayout.EAST, generalPanel); generalSpringLayout.putConstraint(SpringLayout.WEST, textFieldArguments, 20, SpringLayout.EAST, labelArguments); generalSpringLayout.putConstraint(SpringLayout.NORTH, textFieldArguments, 10, SpringLayout.SOUTH, imageEditorPanel); JPanel colorGrid = new JPanel(); colorGrid.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); JScrollPane colorScrollPane = new JScrollPane(colorGrid); tabbedPane.addTab("Appearance", colorScrollPane); colorGrid.add(createColorSelector(dialog, "North Face", Face.getFaceColour(Face.NORTH), createFaceColorProcessor(Face.NORTH))); colorGrid.add(createColorSelector(dialog, "East Face", Face.getFaceColour(Face.EAST), createFaceColorProcessor(Face.EAST))); colorGrid.add(createColorSelector(dialog, "South Face", Face.getFaceColour(Face.SOUTH), createFaceColorProcessor(Face.SOUTH))); colorGrid.add(createColorSelector(dialog, "West Face", Face.getFaceColour(Face.WEST), createFaceColorProcessor(Face.WEST))); colorGrid.add(createColorSelector(dialog, "Up Face", Face.getFaceColour(Face.UP), createFaceColorProcessor(Face.UP))); colorGrid.add(createColorSelector(dialog, "Down Face", Face.getFaceColour(Face.DOWN), createFaceColorProcessor(Face.DOWN))); JButton btnReset = new JButton("Reset Colors"); btnReset.addActionListener(a -> { Face.setFaceColors(Settings.DEFAULT_FACE_COLORS); dialog.dispose(); JOptionPane.showMessageDialog(creator, "Colors reset"); }); colorGrid.add(btnReset); colorGrid.setLayout(new GridLayout(colorGrid.getComponentCount(), 1, 20, 10)); dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { Settings.setAssetsDir(getDirectoryFromSelector(texturePathPanel)); Settings.setUndoLimit((int) undoLimitSpinner.getValue()); Settings.setFaceColors(Face.getFaceColors()); Settings.setImageEditor(getDirectoryFromSelector(imageEditorPanel)); Settings.setImageEditorArgs(textFieldArguments.getText()); Settings.setCardinalPoints(checkBoxCardinalPoints.isSelected()); } }); dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); dialog.requestFocus(); dialog.pack(); dialog.setResizable(false); dialog.setLocationRelativeTo(null); dialog.setVisible(true); } private static JPanel createDirectorySelector(String label, Component parent, String defaultDir) { SpringLayout layout = new SpringLayout(); JPanel panel = new JPanel(layout); panel.setPreferredSize(new Dimension(100, 24)); JTextField textFieldDestination = new JTextField(); textFieldDestination.setPreferredSize(new Dimension(100, 24)); textFieldDestination.setText(defaultDir); textFieldDestination.setEditable(false); textFieldDestination.setFocusable(false); textFieldDestination.setCaretPosition(0); panel.add(textFieldDestination); JButton btnBrowserDir = new JButton("Browse"); btnBrowserDir.setPreferredSize(new Dimension(80, 24)); btnBrowserDir.setIcon(Icons.load); btnBrowserDir.addActionListener(e -> { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Select a Folder"); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setApproveButtonText("Select"); chooser.setCurrentDirectory(new File(defaultDir)); int returnVal = chooser.showOpenDialog(parent); if(returnVal == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); if(file != null) { textFieldDestination.setText(file.getAbsolutePath()); } } }); panel.add(btnBrowserDir); JLabel labelExportDir = new JLabel(label); panel.add(labelExportDir); layout.putConstraint(SpringLayout.NORTH, textFieldDestination, 0, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.WEST, textFieldDestination, 10, SpringLayout.EAST, labelExportDir); layout.putConstraint(SpringLayout.EAST, textFieldDestination, -10, SpringLayout.WEST, btnBrowserDir); layout.putConstraint(SpringLayout.NORTH, labelExportDir, 3, SpringLayout.NORTH, textFieldDestination); layout.putConstraint(SpringLayout.WEST, labelExportDir, 0, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, btnBrowserDir, 0, SpringLayout.NORTH, textFieldDestination); layout.putConstraint(SpringLayout.EAST, btnBrowserDir, 0, SpringLayout.EAST, panel); return panel; } public static String getDirectoryFromSelector(JPanel panel) { for(Component component : panel.getComponents()) { if(component instanceof JTextField) { return ((JTextField) component).getText(); } } return ""; } public static void showExtractAssets(ModelCreator creator) { JDialog dialog = new JDialog(creator, "Extract Assets", Dialog.ModalityType.APPLICATION_MODAL); dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); SpringLayout layout = new SpringLayout(); JPanel panel = new JPanel(layout); panel.setPreferredSize(new Dimension(300, 150)); dialog.add(panel); JLabel labelInfo = new JLabel("This tool allows you to extract Minecraft's assets. The versions listed below are the ones you have downloaded with the Java edition of the game."); panel.add(labelInfo); JLabel labelMinecraftAssets = new JLabel("Minecraft Version"); panel.add(labelMinecraftAssets); JComboBox comboBoxMinecraftVersions = new JComboBox<>(); comboBoxMinecraftVersions.setPreferredSize(new Dimension(40, 24)); Util.getMinecraftVersions().forEach(comboBoxMinecraftVersions::addItem); panel.add(comboBoxMinecraftVersions); JButton btnExtract = new JButton("Extract"); btnExtract.setIcon(Icons.extract); btnExtract.setPreferredSize(new Dimension(80, 24)); btnExtract.addActionListener(e -> { Util.extractMinecraftAssets((String) comboBoxMinecraftVersions.getSelectedItem(), dialog); dialog.dispose(); }); panel.add(btnExtract); layout.putConstraint(SpringLayout.NORTH, labelInfo, 10, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.EAST, labelInfo, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.WEST, labelInfo, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, labelMinecraftAssets, 2, SpringLayout.NORTH, comboBoxMinecraftVersions); layout.putConstraint(SpringLayout.WEST, labelMinecraftAssets, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, comboBoxMinecraftVersions, 15, SpringLayout.SOUTH, labelInfo); layout.putConstraint(SpringLayout.WEST, comboBoxMinecraftVersions, 10, SpringLayout.EAST, labelMinecraftAssets); layout.putConstraint(SpringLayout.EAST, comboBoxMinecraftVersions, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.SOUTH, btnExtract, -10, SpringLayout.SOUTH, panel); layout.putConstraint(SpringLayout.EAST, btnExtract, -10, SpringLayout.EAST, panel); dialog.pack(); dialog.setResizable(false); dialog.setLocationRelativeTo(null); dialog.setVisible(true); } public static JPanel createColorSelector(Window parent, String labelText, int startColor, Processor processor) { SpringLayout layout = new SpringLayout(); JPanel panel = new JPanel(layout); panel.setPreferredSize(new Dimension(200, 30)); panel.setBackground(new Color(0, 0, 0, 0)); JLabel label = new JLabel(labelText); panel.add(label); JPanel colorPanel = new JPanel(); colorPanel.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); colorPanel.setBackground(new Color(startColor)); colorPanel.setPreferredSize(new Dimension(24, 24)); panel.add(colorPanel); JButton button = new JButton("Change"); button.setPreferredSize(new Dimension(80, 24)); button.addActionListener(e -> { int color = selectColor(parent, startColor); if(processor.run(color)) { colorPanel.setBackground(new Color(color)); } }); panel.add(button); layout.putConstraint(SpringLayout.WEST, label, 0, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.VERTICAL_CENTER, label, 0, SpringLayout.VERTICAL_CENTER, panel); layout.putConstraint(SpringLayout.EAST, label, 5, SpringLayout.WEST, colorPanel); layout.putConstraint(SpringLayout.WEST, colorPanel, 80, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.VERTICAL_CENTER, colorPanel, 0, SpringLayout.VERTICAL_CENTER, panel); layout.putConstraint(SpringLayout.EAST, colorPanel, -10, SpringLayout.WEST, button); layout.putConstraint(SpringLayout.EAST, button, 0, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.VERTICAL_CENTER, button, 0, SpringLayout.VERTICAL_CENTER, panel); return panel; } private static int selectColor(Window parent, int startColor) { JDialog dialog = new JDialog(parent, "Select a Color", Dialog.ModalityType.APPLICATION_MODAL); dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); JPanel panel = new JPanel(new BorderLayout()); dialog.add(panel); JColorChooser colorChooser = new JColorChooser(); colorChooser.setColor(startColor); panel.add(colorChooser, BorderLayout.CENTER); JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT)); panel.add(buttons, BorderLayout.SOUTH); JButton btnExtract = new JButton("Select"); btnExtract.setIcon(Icons.extract); btnExtract.setPreferredSize(new Dimension(80, 24)); btnExtract.addActionListener(e -> dialog.dispose()); buttons.add(btnExtract); dialog.pack(); dialog.setResizable(false); dialog.setLocationRelativeTo(null); dialog.setVisible(true); return colorChooser.getColor().getRGB(); } private static Processor createFaceColorProcessor(int side) { return integer -> { if(Face.getFaceColour(side) != integer) { Face.setFaceColor(side, integer); return true; } return false; }; } private static void showDisplayProperties(ModelCreator creator) { DisplayPropertiesDialog dialog = new DisplayPropertiesDialog(creator); dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { Menu.displayPropertiesDialog = null; ModelCreator.restoreStandardRenderer(); } }); dialog.setLocationRelativeTo(null); dialog.setLocation(dialog.getLocation().x - 500, dialog.getLocation().y); dialog.setVisible(true); dialog.requestFocus(); Menu.displayPropertiesDialog = dialog; ModelCreator.setCanvasRenderer(DisplayProperties.RENDER_MAP.get("gui")); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/component/MenuAdapter.java ================================================ package com.mrcrayfish.modelcreator.component; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; /** * Author: MrCrayfish */ public abstract class MenuAdapter implements MenuListener { @Override public void menuSelected(MenuEvent e) { } @Override public void menuDeselected(MenuEvent e) { } @Override public void menuCanceled(MenuEvent e) { } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/component/TextureEntryEditor.java ================================================ package com.mrcrayfish.modelcreator.component; import com.mrcrayfish.modelcreator.Icons; import com.mrcrayfish.modelcreator.Settings; import com.mrcrayfish.modelcreator.TexturePath; import com.mrcrayfish.modelcreator.texture.TextureEntry; import com.mrcrayfish.modelcreator.util.ComponentUtil; import com.mrcrayfish.modelcreator.util.Util; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Locale; /** * Author: MrCrayfish */ public class TextureEntryEditor extends JDialog { private TextureEntry entry; private JLabel icon; private JTextField textFieldKey; private JTextField textFieldValue; private boolean triedEditingValue = false; private File texture = null; public TextureEntryEditor(Window owner, TextureEntry entry, ModalityType type) { super(owner, "Edit Texture Entry", type); this.entry = entry; this.setPreferredSize(new Dimension(300, 370)); this.setResizable(false); this.initComponents(); this.pack(); } private void initComponents() { JPanel panel = new JPanel(); panel.setLayout(new SpringLayout()); this.add(panel); JPanel image = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); image.setPreferredSize(new Dimension(150, 150)); image.setBackground(Color.WHITE); icon = new JLabel(resize(entry.getSource(), 150)); image.add(icon); panel.add(image); JPanel fileSelector = ComponentUtil.createFileSelector("File", this, entry.getTextureFile().getAbsolutePath(), new FileNameExtensionFilter("PNG Image", "png"), file -> { if(this.setTexture(file)) { TexturePath texturePath = new TexturePath(file); textFieldValue.setText(texturePath.toString()); return true; } return false; }); panel.add(fileSelector); JSeparator separator1 = new JSeparator(); panel.add(separator1); JLabel labelKey = new JLabel("Key"); panel.add(labelKey); textFieldKey = new JTextField(); textFieldKey.setPreferredSize(new Dimension(0, 24)); textFieldKey.setText(entry.getKey()); panel.add(textFieldKey); JLabel labelValue = new JLabel("Value"); panel.add(labelValue); textFieldValue = new JTextField(); textFieldValue.setPreferredSize(new Dimension(0, 24)); textFieldValue.setText(entry.getTexturePath().toString()); textFieldValue.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { if(!triedEditingValue) { JOptionPane.showMessageDialog(TextureEntryEditor.this, "Only edit this value if you are an advanced user. Changing this may cause the texture to not load in Minecraft", "Important", JOptionPane.INFORMATION_MESSAGE); triedEditingValue = true; } } }); panel.add(textFieldValue); JSeparator separator2 = new JSeparator(); panel.add(separator2); JButton btnRefresh = new JButton(); btnRefresh.setIcon(Icons.refresh); btnRefresh.addActionListener(e -> this.setTexture(entry.getTextureFile())); panel.add(btnRefresh); JButton btnEdit = new JButton("Edit"); btnEdit.setIcon(Icons.edit_image); btnEdit.addActionListener(a -> { String program = Settings.getImageEditor(); if(!program.isEmpty()) { try { String command = program + " " + String.format(Settings.getImageEditorArgs(), entry.getTextureFile().getAbsolutePath()); Runtime.getRuntime().exec(command); } catch(IOException e) { e.printStackTrace(); } } else { int returnVal = JOptionPane.showConfirmDialog(this, "Image Editor has not been configured. Do you want to open with default editor?", "Message", JOptionPane.YES_NO_OPTION); if(returnVal == JOptionPane.YES_OPTION) { try { Desktop.getDesktop().edit(entry.getTextureFile()); } catch(IOException e) { e.printStackTrace(); } } } }); panel.add(btnEdit); JButton btnCancel = new JButton("Cancel"); btnCancel.addActionListener(e -> this.dispose()); panel.add(btnCancel); JButton btnSave = new JButton("Save"); btnSave.setIcon(Icons.disk); btnSave.addActionListener(e -> { String key = textFieldKey.getText().trim().toLowerCase(Locale.ENGLISH); String value = textFieldValue.getText().trim().toLowerCase(Locale.ENGLISH); if(!TextureEntry.KEY_PATTERN.matcher(key).matches()) { JOptionPane.showMessageDialog(this, "Invalid key format. It may only contain lowercase letters, numbers, and underscore.", "Key Error", JOptionPane.ERROR_MESSAGE); return; } TextureEntry foundEntry = TextureManager.getTexture(key); if(foundEntry != null && foundEntry != entry) { JOptionPane.showMessageDialog(this, "The key entered is already in use by another texture. Please choose a different key", "Key Error", JOptionPane.ERROR_MESSAGE); return; } if("particle".equals(key)) { JOptionPane.showMessageDialog(this, "The key 'particle' is reserved. Please choose a different key", "Key Error", JOptionPane.ERROR_MESSAGE); return; } if(!TexturePath.PATTERN.matcher(value).matches()) { JOptionPane.showMessageDialog(this, "Invalid value format", "Error", JOptionPane.ERROR_MESSAGE); return; } if(texture != null) { try { Dimension dimension = Util.getImageDimension(texture); if(dimension.getWidth() % 16 != 0 || dimension.getHeight() % 16 != 0) { JOptionPane.showMessageDialog(this, "Image size must be multiple of 16", "Error", JOptionPane.ERROR_MESSAGE); return; } } catch(IOException e1) { JOptionPane.showMessageDialog(this, "Unable to determine image dimensions", "Error", JOptionPane.ERROR_MESSAGE); return; } entry.setTextureFile(texture); } entry.setTexturePath(new TexturePath(value)); entry.setKey(key); this.dispose(); }); panel.add(btnSave); SpringLayout layout = (SpringLayout) panel.getLayout(); layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, image, 0, SpringLayout.HORIZONTAL_CENTER, panel); layout.putConstraint(SpringLayout.NORTH, image, 10, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.WEST, fileSelector, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, fileSelector, 20, SpringLayout.SOUTH, image); layout.putConstraint(SpringLayout.EAST, fileSelector, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.WEST, separator1, 0, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, separator1, 10, SpringLayout.SOUTH, fileSelector); layout.putConstraint(SpringLayout.EAST, separator1, 0, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.WEST, labelKey, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, labelKey, 2, SpringLayout.NORTH, textFieldKey); layout.putConstraint(SpringLayout.WEST, textFieldKey, 40, SpringLayout.WEST, labelKey); layout.putConstraint(SpringLayout.NORTH, textFieldKey, 10, SpringLayout.SOUTH, separator1); layout.putConstraint(SpringLayout.EAST, textFieldKey, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.WEST, labelValue, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, labelValue, 2, SpringLayout.NORTH, textFieldValue); layout.putConstraint(SpringLayout.WEST, textFieldValue, 40, SpringLayout.WEST, labelValue); layout.putConstraint(SpringLayout.NORTH, textFieldValue, 10, SpringLayout.SOUTH, textFieldKey); layout.putConstraint(SpringLayout.EAST, textFieldValue, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.WEST, separator2, 0, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, separator2, 10, SpringLayout.SOUTH, textFieldValue); layout.putConstraint(SpringLayout.EAST, separator2, 0, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.WEST, btnRefresh, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.SOUTH, btnRefresh, -10, SpringLayout.SOUTH, panel); layout.putConstraint(SpringLayout.WEST, btnEdit, 10, SpringLayout.EAST, btnRefresh); layout.putConstraint(SpringLayout.SOUTH, btnEdit, -10, SpringLayout.SOUTH, panel); layout.putConstraint(SpringLayout.EAST, btnCancel, -10, SpringLayout.WEST, btnSave); layout.putConstraint(SpringLayout.SOUTH, btnCancel, -10, SpringLayout.SOUTH, panel); layout.putConstraint(SpringLayout.EAST, btnSave, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.SOUTH, btnSave, -10, SpringLayout.SOUTH, panel); } private static ImageIcon resize(BufferedImage source, int size) { Image scaledImage = source.getScaledInstance(size, size, java.awt.Image.SCALE_FAST); return new ImageIcon(scaledImage); } private boolean setTexture(File file) { try { Dimension dimension = Util.getImageDimension(file); if(dimension.getWidth() % 16 != 0 || dimension.getHeight() % 16 != 0) { JOptionPane.showMessageDialog(this, "Image size must be multiple of 16", "Error", JOptionPane.ERROR_MESSAGE); return false; } } catch(IOException e1) { JOptionPane.showMessageDialog(this, "Unable to determine image dimensions", "Error", JOptionPane.ERROR_MESSAGE); return false; } try { icon.setIcon(resize(ImageIO.read(file), 150)); texture = file; } catch(IOException e) { JOptionPane.showMessageDialog(this, "Unable to load image", "Error", JOptionPane.ERROR_MESSAGE); return false; } return true; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/component/TextureManager.java ================================================ package com.mrcrayfish.modelcreator.component; import com.mrcrayfish.modelcreator.Icons; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.Settings; import com.mrcrayfish.modelcreator.TexturePath; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.texture.TextureEntry; import com.mrcrayfish.modelcreator.util.Util; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; import java.util.List; /** * Author: MrCrayfish */ public class TextureManager extends JDialog { public static final Object LOCK = new Object(); public static final int CANCELLED = 1; public static final int APPLIED = 1; private static final List pendingLoad = new ArrayList<>(); private static final List pendingRemove = new ArrayList<>(); private static final List textureEntries = new ArrayList<>(); private static File lastLocation = null; private ElementManager manager; private JList textureEntryList; private JButton btnApply; private JButton btnCancel; private JButton btnNew; private JButton btnEdit; private JButton btnRemove; private int result; private boolean canApply = true; public TextureManager(Frame owner, ElementManager manager, ModalityType type, boolean canApply) { super(owner, "Texture Manager", type); this.canApply = canApply; this.manager = manager; this.setPreferredSize(new Dimension(500, 392)); this.setResizable(false); this.initComponents(); this.pack(); } private void initComponents() { JPanel content = new JPanel(); content.setLayout(new SpringLayout()); this.add(content); textureEntryList = new JList<>(); textureEntryList.setModel(new DefaultListModel<>()); textureEntryList.setCellRenderer(new TextureCellRenderer()); textureEntryList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); textureEntryList.addListSelectionListener(e -> { if(btnApply != null) { btnApply.setEnabled(true); } btnEdit.setEnabled(true); btnRemove.setEnabled(true); }); JScrollPane scrollPane = new JScrollPane(textureEntryList); scrollPane.getVerticalScrollBar().setUnitIncrement(10); content.add(scrollPane); if(canApply) { btnApply = new JButton("Apply"); btnApply.setPreferredSize(new Dimension(110, 26)); btnApply.setEnabled(false); btnApply.addActionListener(e -> { result = APPLIED; this.dispose(); }); content.add(btnApply); } btnCancel = new JButton(canApply ? "Cancel" : "Close"); btnCancel.setPreferredSize(new Dimension(110, 26)); btnCancel.addActionListener(e -> this.dispose()); content.add(btnCancel); btnNew = new JButton("New Texture"); btnNew.addActionListener(e -> showFileChooser()); btnNew.setPreferredSize(new Dimension(110, 26)); btnNew.setIcon(Icons.texture); content.add(btnNew); btnEdit = new JButton("Edit"); btnEdit.setPreferredSize(new Dimension(110, 26)); btnEdit.setIcon(Icons.edit); btnEdit.setEnabled(false); btnEdit.addActionListener(e -> { TextureEntry entry = textureEntryList.getSelectedValue(); if(entry != null) { TextureEntryEditor editor = new TextureEntryEditor(this.getOwner(), entry, ModalityType.APPLICATION_MODAL); editor.setLocationRelativeTo(null); editor.setVisible(true); } }); content.add(btnEdit); btnRemove = new JButton("Remove"); btnRemove.setPreferredSize(new Dimension(110, 26)); btnRemove.setIcon(Icons.bin2); btnRemove.setEnabled(false); btnRemove.addActionListener(e -> { if(textureEntryList.getSelectedIndex() != -1) { TextureEntry entry = textureEntryList.getSelectedValue(); manager.getAllElements().forEach(element -> { for(Face face : element.getAllFaces()) { if(face.getTexture() == entry) { face.setTexture(null); } } }); if(manager.getParticle() == entry) { manager.setParticle(null); } textureEntries.remove(entry); DefaultListModel listModel = (DefaultListModel) textureEntryList.getModel(); listModel.removeElement(entry); TextureManager.removeTexture(entry); manager.updateValues(); } if(btnApply != null) { btnApply.setEnabled(false); } btnEdit.setEnabled(false); btnRemove.setEnabled(false); }); content.add(btnRemove); SpringLayout layout = (SpringLayout) content.getLayout(); layout.putConstraint(SpringLayout.WEST, scrollPane, 10, SpringLayout.WEST, content); layout.putConstraint(SpringLayout.NORTH, scrollPane, 10, SpringLayout.NORTH, content); layout.putConstraint(SpringLayout.EAST, scrollPane, -10, SpringLayout.WEST, btnNew); layout.putConstraint(SpringLayout.SOUTH, scrollPane, -10, SpringLayout.SOUTH, content); if(canApply) { layout.putConstraint(SpringLayout.SOUTH, btnApply, -10, SpringLayout.NORTH, btnCancel); layout.putConstraint(SpringLayout.EAST, btnApply, -10, SpringLayout.EAST, content); } layout.putConstraint(SpringLayout.SOUTH, btnCancel, -10, SpringLayout.SOUTH, content); layout.putConstraint(SpringLayout.EAST, btnCancel, -10, SpringLayout.EAST, content); layout.putConstraint(SpringLayout.NORTH, btnNew, 10, SpringLayout.NORTH, content); layout.putConstraint(SpringLayout.EAST, btnNew, -10, SpringLayout.EAST, content); layout.putConstraint(SpringLayout.NORTH, btnEdit, 10, SpringLayout.SOUTH, btnNew); layout.putConstraint(SpringLayout.EAST, btnEdit, -10, SpringLayout.EAST, content); layout.putConstraint(SpringLayout.NORTH, btnRemove, 10, SpringLayout.SOUTH, btnEdit); layout.putConstraint(SpringLayout.EAST, btnRemove, -10, SpringLayout.EAST, content); DefaultListModel listModel = (DefaultListModel) textureEntryList.getModel(); textureEntries.forEach(listModel::addElement); } public TextureEntry getSelectedTexture() { if(textureEntryList != null) { return textureEntryList.getSelectedValue(); } return null; } public int getResult() { return result; } public void showFileChooser() { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Select a Texture"); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setApproveButtonText("Select"); if(lastLocation == null) { String dir = Settings.getImageImportDir(); if(dir != null) { lastLocation = new File(dir); } } if(lastLocation != null) { chooser.setCurrentDirectory(lastLocation); } else { try { if(Settings.getAssetsDir() != null) { chooser.setCurrentDirectory(new File(Settings.getAssetsDir())); } } catch(Exception e) { e.printStackTrace(); } } FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG Images", "png"); chooser.setFileFilter(filter); int returnVal = chooser.showOpenDialog(null); if(returnVal == JFileChooser.APPROVE_OPTION) { this.addImage(chooser.getSelectedFile()); } } private void addImage(File image) { try { String type = Files.probeContentType(image.toPath()); if(type.equals("image/png")) { Dimension dimension = Util.getImageDimension(image); if(dimension.getWidth() % 16 != 0 || dimension.getHeight() % 16 != 0) { JOptionPane.showMessageDialog(this, "Image size must be multiple of 16", "Error", JOptionPane.ERROR_MESSAGE); return; } lastLocation = image.getParentFile(); Settings.setImageImportDir(lastLocation.toString()); DefaultListModel listModel = (DefaultListModel) textureEntryList.getModel(); TextureEntry entry = new TextureEntry(image); listModel.addElement(entry); textureEntries.add(entry); TextureManager.loadTexture(entry); } } catch(IOException e) { e.printStackTrace(); } } public static TextureEntry addImage(String id, TexturePath path, File image) { for(TextureEntry entry : textureEntries) { if(entry.getKey().equals(id)) { return entry; } } try { if(image.exists()) { String type = Files.probeContentType(image.toPath()); if(type.equals("image/png")) { Dimension dimension = Util.getImageDimension(image); if(dimension.getWidth() % 16 != 0 || dimension.getHeight() % 16 != 0) { JOptionPane.showMessageDialog(null, "Image size must be multiple of 16", "Error", JOptionPane.ERROR_MESSAGE); return null; } TextureEntry entry = new TextureEntry(id, path, image); textureEntries.add(entry); TextureManager.loadTexture(entry); return entry; } } } catch(IOException e) { e.printStackTrace(); } return null; } public static TextureEntry getTexture(String id) { for(TextureEntry entry : textureEntries) { if(entry.getKey().equalsIgnoreCase(id)) { return entry; } } return null; } public static class TextureCellRenderer implements ListCellRenderer { @Override public Component getListCellRendererComponent(JList list, TextureEntry entry, int index, boolean isSelected, boolean cellHasFocus) { JPanel panel = new JPanel(); panel.setBackground(isSelected ? new Color(186, 193, 211) : ModelCreator.BACKGROUND); panel.setPreferredSize(new Dimension(200, 85)); if(isSelected) { panel.setBorder(BorderFactory.createLineBorder(new Color(131, 138, 156), 1)); } SpringLayout layout = new SpringLayout(); panel.setLayout(layout); JLabel icon = new JLabel(entry.getIcon()); panel.add(icon); JLabel id = new JLabel("" + entry.getKey() + ""); panel.add(id); JLabel name = new JLabel("" + entry.getTexturePath().toString() + ""); panel.add(name); layout.putConstraint(SpringLayout.WEST, icon, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, icon, 10, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.WEST, id, 10, SpringLayout.EAST, icon); layout.putConstraint(SpringLayout.NORTH, id, 10, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.EAST, id, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.WEST, name, 10, SpringLayout.EAST, icon); layout.putConstraint(SpringLayout.NORTH, name, 5, SpringLayout.SOUTH, id); layout.putConstraint(SpringLayout.EAST, name, -10, SpringLayout.EAST, panel); return panel; } } public static TextureEntry display(Frame owner, ElementManager manager, ModalityType modalityType) { TextureManager textureManager = new TextureManager(owner, manager, modalityType, true); textureManager.setLocationRelativeTo(null); textureManager.setVisible(true); if(textureManager.getResult() == APPLIED) { return textureManager.getSelectedTexture(); } return null; } public static void loadTexture(TextureEntry entry) { synchronized(LOCK) { pendingLoad.add(entry); } } public static void removeTexture(TextureEntry entry) { synchronized(LOCK) { pendingRemove.add(entry); } } public static void processPendingTextures() { if(pendingRemove.size() > 0) { synchronized(LOCK) { for(TextureEntry entry : pendingRemove) { entry.deleteTexture(); } pendingRemove.clear(); } } if(pendingLoad.size() > 0) { synchronized(LOCK) { for(TextureEntry entry : pendingLoad) { entry.deleteTexture(); entry.loadTexture(); } pendingLoad.clear(); } } } public static void clear() { synchronized(LOCK) { pendingRemove.addAll(textureEntries); textureEntries.clear(); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/dialog/WelcomeDialog.java ================================================ package com.mrcrayfish.modelcreator.dialog; import com.mrcrayfish.modelcreator.Constants; import com.mrcrayfish.modelcreator.Icons; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; import java.net.URL; public class WelcomeDialog { public static void show(JFrame parent) { JPanel dialogContent = getDialogContent(parent); JDialog welcomeDialog = getWelcomeDialog(parent, dialogContent); welcomeDialog.requestFocus(); welcomeDialog.setAlwaysOnTop(true); showDialog(welcomeDialog); } private static JPanel getDialogContent(JFrame parent) { JPanel container = new JPanel(new BorderLayout(20, 10)); container.setBorder(new EmptyBorder(10, 10, 10, 10)); ImageIcon crayfish = new ImageIcon(parent.getClass().getClassLoader().getResource("sticker.png")); container.add(new JLabel(crayfish), BorderLayout.EAST); JPanel leftPanel = getLeftPanel(); container.add(leftPanel, BorderLayout.CENTER); JPanel btnGrid = getButtonGrid(); container.add(btnGrid, BorderLayout.SOUTH); return container; } private static JPanel getLeftPanel() { JPanel leftPanel = new JPanel(new BorderLayout()); JLabel title = new JLabel("
Model Creator by MrCrayfish
"); leftPanel.add(title, BorderLayout.NORTH); JScrollPane message = getScrollableMessage(); leftPanel.add(message, BorderLayout.CENTER); return leftPanel; } private static JScrollPane getScrollableMessage() { String message = "Thank you for downloading my program. I hope it encourages" + " you to create awesome models. If you do create something awesome, I" + " would love to see it. You can post your screenshots to me via Twitter" + " or Facebook. If you are unsure how to use anything works, hover your " + "mouse over the component and it will tell you what it does." + "\n\n" + "I've put a lot of work into this program, so if you are " + "feeling generous, you can donate by clicking the button below. Thank you!" + ""; JTextArea textArea = new JTextArea(message); textArea.setEditable(false); textArea.setCursor(null); textArea.setFocusable(false); textArea.setBorder(null); textArea.setOpaque(false); textArea.setLineWrap(true); textArea.setWrapStyleWord(true); JScrollPane scrollPane = new JScrollPane(textArea); scrollPane.setBorder(null); return scrollPane; } private static JPanel getButtonGrid() { JPanel btnGrid = new JPanel(new GridLayout(1, 4, 5, 0)); JButton btnDonate = new JButton("Donate"); btnDonate.setIcon(Icons.patreon); btnDonate.addActionListener(a -> openUrl(Constants.URL_DONATE)); btnGrid.add(btnDonate); JButton btnTwitter = new JButton("Twitter"); btnTwitter.setIcon(Icons.twitter); btnTwitter.addActionListener(arg0 -> openUrl(Constants.URL_TWITTER)); btnGrid.add(btnTwitter); JButton btnFacebook = new JButton("Facebook"); btnFacebook.setIcon(Icons.facebook); btnFacebook.addActionListener(a -> openUrl(Constants.URL_FACEBOOK)); btnGrid.add(btnFacebook); JButton btnClose = new JButton("Close"); btnClose.addActionListener(a -> SwingUtilities.getWindowAncestor(btnClose).dispose()); btnGrid.add(btnClose); return btnGrid; } private static void openUrl(String url) { Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; if(desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { try { desktop.browse(new URL(url).toURI()); } catch(Exception e) { e.printStackTrace(); } } } private static JDialog getWelcomeDialog(JFrame parent, JPanel dialogContent) { JDialog dialog = new JDialog(parent, "Welcome", Dialog.ModalityType.APPLICATION_MODAL); dialog.setResizable(false); dialog.setPreferredSize(new Dimension(500, 290)); dialog.add(dialogContent); dialog.pack(); return dialog; } private static void showDialog(JDialog dialog) { dialog.setLocationRelativeTo(null); dialog.setVisible(true); dialog.requestFocusInWindow(); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/CanvasRenderer.java ================================================ package com.mrcrayfish.modelcreator.display; import com.mrcrayfish.modelcreator.Camera; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import java.util.ArrayList; import java.util.List; /** * Author: MrCrayfish */ public abstract class CanvasRenderer { protected List elements = new ArrayList<>(); public void onInit(Camera camera) {} public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) {} public void onRenderOverlay(ElementManager manager, Camera camera, ModelCreator creator) {} } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/DisplayProperties.java ================================================ package com.mrcrayfish.modelcreator.display; import com.mrcrayfish.modelcreator.display.render.*; import java.util.HashMap; import java.util.Map; /** * Author: MrCrayfish */ public class DisplayProperties { public static final Map RENDER_MAP = new HashMap<>(); public static final DisplayProperties MODEL_CREATOR_BLOCK; public static final DisplayProperties DEFAULT_BLOCK; public static final DisplayProperties DEFAULT_ITEM; static { MODEL_CREATOR_BLOCK = new DisplayProperties("Model Creator Block", true); MODEL_CREATOR_BLOCK.add("gui", 30, 45, 0, 0, 0, 0, 0.625, 0.625, 0.625, true); MODEL_CREATOR_BLOCK.add("ground", 0, 0, 0, 0, 3, 0, 0.25, 0.25, 0.25, true); MODEL_CREATOR_BLOCK.add("fixed", 0, 180, 0, 0, 0, 0, 1, 1, 1, true); MODEL_CREATOR_BLOCK.add("head", 0, 180, 0, 0, 0, 0, 1, 1, 1, true); MODEL_CREATOR_BLOCK.add("firstperson_righthand", 0, 315, 0, 0, 2.5, 0, 0.4, 0.4, 0.4, true); MODEL_CREATOR_BLOCK.add("firstperson_lefthand", 0, 0, 45, 0, 2.5, 0, 0.4, 0.4, 0.4, false); MODEL_CREATOR_BLOCK.add("thirdperson_righthand", 75, 315, 0, 0, 2.5, 0, 0.375, 0.375, 0.375, true); MODEL_CREATOR_BLOCK.add("thirdperson_lefthand", 75, 45, 0, 0, 2.5, 0, 0.375, 0.375, 0.375, false); DEFAULT_BLOCK = new DisplayProperties("Default Block", true); DEFAULT_BLOCK.add("gui", 30, 225, 0, 0, 0, 0, 0.625, 0.625, 0.625, true); DEFAULT_BLOCK.add("ground", 0, 0, 0, 0, 3, 0, 0.25, 0.25, 0.25, true); DEFAULT_BLOCK.add("fixed", 0, 0, 0, 0, 0, 0, 0.5, 0.5, 0.5, true); DEFAULT_BLOCK.add("head", 0, 0, 0, 0, 0, 0, 1, 1, 1, false); DEFAULT_BLOCK.add("firstperson_righthand", 0, 45, 0, 0, 2.5, 0, 0.4, 0.4, 0.4, true); DEFAULT_BLOCK.add("firstperson_lefthand", 0, 0, 225, 0, 2.5, 0, 0.4, 0.4, 0.4, true); DEFAULT_BLOCK.add("thirdperson_righthand", 75, 45, 0, 0, 2.5, 0, 0.375, 0.375, 0.375, true); DEFAULT_BLOCK.add("thirdperson_lefthand", 75, 225, 0, 0, 2.5, 0, 0.375, 0.375, 0.375, true); DEFAULT_ITEM = new DisplayProperties("Default Item", true); DEFAULT_ITEM.add("gui", 0, 0, 0, 0, 0, 0, 1, 1, 1, true); DEFAULT_ITEM.add("ground", 0, 0, 0, 0, 2, 0, 0.5, 0.5, 0.5, true); DEFAULT_ITEM.add("fixed", 0, 180, 0, 0, 0, 0, 1, 1, 1, true); DEFAULT_ITEM.add("head", 0, 180, 0, 0, 13, 7, 1, 1, 1, true); DEFAULT_ITEM.add("firstperson_righthand", 0, -90, 25, 1.13, 3.2, 1.13, 0.68, 0.68, 0.68, true); DEFAULT_ITEM.add("firstperson_lefthand", 0, -90, 25, 1.13, 3.2, 1.13, 0.68, 0.68, 0.68, true); DEFAULT_ITEM.add("thirdperson_righthand", 0, 0, 0, 0, 3, 1, 0.55, 0.55, 0.55, true); DEFAULT_ITEM.add("thirdperson_lefthand", 0, 0, 0, 0, 3, 1, 0.55, 0.55, 0.55, true); RENDER_MAP.put("head", new HeadPropertyRenderer()); RENDER_MAP.put("gui", new GuiPropertyRenderer()); RENDER_MAP.put("ground", new GroundPropertyRenderer()); RENDER_MAP.put("fixed", new FixedPropertyRenderer()); RENDER_MAP.put("firstperson_righthand", new FirstPersonPropertyRenderer(false)); RENDER_MAP.put("thirdperson_righthand", new ThirdPersonPropertyRenderer(false)); RENDER_MAP.put("firstperson_lefthand", new FirstPersonPropertyRenderer(true)); RENDER_MAP.put("thirdperson_lefthand", new ThirdPersonPropertyRenderer(true)); } private Map entries = new HashMap<>(); private String name; private boolean isDefault = false; private DisplayProperties(String name, boolean isDefault) { this.name = name; this.isDefault = isDefault; } public DisplayProperties(DisplayProperties properties) { this.name = properties.name; properties.entries.forEach((id, entry) -> entries.put(id, new Entry(entry))); } public DisplayProperties(String name, DisplayProperties properties) { this.name = name; properties.entries.forEach((id, entry) -> entries.put(id, new Entry(entry))); } public void add(String id, double rotationX, double rotationY, double rotationZ, double translationX, double translationY, double translationZ, double scaleX, double scaleY, double scaleZ, boolean enabled) { Entry entry = new Entry(id, rotationX, rotationY, rotationZ, translationX, translationY, translationZ, scaleX, scaleY, scaleZ); entry.setEnabled(enabled); entries.put(id, entry); } public String getName() { return name; } public boolean isDefault() { return isDefault; } public Entry getEntry(String id) { return entries.get(id); } public Map getEntries() { return entries; } @Override public String toString() { return name; } public static class Entry { private boolean enabled = true; private String id; private double rotationX, rotationY, rotationZ; private double translationX, translationY, translationZ; private double scaleX, scaleY, scaleZ; public Entry(String id, double rotationX, double rotationY, double rotationZ, double translationX, double translationY, double translationZ, double scaleX, double scaleY, double scaleZ) { this.id = id; this.rotationX = rotationX; this.rotationY = rotationY; this.rotationZ = rotationZ; this.translationX = translationX; this.translationY = translationY; this.translationZ = translationZ; this.scaleX = scaleX; this.scaleY = scaleY; this.scaleZ = scaleZ; } public Entry(Entry entry) { this.enabled = entry.enabled; this.id = entry.id; this.rotationX = entry.rotationX; this.rotationY = entry.rotationY; this.rotationZ = entry.rotationZ; this.translationX = entry.translationX; this.translationY = entry.translationY; this.translationZ = entry.translationZ; this.scaleX = entry.scaleX; this.scaleY = entry.scaleY; this.scaleZ = entry.scaleZ; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public boolean isEnabled() { return enabled; } public String getId() { return id; } public double getRotationX() { return rotationX; } public void setRotationX(double rotationX) { this.rotationX = rotationX; } public double getRotationY() { return rotationY; } public void setRotationY(double rotationY) { this.rotationY = rotationY; } public double getRotationZ() { return rotationZ; } public void setRotationZ(double rotationZ) { this.rotationZ = rotationZ; } public double getTranslationX() { return translationX; } public void setTranslationX(double translationX) { this.translationX = translationX; } public double getTranslationY() { return translationY; } public void setTranslationY(double translationY) { this.translationY = translationY; } public double getTranslationZ() { return translationZ; } public void setTranslationZ(double translationZ) { this.translationZ = translationZ; } public double getScaleX() { return scaleX; } public void setScaleX(double scaleX) { this.scaleX = scaleX; } public double getScaleY() { return scaleY; } public void setScaleY(double scaleY) { this.scaleY = scaleY; } public double getScaleZ() { return scaleZ; } public void setScaleZ(double scaleZ) { this.scaleZ = scaleZ; } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/render/DisplayPropertyRenderer.java ================================================ package com.mrcrayfish.modelcreator.display.render; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import static org.lwjgl.opengl.GL11.glTranslatef; /** * Author: MrCrayfish */ public abstract class DisplayPropertyRenderer extends StandardRenderer { @Override protected void drawElements(ElementManager manager) { glTranslatef(-8, 0, -8); for(int i = 0; i < manager.getElementCount(); i++) { Element cube = manager.getElement(i); if(cube.isVisible()) { cube.draw(); cube.drawExtras(manager); } } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/render/FirstPersonPropertyRenderer.java ================================================ package com.mrcrayfish.modelcreator.display.render; import com.mrcrayfish.modelcreator.Camera; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.texture.TextureAtlas; import com.mrcrayfish.modelcreator.util.AtlasRenderUtil; import org.lwjgl.opengl.GL11; import org.lwjgl.util.glu.GLU; import org.newdawn.slick.opengl.TextureImpl; import static org.lwjgl.opengl.GL11.*; /** * Author: MrCrayfish */ public class FirstPersonPropertyRenderer extends DisplayPropertyRenderer { private boolean leftHanded; public FirstPersonPropertyRenderer(boolean leftHanded) { this.leftHanded = leftHanded; } @Override public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) {} @Override public void onRenderOverlay(ElementManager manager, Camera camera, ModelCreator creator) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry(!leftHanded ? "firstperson_righthand" : "firstperson_lefthand"); if(entry != null) { int canvasOffset = creator.getCanvasOffset(); int canvasWidth = creator.getCanvasWidth() - creator.getCanvasOffset(); int canvasHeight = creator.getCanvasHeight(); glViewport(canvasOffset, 0, canvasWidth, canvasHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GL11.glOrtho(canvasOffset, canvasWidth, canvasHeight, 0, 500.0D, -500.0D); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); TextureAtlas.bind(); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDisable(GL_CULL_FACE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glColor3f(1.0F, 1.0F, 1.0F); double startX = (canvasWidth - 960) / 2; double startY = (canvasHeight - 540) / 2; glTranslated((int) startX, (int) startY, 0); AtlasRenderUtil.bindTexture(TextureAtlas.FIRST_PERSON_PREVIEW); AtlasRenderUtil.drawQuad(0, 0, 960, 540); glEnable(GL_SCISSOR_TEST); glScissor((int) startX, (int) startY, 960, 540); glPopMatrix(); glPushMatrix(); { glViewport((int) startX, (int) startY, 960, 540); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLU.gluPerspective(-70F, (float) 960 / (float) 540, 0.3F, 1000F); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); if(leftHanded) { glScaled(-1, 1, 1); } glTranslated(-9, 8.35, -11.5); glTranslated(-entry.getTranslationX(), -entry.getTranslationY(), entry.getTranslationZ()); glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); glRotatef(180F, 1, 0, 0); glRotatef((float) entry.getRotationX(), 1, 0, 0); glRotatef((float) entry.getRotationY(), 0, 1, 0); glRotatef((float) entry.getRotationZ(), 0, 0, 1); glTranslated(0, -8, 0); glRotated(180F, 0, 1, 0); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); if(leftHanded) { glScaled(-1, 1, 1); glRotatef(180F, 0, 1, 0); } this.drawElements(manager); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_TEXTURE_2D); glDisable(GL_SCISSOR_TEST); } glPopMatrix(); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/render/FixedPropertyRenderer.java ================================================ package com.mrcrayfish.modelcreator.display.render; import com.mrcrayfish.modelcreator.Camera; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import static org.lwjgl.opengl.GL11.*; /** * Author: MrCrayfish */ public class FixedPropertyRenderer extends DisplayPropertyRenderer { public FixedPropertyRenderer() { this.addElements(); } private void addElements() { Element frameOne = new Element(12, 1, 1); frameOne.setStartX(-6); frameOne.setStartY(2); frameOne.setStartZ(-1); elements.add(frameOne); Element frameTwo = new Element(12, 1, 1); frameTwo.setStartX(-6); frameTwo.setStartY(13); frameTwo.setStartZ(-1); elements.add(frameTwo); Element frameThree = new Element(10, 10, 0.5); frameThree.setStartX(-5); frameThree.setStartY(3); frameThree.setStartZ(-1); elements.add(frameThree); Element frameFour = new Element(1, 10, 1); frameFour.setStartX(-6); frameFour.setStartY(3); frameFour.setStartZ(-1); elements.add(frameFour); Element frameFive = new Element(1, 10, 1); frameFive.setStartX(5); frameFive.setStartY(3); frameFive.setStartZ(-1); elements.add(frameFive); } @Override public void onInit(Camera camera) { camera.setX(0); camera.setY(-9); camera.setZ(-30); camera.setRX(0); camera.setRY(0); camera.setRZ(0); } @Override public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) { DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry("fixed"); if(entry != null) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); camera.useView(); glTranslated(0, -5, 0); glScalef(1.75F, 1.75F, 1.75F); glPushMatrix(); for(Element element : elements) { element.drawExtras(manager); element.draw(); } glPopMatrix(); glTranslated(0, 8, 0); glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); glRotatef(180F, 0, 1, 0); glScalef(0.5F, 0.5F, 0.5F); glTranslated(entry.getTranslationX(), entry.getTranslationY(), entry.getTranslationZ()); glRotatef((float) entry.getRotationX(), 1, 0, 0); glRotatef((float) entry.getRotationY(), 0, 1, 0); glRotatef((float) entry.getRotationZ(), 0, 0, 1); glTranslated(0, -8, 0); glPushMatrix(); { this.drawGrid(camera, false); this.drawElements(manager); } glPopMatrix(); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/render/GroundPropertyRenderer.java ================================================ package com.mrcrayfish.modelcreator.display.render; import com.mrcrayfish.modelcreator.Animation; import com.mrcrayfish.modelcreator.Camera; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import static org.lwjgl.opengl.GL11.*; /** * Author: MrCrayfish */ public class GroundPropertyRenderer extends DisplayPropertyRenderer { public GroundPropertyRenderer() { this.addElements(); } private void addElements() { Element block = new Element(16, 16, 16); block.setStartX(-8); block.setStartY(-16); block.setStartZ(-8); elements.add(block); } @Override public void onInit(Camera camera) { camera.setX(0); camera.setY(0); camera.setZ(-25); camera.setRX(20); camera.setRY(0); camera.setRZ(0); } @Override public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) { DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry("ground"); if(entry != null) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); camera.useView(); for(Element element : elements) { element.drawExtras(manager); element.draw(); } double yOffset = (Animation.getCounter() + Animation.getCounter()) / 60F; yOffset = Math.sin(yOffset); glTranslated(0, (yOffset * 1.5) * entry.getScaleY(), 0); glRotated((Animation.getCounter() + Animation.getPartialTicks()), 0, 1, 0); glTranslated(-entry.getTranslationX(), entry.getTranslationY(), -entry.getTranslationZ()); glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); glTranslated(0, 5.5, 0); glRotatef(180F, 0, 1, 0); glRotatef((float) entry.getRotationX(), 1, 0, 0); glRotatef((float) entry.getRotationY(), 0, 1, 0); glRotatef((float) entry.getRotationZ(), 0, 0, 1); glTranslated(0, -8, 0); glPushMatrix(); { this.drawGrid(camera, false); this.drawElements(manager); } glPopMatrix(); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/render/GuiPropertyRenderer.java ================================================ package com.mrcrayfish.modelcreator.display.render; import com.mrcrayfish.modelcreator.Camera; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.texture.TextureAtlas; import com.mrcrayfish.modelcreator.util.AtlasRenderUtil; import org.lwjgl.opengl.GL11; import static org.lwjgl.opengl.GL11.*; /** * Author: MrCrayfish */ public class GuiPropertyRenderer extends DisplayPropertyRenderer { @Override public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) {} @Override public void onRenderOverlay(ElementManager manager, Camera camera, ModelCreator creator) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry("gui"); if(entry != null) { int canvasOffset = creator.getCanvasOffset(); int canvasWidth = creator.getCanvasWidth() - creator.getCanvasOffset(); int canvasHeight = creator.getCanvasHeight(); glViewport(canvasOffset, 0, canvasWidth, canvasHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GL11.glOrtho(canvasOffset, canvasWidth, canvasHeight, 0, 500.0D, -500.0D); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); { TextureAtlas.bind(); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDisable(GL_CULL_FACE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glColor3f(1.0F, 1.0F, 1.0F); int scale = 30; int slotSize = 16 * scale; int startX = (canvasWidth - slotSize) / 2; int startY = (canvasHeight - slotSize) / 2; glTranslatef(startX, startY, 0); glScalef(scale, scale, 0); AtlasRenderUtil.bindTexture(TextureAtlas.GUI_SLOT); AtlasRenderUtil.drawQuad(0, 0, 16, 16); } glPopMatrix(); glPushMatrix(); { int scale = 24; int startX = canvasWidth / 2; int startY = canvasHeight / 2; glTranslatef(startX, startY, 0); glScaled(scale, scale, scale); glTranslated(entry.getTranslationX(), -entry.getTranslationY(), entry.getTranslationZ()); glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); glRotatef(180F, 1, 0, 0); glRotatef((float) entry.getRotationX(), 1, 0, 0); glRotatef((float) entry.getRotationY(), 0, 1, 0); glRotatef((float) entry.getRotationZ(), 0, 0, 1); glTranslatef(0, -8, 0); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); this.drawElements(manager); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_TEXTURE_2D); } glPopMatrix(); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/render/HeadPropertyRenderer.java ================================================ package com.mrcrayfish.modelcreator.display.render; import com.mrcrayfish.modelcreator.Camera; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import static org.lwjgl.opengl.GL11.*; /** * Author: MrCrayfish */ public class HeadPropertyRenderer extends DisplayPropertyRenderer { public HeadPropertyRenderer() { this.addElements(); } private void addElements() { Element rightArm = new Element(4, 12, 4); rightArm.setStartX(-8); rightArm.setStartY(-12); rightArm.setStartZ(-2); rightArm.setOriginX(-6); rightArm.setOriginY(-2); rightArm.setOriginZ(0); rightArm.setRotation(15F); //TODO maybe add option to change elements.add(rightArm); Element leftArm = new Element(4, 12, 4); leftArm.setStartX(4); leftArm.setStartY(-12); leftArm.setStartZ(-2); leftArm.setOriginX(6); leftArm.setOriginY(-2); leftArm.setOriginZ(0); leftArm.setRotation(-15F); //TODO maybe add option to change elements.add(leftArm); Element body = new Element(8, 12, 4); body.setStartX(-4); body.setStartY(-12); body.setStartZ(-2); body.setOriginX(0); body.setOriginY(0); body.setOriginZ(0); elements.add(body); Element head = new Element(8, 8, 8); head.setStartX(-4); head.setStartY(0); head.setStartZ(-4); head.setOriginX(0); head.setOriginY(0); head.setOriginZ(0); elements.add(head); Element rightLeg = new Element(4, 12, 4); rightLeg.setStartX(-4); rightLeg.setStartY(-24); rightLeg.setStartZ(-2); rightLeg.setOriginX(4); rightLeg.setOriginY(-12); rightLeg.setOriginZ(0); rightLeg.setRotation(-15F); elements.add(rightLeg); Element leftLeg = new Element(4, 12, 4); leftLeg.setStartX(0); leftLeg.setStartY(-24); leftLeg.setStartZ(-2); leftLeg.setOriginX(8); leftLeg.setOriginX(2); leftLeg.setOriginY(-12); leftLeg.setOriginZ(0); leftLeg.setRotation(15F); elements.add(leftLeg); } @Override public void onInit(Camera camera) { camera.setX(0); camera.setY(-5); camera.setZ(-45); camera.setRX(10); camera.setRY(45); camera.setRZ(0); } @Override public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) { DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry("head"); if(entry != null) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); camera.useView(); glScaled(2.0, 2.0, 2.0); for(Element element : elements) { element.drawExtras(manager); element.draw(); } glTranslated(0, 4, 0); glTranslated(-entry.getTranslationX(), entry.getTranslationY(), -entry.getTranslationZ()); glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); glRotatef(180F, 0, 1, 0); glRotatef((float) entry.getRotationX(), 1, 0, 0); glRotatef((float) entry.getRotationY(), 0, 1, 0); glRotatef((float) entry.getRotationZ(), 0, 0, 1); glTranslated(0, -4, 0); glScalef(0.625F, 0.625F, 0.625F); glPushMatrix(); { this.drawGrid(camera, false); this.drawElements(manager); } glPopMatrix(); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/render/StandardRenderer.java ================================================ package com.mrcrayfish.modelcreator.display.render; import com.mrcrayfish.modelcreator.Camera; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.Settings; import com.mrcrayfish.modelcreator.component.Menu; import com.mrcrayfish.modelcreator.display.CanvasRenderer; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.util.FontManager; import org.lwjgl.opengl.GL11; import org.newdawn.slick.Color; import org.newdawn.slick.opengl.TextureImpl; import static org.lwjgl.opengl.GL11.*; /** * Author: MrCrayfish */ public class StandardRenderer extends CanvasRenderer { @Override public void onInit(Camera camera) { camera.setX(0); camera.setY(-5); camera.setZ(-30); camera.setRX(20); camera.setRY(0); camera.setRZ(0); } @Override public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera.useView(); this.drawGrid(camera, Settings.getCardinalPoints()); //TODO make this an option this.drawElements(manager); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); } protected void drawElements(ElementManager manager) { glTranslatef(-8, 0, -8); for(int i = 0; i < manager.getElementCount(); i++) { Element cube = manager.getElement(i); if(cube.isVisible()) { glLoadName(i + 1); cube.draw(); glLoadName(0); cube.drawExtras(manager); } } Element selectedElement = manager.getSelectedElement(); if(selectedElement != null && selectedElement.isVisible()) { selectedElement.drawOutline(); } } protected void drawGrid(Camera camera, boolean renderCardinalPoints) { if(Menu.displayPropertiesDialog != null && !Menu.shouldRenderGrid) { return; } glPushMatrix(); { glColor3f(0.55F, 0.55F, 0.65F); glTranslatef(-8, 0, -8); // Bold outside lines glLineWidth(1.5F); glBegin(GL_LINES); { glVertex3i(0, 0, 0); glVertex3i(0, 0, 16); glVertex3i(16, 0, 0); glVertex3i(16, 0, 16); glVertex3i(0, 0, 16); glVertex3i(16, 0, 16); glVertex3i(0, 0, 0); glVertex3i(16, 0, 0); } glEnd(); // Thin inside lines glLineWidth(1F); glBegin(GL_LINES); { for(int i = 1; i <= 16; i++) { glVertex3i(i, 0, 0); glVertex3i(i, 0, 16); } for(int i = 1; i <= 16; i++) { glVertex3i(0, 0, i); glVertex3i(16, 0, i); } } glEnd(); } glPopMatrix(); glPushMatrix(); { TextureImpl.bindNone(); glTranslatef(-8, 0, -8); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glShadeModel(GL_SMOOTH); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPushMatrix(); glTranslated(0, 0, 16); glScaled(0.015, 0.015, 0.015); glRotated(90, 1, 0, 0); FontManager.BEBAS_NEUE_50.drawString(0, 0, "MrCrayfish's Model Creator", Color.lightGray); glPopMatrix(); if(renderCardinalPoints) { Color color = new Color(0.5F, 0.5F, 0.55F).brighter(0.40F); glPushMatrix(); glTranslated(8, 0, 17); glScaled(0.025, 0.025, 0.025); glRotated(-camera.getRY(), 0, 1, 0); glTranslated(-(FontManager.BEBAS_NEUE_50.getWidth("S") / 2), 0, -(FontManager.BEBAS_NEUE_50.getHeight() / 2)); glRotated(90, 1, 0, 0); FontManager.BEBAS_NEUE_50.drawString(0, 0, "S", color); glPopMatrix(); glPushMatrix(); glTranslated(8, 0, -1); glScaled(0.025, 0.025, 0.025); glRotated(-camera.getRY(), 0, 1, 0); glTranslated(-(FontManager.BEBAS_NEUE_50.getWidth("N") / 2), 0, -(FontManager.BEBAS_NEUE_50.getHeight() / 2)); glRotated(90, 1, 0, 0); FontManager.BEBAS_NEUE_50.drawString(0, 0, "N", color); glPopMatrix(); glPushMatrix(); glTranslated(-1, 0, 8); glScaled(0.025, 0.025, 0.025); glRotated(-camera.getRY(), 0, 1, 0); glTranslated(-(FontManager.BEBAS_NEUE_50.getWidth("W") / 2), 0, -(FontManager.BEBAS_NEUE_50.getHeight() / 2)); glRotated(90, 1, 0, 0); FontManager.BEBAS_NEUE_50.drawString(0, 0, "W", color); glPopMatrix(); glPushMatrix(); glTranslated(17, 0, 8); glScaled(0.025, 0.025, 0.025); glRotated(-camera.getRY(), 0, 1, 0); glTranslated(-(FontManager.BEBAS_NEUE_50.getWidth("E") / 2), 0, -(FontManager.BEBAS_NEUE_50.getHeight() / 2)); glRotated(90, 1, 0, 0); FontManager.BEBAS_NEUE_50.drawString(0, 0, "E", color); glPopMatrix(); } glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); } glPopMatrix(); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/display/render/ThirdPersonPropertyRenderer.java ================================================ package com.mrcrayfish.modelcreator.display.render; import com.mrcrayfish.modelcreator.Camera; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import static org.lwjgl.opengl.GL11.*; /** * Author: MrCrayfish */ public class ThirdPersonPropertyRenderer extends DisplayPropertyRenderer { private boolean leftHanded; public ThirdPersonPropertyRenderer(boolean leftHanded) { this.leftHanded = leftHanded; this.addElements(); } private void addElements() { Element rightArm = new Element(4, 12, 4); rightArm.setStartX(-2); rightArm.setStartY(-12); rightArm.setStartZ(-12); rightArm.setOriginX(0); rightArm.setOriginY(-2); rightArm.setOriginZ(-10); rightArm.setRotation(-90F); //TODO maybe add option to change elements.add(rightArm); Element leftArm = new Element(4, 12, 4); leftArm.setStartX(10); leftArm.setStartY(-12); leftArm.setStartZ(-12); leftArm.setOriginX(12); leftArm.setOriginY(-2); leftArm.setOriginZ(-10); leftArm.setRotation(-15F); //TODO maybe add option to change elements.add(leftArm); Element body = new Element(8, 12, 4); body.setStartX(2); body.setStartY(-12); body.setStartZ(-12); body.setOriginX(0); body.setOriginY(0); body.setOriginZ(0); elements.add(body); Element head = new Element(8, 8, 8); head.setStartX(2); head.setStartY(0); head.setStartZ(-14); head.setOriginX(6); head.setOriginY(0); head.setOriginZ(-10); elements.add(head); Element rightLeg = new Element(4, 12, 4); rightLeg.setStartX(2); rightLeg.setStartY(-24); rightLeg.setStartZ(-12); rightLeg.setOriginX(4); rightLeg.setOriginY(-12); rightLeg.setOriginZ(-10); rightLeg.setRotation(-15F); elements.add(rightLeg); Element leftLeg = new Element(4, 12, 4); leftLeg.setStartX(6); leftLeg.setStartY(-24); leftLeg.setStartZ(-12); leftLeg.setOriginX(8); leftLeg.setOriginY(-12); leftLeg.setOriginZ(-10); leftLeg.setRotation(15F); elements.add(leftLeg); } @Override public void onInit(Camera camera) { camera.setX(leftHanded ? -13 : 13); camera.setY(-5); camera.setZ(-45); camera.setRX(10); camera.setRY(leftHanded ? -90 : 90); camera.setRZ(0); } @Override public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) { DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry(!leftHanded ? "thirdperson_righthand" : "thirdperson_lefthand"); if(entry != null) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); camera.useView(); glPushMatrix(); glPushAttrib(0); { if(leftHanded) { glScaled(-1, 1, 1); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); } glScaled(2.5, 2.5, 2.5); for(Element element : elements) { element.drawExtras(manager); element.draw(); } if(leftHanded) { glCullFace(GL_BACK); glDisable(GL_CULL_FACE); } glTranslated(-entry.getTranslationX(), entry.getTranslationY(), -entry.getTranslationZ()); glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); glRotatef(180F, 0, 1, 0); glRotatef((float) entry.getRotationX(), 1, 0, 0); glRotatef((float) entry.getRotationY(), 0, 1, 0); glRotatef((float) entry.getRotationZ(), 0, 0, 1); glTranslatef(0, -8, 0); if(leftHanded) { glScaled(-1, 1, 1); glRotatef(180F, 0, 1, 0); } glPushMatrix(); { this.drawGrid(camera, false); this.drawElements(manager); } glPopMatrix(); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); } glPopAttrib(); glPopMatrix(); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/element/Element.java ================================================ package com.mrcrayfish.modelcreator.element; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.object.FaceDimension; import com.mrcrayfish.modelcreator.sidebar.UVSidebar; import com.mrcrayfish.modelcreator.texture.TextureEntry; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; import org.lwjgl.util.glu.Sphere; import static org.lwjgl.opengl.GL11.*; public class Element { private String name = "Cube"; private boolean visible = true; // Face Variables private int selectedFace = 0; private Face[] faces = new Face[6]; // Element Variables private double startX = 0.0, startY = 0.0, startZ = 0.0; private double width = 16.0, height = 1.0, depth = 1.0; // Rotation Variables private double originX = 8, originY = 8, originZ = 8; private double rotation; private int axis = 0; private boolean rescale = false; // Extra Variables private boolean shade = true; // Rotation Point Indicator private Sphere sphere = new Sphere(); public Element(double width, double height, double depth) { this.width = width; this.height = height; this.depth = depth; initFaces(); updateEndUVs(); } public Element(Element cuboid) { this.name = cuboid.getName(); this.width = cuboid.getWidth(); this.height = cuboid.getHeight(); this.depth = cuboid.getDepth(); this.startX = cuboid.getStartX(); this.startY = cuboid.getStartY(); this.startZ = cuboid.getStartZ(); this.originX = cuboid.getOriginX(); this.originY = cuboid.getOriginY(); this.originZ = cuboid.getOriginZ(); this.rotation = cuboid.getRotation(); this.axis = cuboid.getRotationAxis(); this.rescale = cuboid.shouldRescale(); this.shade = cuboid.isShaded(); this.selectedFace = cuboid.getSelectedFaceIndex(); initFaces(); for(int i = 0; i < faces.length; i++) { Face oldFace = cuboid.getAllFaces()[i]; faces[i].fitTexture(oldFace.shouldFitTexture()); faces[i].setTexture(oldFace.getTexture()); faces[i].setStartU(oldFace.getStartU()); faces[i].setStartV(oldFace.getStartV()); faces[i].setEndU(oldFace.getEndU()); faces[i].setEndV(oldFace.getEndV()); faces[i].setRotation(oldFace.getRotation()); faces[i].setCullface(oldFace.isCullfaced()); faces[i].setEnabled(oldFace.isEnabled()); faces[i].setAutoUVEnabled(oldFace.isAutoUVEnabled()); faces[i].setTintIndexEnabled(oldFace.isTintIndexEnabled()); faces[i].setTintIndex(oldFace.getTintIndex()); } updateEndUVs(); } private void initFaces() { for(int i = 0; i < faces.length; i++) faces[i] = new Face(this, i); } public void setSelectedFace(int face) { this.selectedFace = face; } public Face getSelectedFace() { return faces[selectedFace]; } public int getSelectedFaceIndex() { return selectedFace; } public Face[] getAllFaces() { return faces; } public FaceDimension getFaceDimension(int side) { switch(side) { case 0: return new FaceDimension(getWidth(), getHeight()); case 1: return new FaceDimension(getDepth(), getHeight()); case 2: return new FaceDimension(getWidth(), getHeight()); case 3: return new FaceDimension(getDepth(), getHeight()); case 4: return new FaceDimension(getWidth(), getDepth()); case 5: return new FaceDimension(getWidth(), getDepth()); } return null; } public void setAllTextures(TextureEntry entry) { for(Face face : faces) { face.setTexture(entry); } } public void draw() { GL11.glPushMatrix(); { GL11.glEnable(GL_BLEND); GL11.glEnable(GL_CULL_FACE); GL11.glTranslated(getOriginX(), getOriginY(), getOriginZ()); rotateAxis(); GL11.glTranslated(-getOriginX(), -getOriginY(), -getOriginZ()); // North if(faces[0].isEnabled()) { faces[0].renderNorth(); } // East if(faces[1].isEnabled()) { faces[1].renderEast(); } // South if(faces[2].isEnabled()) { faces[2].renderSouth(); } // West if(faces[3].isEnabled()) { faces[3].renderWest(); } // Top if(faces[4].isEnabled()) { faces[4].renderUp(); } // Bottom if(faces[5].isEnabled()) { faces[5].renderDown(); } } GL11.glPopMatrix(); } public void drawExtras(ElementManager manager) { if(manager.getSelectedElement() == this) { GL11.glPushMatrix(); { GL11.glTranslated(getOriginX(), getOriginY(), getOriginZ()); GL11.glColor3f(0.25F, 0.25F, 0.25F); sphere.draw(0.2F, 16, 16); rotateAxis(); GL11.glLineWidth(2F); GL11.glBegin(GL_LINES); { GL11.glColor3f(1, 0, 0); GL11.glVertex3i(-4, 0, 0); GL11.glVertex3i(4, 0, 0); GL11.glColor3f(0, 1, 0); GL11.glVertex3i(0, -4, 0); GL11.glVertex3i(0, 4, 0); GL11.glColor3f(0, 0, 1); GL11.glVertex3i(0, 0, -4); GL11.glVertex3i(0, 0, 4); } GL11.glEnd(); } GL11.glPopMatrix(); } } public void drawOutline() { GL11.glDepthMask(false); GL11.glPushMatrix(); { GL11.glTranslated(getOriginX(), getOriginY(), getOriginZ()); rotateAxis(); GL11.glTranslated(-getOriginX(), -getOriginY(), -getOriginZ()); GL11.glTranslated(getStartX(), getStartY(), getStartZ()); float outlineScale = 1.01F; GL11.glScalef(outlineScale, outlineScale, outlineScale); GL11.glTranslated(-((getWidth() * outlineScale) - getWidth()) / 2.0, -((getHeight() * outlineScale) - getHeight()) / 2.0, -((getDepth() * outlineScale) - getDepth()) / 2.0); GL11.glColor3f(1.0F, 1.0F, 1.0F); GL11.glLineWidth(3F); boolean grabbing = ((UVSidebar)ModelCreator.uvSidebar).isGrabbing(); int hoveredFace = ((UVSidebar)ModelCreator.uvSidebar).getHoveredFace(); if(hoveredFace == -1 && ModelCreator.isUVSidebarOpen) { hoveredFace = this.getSelectedFace().getSide(); } /* Bottom */ if(hoveredFace != Face.DOWN) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, 0, 0); GL11.glVertex3d(width, 0, 0); GL11.glVertex3d(width, 0, depth); GL11.glVertex3d(0, 0, depth); } GL11.glEnd(); } /* Top */ if(hoveredFace != Face.UP) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, height, 0); GL11.glVertex3d(width, height, 0); GL11.glVertex3d(width, height, depth); GL11.glVertex3d(0, height, depth); } GL11.glEnd(); } /* North */ if(hoveredFace != Face.NORTH) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, 0, 0); GL11.glVertex3d(0, height, 0); GL11.glVertex3d(width, height, 0); GL11.glVertex3d(width, 0, 0); } GL11.glEnd(); } /* South */ if(hoveredFace != Face.SOUTH) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, 0, depth); GL11.glVertex3d(0, height, depth); GL11.glVertex3d(width, height, depth); GL11.glVertex3d(width, 0, depth); } GL11.glEnd(); } /* West */ if(hoveredFace != Face.WEST) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, 0, 0); GL11.glVertex3d(0, 0, depth); GL11.glVertex3d(0, height, depth); GL11.glVertex3d(0, height, 0); } GL11.glEnd(); } /* EAST */ if(hoveredFace != Face.EAST) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(width, 0, 0); GL11.glVertex3d(width, 0, depth); GL11.glVertex3d(width, height, depth); GL11.glVertex3d(width, height, 0); } GL11.glEnd(); } GL11.glColor3f(1.0F, 0.0F, 0.0F); GL11.glLineWidth(3F); /* Bottom */ if(hoveredFace == Face.DOWN) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, 0, 0); GL11.glVertex3d(width, 0, 0); GL11.glVertex3d(width, 0, depth); GL11.glVertex3d(0, 0, depth); } GL11.glEnd(); } /* Top */ if(hoveredFace == Face.UP) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, height, 0); GL11.glVertex3d(width, height, 0); GL11.glVertex3d(width, height, depth); GL11.glVertex3d(0, height, depth); } GL11.glEnd(); } /* North */ if(hoveredFace == Face.NORTH) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, 0, 0); GL11.glVertex3d(0, height, 0); GL11.glVertex3d(width, height, 0); GL11.glVertex3d(width, 0, 0); } GL11.glEnd(); } /* South */ if(hoveredFace == Face.SOUTH) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, 0, depth); GL11.glVertex3d(0, height, depth); GL11.glVertex3d(width, height, depth); GL11.glVertex3d(width, 0, depth); } GL11.glEnd(); } /* West */ if(hoveredFace == Face.WEST) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(0, 0, 0); GL11.glVertex3d(0, 0, depth); GL11.glVertex3d(0, height, depth); GL11.glVertex3d(0, height, 0); } GL11.glEnd(); } /* East */ if(hoveredFace == Face.EAST) { GL11.glBegin(GL_LINE_LOOP); { GL11.glVertex3d(width, 0, 0); GL11.glVertex3d(width, 0, depth); GL11.glVertex3d(width, height, depth); GL11.glVertex3d(width, height, 0); } GL11.glEnd(); } } GL11.glPopMatrix(); GL11.glDepthMask(true); } public void addStartX(double amt) { this.startX += amt; } public void addStartY(double amt) { this.startY += amt; } public void addStartZ(double amt) { this.startZ += amt; } public double getStartX() { return startX; } public double getStartY() { return startY; } public double getStartZ() { return startZ; } public void setStartX(double amt) { this.startX = amt; } public void setStartY(double amt) { this.startY = amt; } public void setStartZ(double amt) { this.startZ = amt; } public double getWidth() { return width; } public double getHeight() { return height; } public double getDepth() { return depth; } public void addWidth(double amt) { this.width += amt; } public void addHeight(double amt) { this.height += amt; } public void addDepth(double amt) { this.depth += amt; } public void setWidth(double width) { this.width = width; } public void setHeight(double height) { this.height = height; } public void setDepth(double depth) { this.depth = depth; } public double getOriginX() { return originX; } public double getOriginY() { return originY; } public double getOriginZ() { return originZ; } public void addOriginX(double amt) { this.originX += amt; } public void addOriginY(double amt) { this.originY += amt; } public void addOriginZ(double amt) { this.originZ += amt; } public void setOriginX(double amt) { this.originX = amt; } public void setOriginY(double amt) { this.originY = amt; } public void setOriginZ(double amt) { this.originZ = amt; } public double getRotation() { return rotation; } public void setRotation(double rotation) { this.rotation = rotation; } public int getRotationAxis() { return axis; } public void setRotationAxis(int axis) { this.axis = axis; } public void setRescale(boolean rescale) { this.rescale = rescale; } public boolean shouldRescale() { return rescale; } public boolean isShaded() { return shade; } public void setShade(boolean shade) { this.shade = shade; } public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return name + "(w:" + width + ",h:" + height + ",d:" + depth + ")"; } public void updateStartUVs() { for(Face face : faces) { face.updateStartUV(); } } public void updateEndUVs() { for(Face face : faces) { face.updateEndUV(); } } private void rotateAxis() { switch(axis) { case 0: GL11.glRotated(getRotation(), 1, 0, 0); break; case 1: GL11.glRotated(getRotation(), 0, 1, 0); break; case 2: GL11.glRotated(getRotation(), 0, 0, 1); break; } } public static String parseAxis(int axis) { switch(axis) { case 0: return "x"; case 1: return "y"; case 2: return "z"; } return "x"; } public static int parseAxisString(String axis) { switch(axis) { case "x": return 0; case "y": return 1; case "z": return 2; } return 0; } public boolean isVisible() { return visible; } public void setVisible(boolean visible) { this.visible = visible; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/element/ElementCellEntry.java ================================================ package com.mrcrayfish.modelcreator.element; import com.mrcrayfish.modelcreator.Icons; import javax.swing.*; import java.awt.*; /** * Author: MrCrayfish */ public class ElementCellEntry { private Element element; private JPanel panel; private JLabel visibility; private JLabel name; public ElementCellEntry(Element element) { this.element = element; this.createPanel(); } private void createPanel() { panel = new JPanel(); panel.setLayout(new FlowLayout(FlowLayout.LEFT)); visibility = new JLabel(); visibility.setIcon(element.isVisible() ? Icons.light_on : Icons.light_off); panel.add(visibility); name = new JLabel(element.getName()); panel.add(name); } public Element getElement() { return element; } public JPanel getPanel() { return panel; } public JLabel getVisibility() { return visibility; } public JLabel getName() { return name; } public void toggleVisibility() { element.setVisible(!element.isVisible()); visibility.setIcon(element.isVisible() ? Icons.light_on : Icons.light_off); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/element/ElementCellRenderer.java ================================================ package com.mrcrayfish.modelcreator.element; import javax.swing.*; import java.awt.*; /** * Author: MrCrayfish */ public class ElementCellRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { ElementCellEntry entry = (ElementCellEntry) value; JPanel panel = entry.getPanel(); panel.setBackground(isSelected ? new Color(186, 193, 211) : new Color(234, 234, 242)); entry.getName().setText(entry.getElement().getName()); return panel; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/element/ElementManager.java ================================================ package com.mrcrayfish.modelcreator.element; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.texture.TextureEntry; import java.util.List; public interface ElementManager { Element getSelectedElement(); void setSelectedElement(int pos); List getAllElements(); Element getElement(int index); int getElementCount(); void clearElements(); void updateName(); void updateValues(); boolean getAmbientOcc(); void setAmbientOcc(boolean occ); void addElement(Element e); void setParticle(TextureEntry entry); TextureEntry getParticle(); void reset(); default ElementManagerState createState() { return new ElementManagerState(this); } void restoreState(ElementManagerState state); void setDisplayProperties(DisplayProperties properties); DisplayProperties getDisplayProperties(); } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/element/ElementManagerState.java ================================================ package com.mrcrayfish.modelcreator.element; import com.mrcrayfish.modelcreator.texture.TextureEntry; import java.util.List; import java.util.stream.Collectors; /** * Author: MrCrayfish */ public class ElementManagerState { private final List elements; private final int selectedIndex; private final boolean ambientOcclusion; private final TextureEntry particleTexture; public ElementManagerState(ElementManager manager) { this.elements = manager.getAllElements().stream().map(Element::new).collect(Collectors.toList()); this.selectedIndex = manager.getAllElements().indexOf(manager.getSelectedElement()); this.ambientOcclusion = manager.getAmbientOcc(); this.particleTexture = manager.getParticle(); } public List getElements() { return elements; } public int getSelectedIndex() { return selectedIndex; } public boolean isAmbientOcclusion() { return ambientOcclusion; } public TextureEntry getParticleTexture() { return particleTexture; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/element/Face.java ================================================ package com.mrcrayfish.modelcreator.element; import com.mrcrayfish.modelcreator.Settings; import com.mrcrayfish.modelcreator.texture.TextureEntry; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import java.nio.FloatBuffer; import static org.lwjgl.opengl.GL11.*; public class Face { private static int[] colors; static { colors = Settings.getFaceColors(); } public static final int NORTH = 0; public static final int EAST = 1; public static final int SOUTH = 2; public static final int WEST = 3; public static final int UP = 4; public static final int DOWN = 5; private TextureEntry texture = null; private double textureU = 0; private double textureV = 0; private double textureUEnd = 16; private double textureVEnd = 16; private boolean fitTexture = false; private boolean binded = false; private boolean cullface = false; private boolean enabled = true; private boolean autoUV = true; private int rotation; private boolean tintIndexEnabled = false; private int tintIndex = -1; private Element cuboid; private int side; public Face(Element cuboid, int side) { this.cuboid = cuboid; this.side = side; } public Face(Face face) { this.copyProperties(face); } public void copyProperties(Face face) { this.fitTexture = face.fitTexture; this.texture = face.texture; this.textureU = face.textureU; this.textureV = face.textureV; this.textureUEnd = face.textureUEnd; this.textureVEnd = face.textureVEnd; this.rotation = face.rotation; this.cullface = face.cullface; this.enabled = face.enabled; this.autoUV = face.autoUV; this.tintIndex = face.tintIndex; } public void renderNorth() { int passes = texture != null ? texture.getPasses() : 1; for(int i = 0; i < passes; i++) { renderNorth(i, GL11.GL_QUADS); } } private void renderNorth(int pass, int mode) { GL11.glPushMatrix(); { startRender(pass); applyShade(0.45F); GL11.glBegin(mode); { if(binded) { setTexCoord(0); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY(), cuboid.getStartZ()); if(binded) { setTexCoord(1); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY(), cuboid.getStartZ()); if(binded) { setTexCoord(2); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ()); if(binded) { setTexCoord(3); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ()); } GL11.glEnd(); finishRender(); } GL11.glPopMatrix(); } public void renderEast() { int passes = texture != null ? texture.getPasses() : 1; for(int i = 0; i < passes; i++) { renderEast(i, GL11.GL_QUADS); } } private void renderEast(int pass, int mode) { GL11.glPushMatrix(); { startRender(pass); applyShade(0.3F); GL11.glBegin(mode); { if(binded) { setTexCoord(0); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY(), cuboid.getStartZ() + cuboid.getDepth()); if(binded) { setTexCoord(1); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY(), cuboid.getStartZ()); if(binded) { setTexCoord(2); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ()); if(binded) { setTexCoord(3); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ() + cuboid.getDepth()); } GL11.glEnd(); finishRender(); } GL11.glPopMatrix(); } public void renderSouth() { int passes = texture != null ? texture.getPasses() : 1; for(int i = 0; i < passes; i++) { renderSouth(i, GL11.GL_QUADS); } } private void renderSouth(int pass, int mode) { GL11.glPushMatrix(); { startRender(pass); applyShade(0.15F); GL11.glBegin(mode); { if(binded) { setTexCoord(0); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY(), cuboid.getStartZ() + cuboid.getDepth()); if(binded) { setTexCoord(1); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY(), cuboid.getStartZ() + cuboid.getDepth()); if(binded) { setTexCoord(2); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ() + cuboid.getDepth()); if(binded) { setTexCoord(3); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ() + cuboid.getDepth()); } GL11.glEnd(); finishRender(); } GL11.glPopMatrix(); } public void renderWest() { int passes = texture != null ? texture.getPasses() : 1; for(int i = 0; i < passes; i++) { renderWest(i, GL11.GL_QUADS); } } private void renderWest(int pass, int mode) { GL11.glPushMatrix(); { startRender(pass); applyShade(0.3F); GL11.glBegin(mode); { if(binded) { setTexCoord(0); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY(), cuboid.getStartZ()); if(binded) { setTexCoord(1); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY(), cuboid.getStartZ() + cuboid.getDepth()); if(binded) { setTexCoord(2); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ() + cuboid.getDepth()); if(binded) { setTexCoord(3); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ()); } GL11.glEnd(); finishRender(); } GL11.glPopMatrix(); } public void renderUp() { int passes = texture != null ? texture.getPasses() : 1; for(int i = 0; i < passes; i++) { renderUp(i, GL11.GL_QUADS); } } private void renderUp(int pass, int mode) { GL11.glPushMatrix(); { startRender(pass); GL11.glBegin(mode); { if(binded) { setTexCoord(0); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ() + cuboid.getDepth()); if(binded) { setTexCoord(1); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ() + cuboid.getDepth()); if(binded) { setTexCoord(2); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ()); if(binded) { setTexCoord(3); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY() + cuboid.getHeight(), cuboid.getStartZ()); } GL11.glEnd(); finishRender(); } GL11.glPopMatrix(); } public void renderDown() { int passes = texture != null ? texture.getPasses() : 1; for(int i = 0; i < passes; i++) { renderDown(i, GL11.GL_QUADS); } } private void renderDown(int pass, int mode) { GL11.glPushMatrix(); { startRender(pass); applyShade(0.55F); GL11.glBegin(mode); { if(binded) { setTexCoord(0); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY(), cuboid.getStartZ()); if(binded) { setTexCoord(1); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY(), cuboid.getStartZ()); if(binded) { setTexCoord(2); } GL11.glVertex3d(cuboid.getStartX() + cuboid.getWidth(), cuboid.getStartY(), cuboid.getStartZ() + cuboid.getDepth()); if(binded) { setTexCoord(3); } GL11.glVertex3d(cuboid.getStartX(), cuboid.getStartY(), cuboid.getStartZ() + cuboid.getDepth()); } GL11.glEnd(); finishRender(); } GL11.glPopMatrix(); } private void setTexCoord(int corner) { setTexCoord(corner, false); } private void setTexCoord(int corner, boolean forceFit) { int coord = corner + rotation; if(coord == 0 | coord == 4) { GL11.glTexCoord2d(fitTexture || forceFit ? 0 : (textureU / 16), fitTexture || forceFit ? 1 : (textureVEnd / 16)); } if(coord == 1 | coord == 5) { GL11.glTexCoord2d(fitTexture || forceFit ? 1 : (textureUEnd / 16), fitTexture || forceFit ? 1 : (textureVEnd / 16)); } if(coord == 2 | coord == 6) { GL11.glTexCoord2d(fitTexture || forceFit ? 1 : (textureUEnd / 16), fitTexture || forceFit ? 0 : (textureV / 16)); } if(coord == 3) { GL11.glTexCoord2d(fitTexture || forceFit ? 0 : (textureU / 16), fitTexture || forceFit ? 0 : (textureV / 16)); } } private void startRender(int pass) { int color = Face.colors[side]; float b = (float) (color & 0xFF) / 0xFF; float g = (float) ((color >>> 8) & 0xFF) / 0xFF; float r = (float) ((color >>> 16) & 0xFF) / 0xFF; GL11.glColor3f(r, g, b); GL11.glEnable(GL_TEXTURE_2D); bindTexture(pass); } private void finishRender() { GL11.glDisable(GL_TEXTURE_2D); } private void applyShade(float reduction) { if(cuboid.isShaded()) { FloatBuffer buffer = BufferUtils.createFloatBuffer(16); GL11.glGetFloat(GL11.GL_CURRENT_COLOR, buffer); GL11.glColor3f(buffer.get() - reduction, buffer.get() - reduction, buffer.get() - reduction); } } public void setTexture(TextureEntry texture) { this.texture = texture; } public void bindTexture(int pass) { GL11.glDisable(GL_TEXTURE_2D); if(texture != null) { if(pass == 0) { GL11.glEnable(GL_BLEND); GL11.glEnable(GL_TEXTURE_2D); GL11.glColor3f(1.0F, 1.0F, 1.0F); texture.bindTexture(); } else if(pass == 1) { if(texture.isAnimated()) { GL11.glEnable(GL_TEXTURE_2D); GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL11.glDepthFunc(GL11.GL_EQUAL); texture.bindNextTexture(); GL11.glColor4d(1.0D, 1.0D, 1.0D, texture.getAnimation().getFrameInterpolation()); } } binded = true; } } public void moveTextureU(double amt) { this.textureU += amt; this.textureUEnd += amt; } public void moveTextureV(double amt) { this.textureV += amt; this.textureVEnd += amt; } private double getMinX() { if(side == EAST) { return cuboid.getStartX() + cuboid.getWidth(); } return cuboid.getStartX(); } private double getMinY() { if(side == UP) { return cuboid.getStartY() + cuboid.getHeight(); } return cuboid.getStartY(); } private double getMinZ() { if(side == SOUTH) { return cuboid.getStartZ() + cuboid.getDepth(); } return cuboid.getStartZ(); } private double getMaxX() { if(side == WEST) { return cuboid.getStartX(); } return cuboid.getStartX() + cuboid.getWidth(); } private double getMaxY() { if(side == DOWN) { return cuboid.getStartY(); } return cuboid.getStartY() + cuboid.getHeight(); } private double getMaxZ() { if(side == NORTH) { return cuboid.getStartZ(); } return cuboid.getStartZ() + cuboid.getDepth(); } public void addTextureX(double amt) { this.textureU += amt; } public void addTextureY(double amt) { this.textureV += amt; } public void addTextureXEnd(double amt) { this.textureUEnd += amt; } public void addTextureYEnd(double amt) { this.textureVEnd += amt; } public double getStartU() { return textureU; } public double getStartV() { return textureV; } public double getEndU() { return textureUEnd; } public double getEndV() { return textureVEnd; } public void setStartU(double u) { textureU = u; } public void setStartV(double v) { textureV = v; } public void setEndU(double ue) { textureUEnd = ue; } public void setEndV(double ve) { textureVEnd = ve; } public TextureEntry getTexture() { return texture; } public void fitTexture(boolean fitTexture) { this.fitTexture = fitTexture; } public boolean shouldFitTexture() { return fitTexture; } public int getSide() { return side; } public boolean isCullfaced() { return cullface; } public void setCullface(boolean cullface) { this.cullface = cullface; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public boolean isAutoUVEnabled() { return autoUV; } public void setAutoUVEnabled(boolean enabled) { this.autoUV = enabled; } public boolean isBinded() { return binded; } public void updateStartUV() { if(autoUV) { textureU = Math.max(0.0, textureUEnd - cuboid.getFaceDimension(side).getWidth()); textureV = Math.max(0.0, textureVEnd - cuboid.getFaceDimension(side).getHeight()); } } public void updateEndUV() { if(autoUV) { textureUEnd = Math.min(16.0, textureU + cuboid.getFaceDimension(side).getWidth()); textureVEnd = Math.min(16.0, textureV + cuboid.getFaceDimension(side).getHeight()); } } public static String getFaceName(int face) { switch(face) { case 0: return "north"; case 1: return "east"; case 2: return "south"; case 3: return "west"; case 4: return "up"; case 5: return "down"; } return null; } public static int getFaceSide(String name) { switch(name) { case "north": return 0; case "east": return 1; case "south": return 2; case "west": return 3; case "up": return 4; case "down": return 5; } return -1; } public static int getFaceColour(int side) { if(side >= 0 && side < colors.length) { return colors[side]; } return 0; } public static int[] getFaceColors() { return colors; } public static void setFaceColors(int[] colors) { if(colors.length == 6) { Face.colors = colors; } } public static void setFaceColor(int side, int color) { Face.colors[side] = color; } public int getRotation() { return rotation; } public void setRotation(int rotation) { this.rotation = rotation; } public void setTintIndexEnabled(boolean enabled) { this.tintIndexEnabled = enabled; } public boolean isTintIndexEnabled() { return tintIndexEnabled; } public int getTintIndex() { return tintIndex; } public void setTintIndex(int tintIndex) { this.tintIndex = tintIndex; } public boolean isVisible(ElementManager manager) { if(cuboid.getRotation() != 0.0) //TODO make it an option { return true; } for(Element element : manager.getAllElements()) { if(element == cuboid || element.getRotation() != 0.0) { continue; } if(this.getMinX() >= element.getStartX() && this.getMinX() <= element.getStartX() + element.getWidth()) { if(this.getMinY() >= element.getStartY() && this.getMinY() <= element.getStartY() + element.getHeight()) { if(this.getMinZ() >= element.getStartZ() && this.getMinZ() <= element.getStartZ() + element.getDepth()) { if(this.getMaxX() >= element.getStartX() && this.getMaxX() <= element.getStartX() + element.getWidth()) { if(this.getMaxY() >= element.getStartY() && this.getMaxY() <= element.getStartY() + element.getHeight()) { if(this.getMaxZ() >= element.getStartZ() && this.getMaxZ() <= element.getStartZ() + element.getDepth()) { return false; } } } } } } } return true; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/object/FaceDimension.java ================================================ package com.mrcrayfish.modelcreator.object; public class FaceDimension { private double width, height; public FaceDimension(double width, double height) { this.width = width; this.height = height; } public double getWidth() { return width; } public double getHeight() { return height; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/CuboidTabbedPane.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.element.ElementManager; import javax.swing.*; import java.awt.*; public class CuboidTabbedPane extends JTabbedPane { private ElementManager manager; public CuboidTabbedPane(ElementManager manager) { this.manager = manager; } public void updateValues() { for(int i = 0; i < getTabCount(); i++) { Component component = getComponentAt(i); if(component != null) { if(component instanceof IElementUpdater) { IElementUpdater updater = (IElementUpdater) component; updater.updateValues(manager.getSelectedElement()); } } } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/DisplayEntryPanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.Exporter; import com.mrcrayfish.modelcreator.Icons; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.util.Parser; import javax.swing.*; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; /** * Author: MrCrayfish */ public class DisplayEntryPanel extends JPanel { private DisplayProperties.Entry entry; //TODO remove instance private JCheckBox checkBoxEnabled; private JSlider sliderRotationX; private JSlider sliderRotationY; private JSlider sliderRotationZ; private JTextField textFieldTranslationX; private JTextField textFieldTranslationY; private JTextField textFieldTranslationZ; private JTextField textFieldScaleX; private JTextField textFieldScaleY; private JTextField textFieldScaleZ; public DisplayEntryPanel(DisplayProperties.Entry entry) { this.entry = entry; this.setPreferredSize(new Dimension(200, 330)); this.setLayout(new SpringLayout()); this.initComponents(); } public DisplayProperties.Entry getEntry() { return entry; } private void initComponents() { JPanel optionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); this.add(optionsPanel); JPanel sliderPanel = new JPanel(new GridLayout(3, 1, 0, 5)); sliderPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(new Color(221, 221, 228), 0), "Rotation")); sliderPanel.setPreferredSize(new Dimension(0, 180)); this.add(sliderPanel); sliderRotationX = createRotationSlider("X Axis", sliderPanel); sliderRotationX.setValue((int) entry.getRotationX()); sliderRotationX.addChangeListener(e -> entry.setRotationX(sliderRotationX.getValue())); sliderRotationY = createRotationSlider("Y Axis", sliderPanel); sliderRotationY.setValue((int) entry.getRotationY()); sliderRotationY.addChangeListener(e -> entry.setRotationY(sliderRotationY.getValue())); sliderRotationZ = createRotationSlider("Z Axis", sliderPanel); sliderRotationZ.setValue((int) entry.getRotationZ()); sliderRotationZ.addChangeListener(e -> entry.setRotationZ(sliderRotationZ.getValue())); JPanel otherPanel = new JPanel(new GridLayout(1, 2)); otherPanel.setPreferredSize(new Dimension(0, 120)); this.add(otherPanel, BorderLayout.SOUTH); JPanel translatePanel = new JPanel(new GridLayout(3, 3, 5, 5)); translatePanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(new Color(221, 221, 228), 0), "Translation")); Font defaultFont = new Font("SansSerif", Font.BOLD, 16); textFieldTranslationX = new JTextField(); textFieldTranslationX.setText(Exporter.FORMAT.format(entry.getTranslationX())); textFieldTranslationX.setFont(defaultFont); textFieldTranslationX.setHorizontalAlignment(SwingConstants.CENTER); textFieldTranslationX.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { entry.setTranslationX(Parser.parseDouble(textFieldTranslationX.getText(), entry.getTranslationX())); } } }); textFieldTranslationY = new JTextField(); textFieldTranslationY.setText(Exporter.FORMAT.format(entry.getTranslationY())); textFieldTranslationY.setFont(defaultFont); textFieldTranslationY.setHorizontalAlignment(SwingConstants.CENTER); textFieldTranslationY.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { entry.setTranslationY(Parser.parseDouble(textFieldTranslationY.getText(), entry.getTranslationY())); } } }); textFieldTranslationZ = new JTextField(); textFieldTranslationZ.setText(Exporter.FORMAT.format(entry.getTranslationZ())); textFieldTranslationZ.setFont(defaultFont); textFieldTranslationZ.setHorizontalAlignment(SwingConstants.CENTER); textFieldTranslationZ.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { entry.setTranslationZ(Parser.parseDouble(textFieldTranslationZ.getText(), entry.getTranslationZ())); } } }); JButton btnTransX = new JButton(Icons.arrow_up); btnTransX.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setTranslationX(entry.getTranslationX() + 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setTranslationX(entry.getTranslationX() + 0.01); } else { entry.setTranslationX(entry.getTranslationX() + 1.0); } textFieldTranslationX.setText(Exporter.FORMAT.format(entry.getTranslationX())); }); translatePanel.add(btnTransX); JButton btnTransY = new JButton(Icons.arrow_up); btnTransY.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setTranslationY(entry.getTranslationY() + 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setTranslationY(entry.getTranslationY() + 0.01); } else { entry.setTranslationY(entry.getTranslationY() + 1.0); } textFieldTranslationY.setText(Exporter.FORMAT.format(entry.getTranslationY())); }); translatePanel.add(btnTransY); JButton btnTransZ = new JButton(Icons.arrow_up); btnTransZ.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setTranslationZ(entry.getTranslationZ() + 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setTranslationZ(entry.getTranslationZ() + 0.01); } else { entry.setTranslationZ(entry.getTranslationZ() + 1.0); } textFieldTranslationZ.setText(Exporter.FORMAT.format(entry.getTranslationZ())); }); translatePanel.add(btnTransZ); translatePanel.add(textFieldTranslationX); translatePanel.add(textFieldTranslationY); translatePanel.add(textFieldTranslationZ); JButton btnTransXNeg = new JButton(Icons.arrow_down); btnTransXNeg.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setTranslationX(entry.getTranslationX() - 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setTranslationX(entry.getTranslationX() - 0.01); } else { entry.setTranslationX(entry.getTranslationX() - 1.0); } textFieldTranslationX.setText(Exporter.FORMAT.format(entry.getTranslationX())); }); translatePanel.add(btnTransXNeg); JButton btnTransYNeg = new JButton(Icons.arrow_down); btnTransYNeg.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setTranslationY(entry.getTranslationY() - 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setTranslationY(entry.getTranslationY() - 0.01); } else { entry.setTranslationY(entry.getTranslationY() - 1.0); } textFieldTranslationY.setText(Exporter.FORMAT.format(entry.getTranslationY())); }); translatePanel.add(btnTransYNeg); JButton btnTransZNeg = new JButton(Icons.arrow_down); btnTransZNeg.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setTranslationZ(entry.getTranslationZ() - 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setTranslationZ(entry.getTranslationZ() - 0.01); } else { entry.setTranslationZ(entry.getTranslationZ() - 1.0); } textFieldTranslationZ.setText(Exporter.FORMAT.format(entry.getTranslationZ())); }); translatePanel.add(btnTransZNeg); otherPanel.add(translatePanel); JPanel scalePanel = new JPanel(new GridLayout(3, 3, 5, 5)); scalePanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(new Color(221, 221, 228), 0), "Scale")); textFieldScaleX = new JTextField(); textFieldScaleX.setText(Exporter.FORMAT.format(entry.getScaleX())); textFieldScaleX.setFont(defaultFont); textFieldScaleX.setHorizontalAlignment(SwingConstants.CENTER); textFieldScaleX.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { entry.setScaleX(Parser.parseDouble(textFieldScaleX.getText(), entry.getScaleX())); } } }); textFieldScaleY = new JTextField(); textFieldScaleY.setText(Exporter.FORMAT.format(entry.getScaleY())); textFieldScaleY.setFont(defaultFont); textFieldScaleY.setHorizontalAlignment(SwingConstants.CENTER); textFieldScaleY.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { entry.setScaleY(Parser.parseDouble(textFieldScaleY.getText(), entry.getScaleY())); } } }); textFieldScaleZ = new JTextField(); textFieldScaleZ.setText(Exporter.FORMAT.format(entry.getScaleZ())); textFieldScaleZ.setFont(defaultFont); textFieldScaleZ.setHorizontalAlignment(SwingConstants.CENTER); textFieldScaleZ.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { entry.setScaleZ(Parser.parseDouble(textFieldScaleZ.getText(), entry.getScaleZ())); } } }); JButton btnScaleX = new JButton(Icons.arrow_up); btnScaleX.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setScaleX(entry.getScaleX() + 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setScaleX(entry.getScaleX() + 0.01); } else { entry.setScaleX(entry.getScaleX() + 1.0); } textFieldScaleX.setText(Exporter.FORMAT.format(entry.getScaleX())); }); scalePanel.add(btnScaleX); JButton btnScaleY = new JButton(Icons.arrow_up); btnScaleY.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setScaleY(entry.getScaleY() + 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setScaleY(entry.getScaleY() + 0.01); } else { entry.setScaleY(entry.getScaleY() + 1.0); } textFieldScaleY.setText(Exporter.FORMAT.format(entry.getScaleY())); }); scalePanel.add(btnScaleY); JButton btnScaleZ = new JButton(Icons.arrow_up); btnScaleZ.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setScaleZ(entry.getScaleZ() + 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setScaleZ(entry.getScaleZ() + 0.01); } else { entry.setScaleZ(entry.getScaleZ() + 1.0); } textFieldScaleZ.setText(Exporter.FORMAT.format(entry.getScaleZ())); }); scalePanel.add(btnScaleZ); scalePanel.add(textFieldScaleX); scalePanel.add(textFieldScaleY); scalePanel.add(textFieldScaleZ); JButton btnScaleXNeg = new JButton(Icons.arrow_down); btnScaleXNeg.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setScaleX(entry.getScaleX() - 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setScaleX(entry.getScaleX() - 0.01); } else { entry.setScaleX(entry.getScaleX() - 1.0); } textFieldScaleX.setText(Exporter.FORMAT.format(entry.getScaleX())); }); scalePanel.add(btnScaleXNeg); JButton btnScaleYNeg = new JButton(Icons.arrow_down); btnScaleYNeg.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setScaleY(entry.getScaleY() - 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setScaleY(entry.getScaleY() - 0.01); } else { entry.setScaleY(entry.getScaleY() - 1.0); } textFieldScaleY.setText(Exporter.FORMAT.format(entry.getScaleY())); }); scalePanel.add(btnScaleYNeg); JButton btnScaleZNeg = new JButton(Icons.arrow_down); btnScaleZNeg.addActionListener(e -> { if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) == 0) { entry.setScaleZ(entry.getScaleZ() - 0.1); } else if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && (e.getModifiers() & InputEvent.CTRL_MASK) > 0) { entry.setScaleZ(entry.getScaleZ() - 0.01); } else { entry.setScaleZ(entry.getScaleZ() - 1.0); } textFieldScaleZ.setText(Exporter.FORMAT.format(entry.getScaleZ())); }); scalePanel.add(btnScaleZNeg); otherPanel.add(scalePanel); checkBoxEnabled = new JCheckBox("Enabled"); checkBoxEnabled.setSelected(entry.isEnabled()); checkBoxEnabled.setIcon(Icons.light_off); checkBoxEnabled.setRolloverIcon(Icons.light_off); checkBoxEnabled.setSelectedIcon(Icons.light_on); checkBoxEnabled.setRolloverSelectedIcon(Icons.light_on); checkBoxEnabled.addActionListener(e -> { boolean enabled = checkBoxEnabled.isSelected(); entry.setEnabled(enabled); sliderRotationX.setEnabled(enabled); sliderRotationY.setEnabled(enabled); sliderRotationZ.setEnabled(enabled); btnTransX.setEnabled(enabled); btnTransY.setEnabled(enabled); btnTransZ.setEnabled(enabled); textFieldTranslationX.setEnabled(enabled); textFieldTranslationY.setEnabled(enabled); textFieldTranslationZ.setEnabled(enabled); btnTransXNeg.setEnabled(enabled); btnTransYNeg.setEnabled(enabled); btnTransZNeg.setEnabled(enabled); btnScaleX.setEnabled(enabled); btnScaleY.setEnabled(enabled); btnScaleZ.setEnabled(enabled); textFieldScaleX.setEnabled(enabled); textFieldScaleY.setEnabled(enabled); textFieldScaleZ.setEnabled(enabled); btnScaleXNeg.setEnabled(enabled); btnScaleYNeg.setEnabled(enabled); btnScaleZNeg.setEnabled(enabled); }); optionsPanel.add(checkBoxEnabled); SpringLayout springLayout = (SpringLayout) this.getLayout(); springLayout.putConstraint(SpringLayout.NORTH, optionsPanel, 5, SpringLayout.NORTH, this); springLayout.putConstraint(SpringLayout.WEST, optionsPanel, 10, SpringLayout.WEST, this); springLayout.putConstraint(SpringLayout.EAST, optionsPanel, 10, SpringLayout.EAST, this); springLayout.putConstraint(SpringLayout.WEST, sliderPanel, 10, SpringLayout.WEST, this); springLayout.putConstraint(SpringLayout.NORTH, sliderPanel, 5, SpringLayout.SOUTH, optionsPanel); springLayout.putConstraint(SpringLayout.EAST, sliderPanel, -10, SpringLayout.EAST, this); springLayout.putConstraint(SpringLayout.WEST, otherPanel, 10, SpringLayout.WEST, this); springLayout.putConstraint(SpringLayout.NORTH, otherPanel, 10, SpringLayout.SOUTH, sliderPanel); springLayout.putConstraint(SpringLayout.EAST, otherPanel, -10, SpringLayout.EAST, this); } public void updateValues(DisplayProperties.Entry entry) { this.entry = entry; checkBoxEnabled.setSelected(entry.isEnabled()); sliderRotationX.setValue((int) entry.getRotationX()); sliderRotationY.setValue((int) entry.getRotationY()); sliderRotationZ.setValue((int) entry.getRotationZ()); textFieldTranslationX.setText(Exporter.FORMAT.format(entry.getTranslationX())); textFieldTranslationY.setText(Exporter.FORMAT.format(entry.getTranslationY())); textFieldTranslationZ.setText(Exporter.FORMAT.format(entry.getTranslationZ())); textFieldScaleX.setText(Exporter.FORMAT.format(entry.getScaleX())); textFieldScaleY.setText(Exporter.FORMAT.format(entry.getScaleY())); textFieldScaleZ.setText(Exporter.FORMAT.format(entry.getScaleZ())); } private JSlider createRotationSlider(String labelText, JComponent parent) { SpringLayout layout = new SpringLayout(); JPanel panel = new JPanel(layout); JLabel labelKey = new JLabel(labelText); JTextField textFieldValue = new JTextField("0"); JSlider sliderValue = new JSlider(JSlider.HORIZONTAL, 0, 360, 0); labelKey.setPreferredSize(new Dimension(100, 24)); panel.add(labelKey); textFieldValue.setPreferredSize(new Dimension(50, 24)); textFieldValue.setHorizontalAlignment(SwingConstants.CENTER); textFieldValue.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { int value = Parser.parseInt(textFieldValue.getText(), sliderValue.getValue()); value = Math.max(0, Math.min(360, value)); textFieldValue.setText(String.valueOf(value)); sliderValue.setValue(value); } } }); panel.add(textFieldValue); sliderValue.setFocusable(false); sliderValue.addChangeListener(e -> { textFieldValue.setText(String.valueOf(sliderValue.getValue())); }); sliderValue.addPropertyChangeListener("enabled", evt -> { textFieldValue.setEnabled(sliderValue.isEnabled()); }); panel.add(sliderValue); layout.putConstraint(SpringLayout.WEST, labelKey, 5, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, labelKey, 0, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.EAST, textFieldValue, -5, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.NORTH, textFieldValue, 0, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.WEST, sliderValue, 0, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, sliderValue, 5, SpringLayout.SOUTH, textFieldValue); layout.putConstraint(SpringLayout.EAST, sliderValue, 0, SpringLayout.EAST, panel); parent.add(panel); return sliderValue; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/ElementExtraPanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.StateManager; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.util.ComponentUtil; import javax.swing.*; import java.awt.*; public class ElementExtraPanel extends JPanel implements IElementUpdater { private ElementManager manager; private JRadioButton btnShade; public ElementExtraPanel(ElementManager manager) { this.manager = manager; this.setBackground(ModelCreator.BACKGROUND); this.setLayout(new GridLayout(1, 2)); this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Extras")); this.setMaximumSize(new Dimension(186, 50)); this.initComponents(); this.addComponents(); } private void initComponents() { btnShade = ComponentUtil.createRadioButton("Shade", "Determines if shadows should be rendered
Default: On"); btnShade.setBackground(ModelCreator.BACKGROUND); btnShade.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setShade(btnShade.isSelected()); StateManager.pushState(manager); } }); } private void addComponents() { add(btnShade); } @Override public void updateValues(Element cube) { if(cube != null) { btnShade.setEnabled(true); btnShade.setSelected(cube.isShaded()); } else { btnShade.setEnabled(false); btnShade.setSelected(false); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/FaceExtrasPanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.Settings; import com.mrcrayfish.modelcreator.StateManager; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.util.ComponentUtil; import javax.swing.*; import java.awt.*; public class FaceExtrasPanel extends JPanel implements IElementUpdater { private ElementManager manager; private JPanel horizontalBox; private JRadioButton boxCullFace; private JRadioButton boxFill; private JRadioButton boxEnabled; private JRadioButton boxAutoUV; private JCheckBox checkBoxTintIndex; private JSpinner tintIndexSpinner; public FaceExtrasPanel(ElementManager manager) { this.manager = manager; this.setBackground(ModelCreator.BACKGROUND); this.setLayout(new BorderLayout(0, 5)); this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Extras")); this.setMaximumSize(new Dimension(186, 120)); this.initComponents(); this.addComponents(); } private void initComponents() { horizontalBox = new JPanel(new GridLayout(3, 2)); boxCullFace = ComponentUtil.createRadioButton("Cullface", "Should render face is another block is adjacent
Default: Off"); boxCullFace.setBackground(ModelCreator.BACKGROUND); boxCullFace.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.getSelectedFace().setCullface(boxCullFace.isSelected()); StateManager.pushState(manager); } }); boxFill = ComponentUtil.createRadioButton("Fill", "Makes the texture fill the face
Default: Off"); boxFill.setBackground(ModelCreator.BACKGROUND); boxFill.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.getSelectedFace().fitTexture(boxFill.isSelected()); StateManager.pushState(manager); } }); boxEnabled = ComponentUtil.createRadioButton("Enable", "Determines if face should be rendered
Default: On"); boxEnabled.setBackground(ModelCreator.BACKGROUND); boxEnabled.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.getSelectedFace().setEnabled(boxEnabled.isSelected()); StateManager.pushState(manager); } }); boxAutoUV = ComponentUtil.createRadioButton("Auto UV", "Determines if UV end coordinates should be set based on element size
Default: On"); boxAutoUV.setBackground(ModelCreator.BACKGROUND); boxAutoUV.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.getSelectedFace().setAutoUVEnabled(boxAutoUV.isSelected()); selectedElement.getSelectedFace().updateEndUV(); manager.updateValues(); StateManager.pushState(manager); } }); horizontalBox.add(boxCullFace); horizontalBox.add(boxFill); horizontalBox.add(boxEnabled); horizontalBox.add(boxAutoUV); checkBoxTintIndex = ComponentUtil.createCheckBox("Tint Index", "The tint index to apply to this face. Used in gam", false); checkBoxTintIndex.setBackground(ModelCreator.BACKGROUND); checkBoxTintIndex.setEnabled(false); horizontalBox.add(checkBoxTintIndex); SpinnerNumberModel numberModel = new SpinnerNumberModel(); numberModel.setMinimum(0); tintIndexSpinner = new JSpinner(numberModel); tintIndexSpinner.setBackground(ModelCreator.BACKGROUND); tintIndexSpinner.setEnabled(false); tintIndexSpinner.setPreferredSize(new Dimension(75, 24)); tintIndexSpinner.setValue(0); tintIndexSpinner.addChangeListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.getSelectedFace().setTintIndex((int) tintIndexSpinner.getValue()); StateManager.pushState(manager); } }); horizontalBox.add(tintIndexSpinner); checkBoxTintIndex.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { boolean selected = checkBoxTintIndex.isSelected(); selectedElement.getSelectedFace().setTintIndexEnabled(selected); tintIndexSpinner.setEnabled(selected); StateManager.pushState(manager); } }); } private void addComponents() { add(horizontalBox, BorderLayout.NORTH); } @Override public void updateValues(Element cube) { if(cube != null) { boxCullFace.setEnabled(true); boxCullFace.setSelected(cube.getSelectedFace().isCullfaced()); boxFill.setEnabled(true); boxFill.setSelected(cube.getSelectedFace().shouldFitTexture()); boxEnabled.setEnabled(true); boxEnabled.setSelected(cube.getSelectedFace().isEnabled()); boxAutoUV.setEnabled(true); boxAutoUV.setSelected(cube.getSelectedFace().isAutoUVEnabled()); checkBoxTintIndex.setEnabled(true); checkBoxTintIndex.setSelected(cube.getSelectedFace().isTintIndexEnabled()); if(cube.getSelectedFace().isTintIndexEnabled()) { tintIndexSpinner.setEnabled(true); tintIndexSpinner.setValue(cube.getSelectedFace().getTintIndex()); } else { tintIndexSpinner.setEnabled(false); } } else { boxCullFace.setEnabled(false); boxCullFace.setSelected(false); boxFill.setEnabled(false); boxFill.setSelected(false); boxEnabled.setEnabled(false); boxEnabled.setSelected(false); boxAutoUV.setEnabled(false); boxAutoUV.setSelected(false); checkBoxTintIndex.setEnabled(false); checkBoxTintIndex.setSelected(false); tintIndexSpinner.setEnabled(false); tintIndexSpinner.setValue(0); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/GlobalPanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.Icons; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.StateManager; import com.mrcrayfish.modelcreator.component.TextureManager; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.texture.TextureEntry; import com.mrcrayfish.modelcreator.util.ComponentUtil; import javax.swing.*; import java.awt.*; public class GlobalPanel extends JPanel implements IElementUpdater { private ElementManager manager; private JRadioButton ambientOcc; private JButton btnParticle; public GlobalPanel(ElementManager manager) { this.manager = manager; this.setBackground(ModelCreator.BACKGROUND); this.setLayout(new GridLayout(2, 1, 0, 5)); this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Global Properties")); this.setMaximumSize(new Dimension(186, 80)); this.initComponents(); this.addComponents(); } private void initComponents() { ambientOcc = ComponentUtil.createRadioButton("Ambient Occlusion", "Determine the light for each element"); ambientOcc.setBackground(ModelCreator.BACKGROUND); ambientOcc.setSelected(true); ambientOcc.addActionListener(a -> { manager.setAmbientOcc(ambientOcc.isSelected()); StateManager.pushState(manager); }); btnParticle = new JButton("Particle"); btnParticle.setIcon(Icons.texture); btnParticle.addActionListener(a -> { TextureEntry entry = TextureManager.display(((SidebarPanel) manager).getCreator(), manager, Dialog.ModalityType.APPLICATION_MODAL); if(entry != null) { manager.setParticle(entry); btnParticle.setText("#" + entry.getKey()); StateManager.pushState(manager); } }); } private void addComponents() { add(ambientOcc); add(btnParticle); } @Override public void updateValues(Element cube) { ambientOcc.setSelected(manager.getAmbientOcc()); if(manager.getParticle() == null) { btnParticle.setText("Particle"); } else { btnParticle.setText("#" + manager.getParticle().getKey()); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/IElementUpdater.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.element.Element; public interface IElementUpdater { void updateValues(Element cube); } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/OriginPanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.*; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.util.Parser; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class OriginPanel extends JPanel implements IElementUpdater { private ElementManager manager; private JButton btnPlusX; private JButton btnPlusY; private JButton btnPlusZ; private JTextField xOriginField; private JTextField yOriginField; private JTextField zOriginField; private JButton btnNegX; private JButton btnNegY; private JButton btnNegZ; public OriginPanel(ElementManager manager) { this.manager = manager; this.setBackground(ModelCreator.BACKGROUND); this.setLayout(new GridLayout(3, 3, 4, 4)); this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Origin")); this.setMaximumSize(new Dimension(186, 124)); this.initComponents(); this.initProperties(); this.addComponents(); } private void initComponents() { btnPlusX = new JButton(Icons.arrow_up); btnPlusY = new JButton(Icons.arrow_up); btnPlusZ = new JButton(Icons.arrow_up); xOriginField = new JTextField(); yOriginField = new JTextField(); zOriginField = new JTextField(); btnNegX = new JButton(Icons.arrow_down); btnNegY = new JButton(Icons.arrow_down); btnNegZ = new JButton(Icons.arrow_down); } private void initProperties() { Font defaultFont = new Font("SansSerif", Font.BOLD, 20); SidebarPanel.initIncrementableField(xOriginField, defaultFont); xOriginField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setOriginX((Parser.parseDouble(xOriginField.getText(), selectedElement.getOriginX()))); manager.updateValues(); StateManager.pushState(manager); } } } }); xOriginField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setOriginX((Parser.parseDouble(xOriginField.getText(), selectedElement.getOriginX()))); manager.updateValues(); } } }); SidebarPanel.initIncrementableField(yOriginField, defaultFont); yOriginField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setOriginY((Parser.parseDouble(yOriginField.getText(), selectedElement.getOriginY()))); manager.updateValues(); StateManager.pushState(manager); } } } }); yOriginField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setOriginY((Parser.parseDouble(yOriginField.getText(), selectedElement.getOriginY()))); manager.updateValues(); } } }); SidebarPanel.initIncrementableField(zOriginField, defaultFont); zOriginField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setOriginZ((Parser.parseDouble(zOriginField.getText(), selectedElement.getOriginZ()))); manager.updateValues(); StateManager.pushState(manager); } } } }); zOriginField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setOriginZ((Parser.parseDouble(zOriginField.getText(), selectedElement.getOriginZ()))); manager.updateValues(); } } }); SidebarPanel.initIncrementButton(btnPlusX, defaultFont, "X origin", true); btnPlusX.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addOriginX(ctrl == 0 ? 0.1 : 0.01); } else { selectedElement.addOriginX(1.0); } xOriginField.setText(Exporter.FORMAT.format(selectedElement.getOriginX())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.ORIGIN_X); } }); SidebarPanel.initIncrementButton(btnPlusY, defaultFont, "Y origin", true); btnPlusY.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addOriginY(ctrl == 0 ? 0.1 : 0.01); } else { selectedElement.addOriginY(1.0); } yOriginField.setText(Exporter.FORMAT.format(selectedElement.getOriginY())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.ORIGIN_Y); } }); SidebarPanel.initIncrementButton(btnPlusZ, defaultFont, "Z origin", true); btnPlusZ.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addOriginZ(ctrl == 0 ? 0.1 : 0.01); } else { selectedElement.addOriginZ(1.0); } zOriginField.setText(Exporter.FORMAT.format(selectedElement.getOriginZ())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.ORIGIN_Z); } }); SidebarPanel.initIncrementButton(btnNegX, defaultFont, "X origin", false); btnNegX.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addOriginX(ctrl == 0 ? -0.1 : -0.01); } else { selectedElement.addOriginX(-1.0); } xOriginField.setText(Exporter.FORMAT.format(selectedElement.getOriginX())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.ORIGIN_Z); } }); SidebarPanel.initIncrementButton(btnNegY, defaultFont, "Y origin", false); btnNegY.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addOriginY(ctrl == 0 ? -0.1 : -0.01); } else { selectedElement.addOriginY(-1.0); } yOriginField.setText(Exporter.FORMAT.format(selectedElement.getOriginY())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.ORIGIN_Y); } }); SidebarPanel.initIncrementButton(btnNegZ, defaultFont, "Z origin", false); btnNegZ.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addOriginZ(ctrl == 0 ? -0.1 : -0.01); } else { selectedElement.addOriginZ(-1.0); } zOriginField.setText(Exporter.FORMAT.format(selectedElement.getOriginZ())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.ORIGIN_Z); } }); } private void addComponents() { this.add(btnPlusX); this.add(btnPlusY); this.add(btnPlusZ); this.add(xOriginField); this.add(yOriginField); this.add(zOriginField); this.add(btnNegX); this.add(btnNegY); this.add(btnNegZ); } @Override public void updateValues(Element cube) { if(cube != null) { xOriginField.setEnabled(true); yOriginField.setEnabled(true); zOriginField.setEnabled(true); xOriginField.setText(Exporter.FORMAT.format(cube.getOriginX())); yOriginField.setText(Exporter.FORMAT.format(cube.getOriginY())); zOriginField.setText(Exporter.FORMAT.format(cube.getOriginZ())); } else { xOriginField.setEnabled(false); yOriginField.setEnabled(false); zOriginField.setEnabled(false); xOriginField.setText(""); yOriginField.setText(""); zOriginField.setText(""); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/PositionPanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.*; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.util.Parser; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class PositionPanel extends JPanel implements IElementUpdater { private ElementManager manager; private JButton btnPlusX; private JButton btnPlusY; private JButton btnPlusZ; private JTextField xPositionField; private JTextField yPositionField; private JTextField zPositionField; private JButton btnNegX; private JButton btnNegY; private JButton btnNegZ; public PositionPanel(ElementManager manager) { this.manager = manager; this.setBackground(ModelCreator.BACKGROUND); this.setLayout(new GridLayout(3, 3, 4, 4)); this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Position")); this.setMaximumSize(new Dimension(186, 124)); this.setAlignmentX(JPanel.CENTER_ALIGNMENT); this.initComponents(); this.initProperties(); this.addComponents(); } private void initComponents() { btnPlusX = new JButton(Icons.arrow_up); btnPlusY = new JButton(Icons.arrow_up); btnPlusZ = new JButton(Icons.arrow_up); xPositionField = new JTextField(); yPositionField = new JTextField(); zPositionField = new JTextField(); btnNegX = new JButton(Icons.arrow_down); btnNegY = new JButton(Icons.arrow_down); btnNegZ = new JButton(Icons.arrow_down); } private void initProperties() { Font defaultFont = new Font("SansSerif", Font.BOLD, 20); SidebarPanel.initIncrementableField(xPositionField, defaultFont); xPositionField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setStartX(Parser.parseDouble(xPositionField.getText(), selectedElement.getStartX())); selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushState(manager); } } } }); xPositionField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setStartX(Parser.parseDouble(xPositionField.getText(), selectedElement.getStartX())); selectedElement.updateEndUVs(); manager.updateValues(); } } }); SidebarPanel.initIncrementableField(yPositionField, defaultFont); yPositionField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { StateManager.pushState(manager); selectedElement.setStartY(Parser.parseDouble(yPositionField.getText(), selectedElement.getStartY())); selectedElement.updateEndUVs(); manager.updateValues(); } } } }); yPositionField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { StateManager.pushState(manager); selectedElement.setStartY(Parser.parseDouble(yPositionField.getText(), selectedElement.getStartY())); selectedElement.updateEndUVs(); manager.updateValues(); } } }); SidebarPanel.initIncrementableField(zPositionField, defaultFont); zPositionField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { StateManager.pushState(manager); selectedElement.setStartZ(Parser.parseDouble(zPositionField.getText(), selectedElement.getStartZ())); selectedElement.updateEndUVs(); manager.updateValues(); } } } }); zPositionField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { StateManager.pushState(manager); selectedElement.setStartZ(Parser.parseDouble(zPositionField.getText(), selectedElement.getStartZ())); selectedElement.updateEndUVs(); manager.updateValues(); } } }); SidebarPanel.initIncrementButton(btnPlusX, defaultFont, "X position", true); btnPlusX.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addStartX(ctrl == 0 ? 0.1 : 0.01); } else { selectedElement.addStartX(1.0); } xPositionField.setText(Exporter.FORMAT.format(selectedElement.getStartX())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.POS_X); } }); SidebarPanel.initIncrementButton(btnPlusY, defaultFont, "Y position", true); btnPlusY.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addStartY(ctrl == 0 ? 0.1 : 0.01); } else { selectedElement.addStartY(1.0); } yPositionField.setText(Exporter.FORMAT.format(selectedElement.getStartY())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.POS_Y); } }); SidebarPanel.initIncrementButton(btnPlusZ, defaultFont, "Z position", true); btnPlusZ.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addStartZ(ctrl == 0 ? 0.1 : 0.01); } else { selectedElement.addStartZ(1.0); } zPositionField.setText(Exporter.FORMAT.format(selectedElement.getStartZ())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.POS_Z); } }); SidebarPanel.initIncrementButton(btnNegX, defaultFont, "X position", false); btnNegX.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addStartX(ctrl == 0 ? -0.1 : -0.01); } else { selectedElement.addStartX(-1.0); } xPositionField.setText(Exporter.FORMAT.format(selectedElement.getStartX())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.POS_X); } }); SidebarPanel.initIncrementButton(btnNegY, defaultFont, "Y position", false); btnNegY.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addStartY(ctrl == 0 ? -0.1 : -0.01); } else { selectedElement.addStartY(-1.0); } yPositionField.setText(Exporter.FORMAT.format(selectedElement.getStartY())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.POS_Y); } }); SidebarPanel.initIncrementButton(btnNegZ, defaultFont, "Z position", false); btnNegZ.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addStartZ(ctrl == 0 ? -0.1 : -0.01); } else { selectedElement.addStartZ(-1.0F); } zPositionField.setText(Exporter.FORMAT.format(selectedElement.getStartZ())); StateManager.pushStateDelayed(manager, PropertyIdentifiers.POS_Z); } }); } private void addComponents() { this.add(btnPlusX); this.add(btnPlusY); this.add(btnPlusZ); this.add(xPositionField); this.add(yPositionField); this.add(zPositionField); this.add(btnNegX); this.add(btnNegY); this.add(btnNegZ); } @Override public void updateValues(Element cube) { if(cube != null) { xPositionField.setEnabled(true); yPositionField.setEnabled(true); zPositionField.setEnabled(true); xPositionField.setText(Exporter.FORMAT.format(cube.getStartX())); yPositionField.setText(Exporter.FORMAT.format(cube.getStartY())); zPositionField.setText(Exporter.FORMAT.format(cube.getStartZ())); } else { xPositionField.setEnabled(false); yPositionField.setEnabled(false); zPositionField.setEnabled(false); xPositionField.setText(""); yPositionField.setText(""); zPositionField.setText(""); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/SidebarPanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.Icons; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.StateManager; import com.mrcrayfish.modelcreator.component.*; import com.mrcrayfish.modelcreator.component.Menu; import com.mrcrayfish.modelcreator.display.DisplayProperties; import com.mrcrayfish.modelcreator.element.*; import com.mrcrayfish.modelcreator.panels.tabs.ElementPanel; import com.mrcrayfish.modelcreator.panels.tabs.FacePanel; import com.mrcrayfish.modelcreator.panels.tabs.RotationPanel; import com.mrcrayfish.modelcreator.texture.TextureEntry; import javax.swing.*; import java.awt.*; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; public class SidebarPanel extends JPanel implements ElementManager { private ModelCreator creator; // Swing Variables private SpringLayout layout; private DefaultListModel model = new DefaultListModel<>(); private JList list = new JElementList(); private JScrollPane scrollPane; private JPanel btnContainer; private JButton btnAdd = new JButton(); private JButton btnRemove = new JButton(); private JButton btnDuplicate = new JButton(); private JTextField name = new JTextField(); private CuboidTabbedPane tabbedPane = new CuboidTabbedPane(this); private TextureEntry particle = null; private boolean ambientOcc = true; private DisplayProperties properties = new DisplayProperties(DisplayProperties.MODEL_CREATOR_BLOCK); public SidebarPanel(ModelCreator creator) { this.creator = creator; this.setLayout(layout = new SpringLayout()); this.setPreferredSize(new Dimension(200, 760)); this.initComponents(); this.setLayoutConstaints(); } private void initComponents() { Font defaultFont = new Font("SansSerif", Font.BOLD, 14); btnContainer = new JPanel(new GridLayout(1, 3, 4, 0)); btnContainer.setPreferredSize(new Dimension(190, 30)); btnAdd.setIcon(Icons.cube); btnAdd.setToolTipText("New Element"); btnAdd.addActionListener(e -> this.newElement()); btnAdd.setPreferredSize(new Dimension(30, 30)); btnContainer.add(btnAdd); btnRemove.setIcon(Icons.bin); btnRemove.setToolTipText("Remove Element"); btnRemove.addActionListener(e -> this.deleteElement()); btnRemove.setPreferredSize(new Dimension(30, 30)); btnContainer.add(btnRemove); btnDuplicate.setIcon(Icons.copy); btnDuplicate.setToolTipText("Duplicate Element"); btnDuplicate.addActionListener(e -> { int selected = list.getSelectedIndex(); if(selected != -1) { model.addElement(new ElementCellEntry(new Element(model.getElementAt(selected).getElement()))); list.setSelectedIndex(model.getSize() - 1); StateManager.pushState(creator.getElementManager()); } }); btnDuplicate.setFont(defaultFont); btnDuplicate.setPreferredSize(new Dimension(30, 30)); btnContainer.add(btnDuplicate); add(btnContainer); name.setPreferredSize(new Dimension(190, 30)); name.setToolTipText("Element Name"); name.setEnabled(false); name.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { updateName(); } } }); name.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { updateName(); } }); add(name); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); list.setFixedCellHeight(26); list.setModel(model); list.addListSelectionListener(e -> { Element selectedElement = getSelectedElement(); if(selectedElement != null) { tabbedPane.updateValues(); name.setEnabled(true); name.setText(selectedElement.getName()); list.ensureIndexIsVisible(list.getSelectedIndex()); } }); list.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_DELETE) { deleteElement(); return; } boolean home = e.getKeyCode() == KeyEvent.VK_HOME; if (home || e.getKeyCode() == KeyEvent.VK_END) setSelectedElement(home ? 0 : model.getSize() - 1); } }); list.setCellRenderer(new ElementCellRenderer()); scrollPane = new JScrollPane(list); scrollPane.setPreferredSize(new Dimension(190, 170)); add(scrollPane); tabbedPane.setBackground(new Color(127, 132, 145)); tabbedPane.setForeground(Color.WHITE); tabbedPane.add("Element", new ElementPanel(this)); tabbedPane.add("Rotation", new RotationPanel(this)); tabbedPane.add("Faces", new FacePanel(this)); tabbedPane.setPreferredSize(new Dimension(190, 500)); tabbedPane.setTabPlacement(JTabbedPane.TOP); tabbedPane.addChangeListener(c -> { if(tabbedPane.getSelectedIndex() == 2) { creator.setSidebar(ModelCreator.uvSidebar); ModelCreator.isUVSidebarOpen = true; } else { creator.setSidebar(null); ModelCreator.isUVSidebarOpen = false; } }); add(tabbedPane); } public static void initIncrementButton(JButton button, Font defaultFont, String subject, boolean increase) { button.setPreferredSize(new Dimension(62, 30)); button.setFont(defaultFont); button.setToolTipText(String.format("%screases the %s.
Hold shift for decimals", increase ? "In" : "De", subject)); } public static void initIncrementableField(JTextField field, Font defaultFont) { field.setSize(new Dimension(62, 30)); field.setFont(defaultFont); field.setHorizontalAlignment(JTextField.CENTER); } private void setLayoutConstaints() { layout.putConstraint(SpringLayout.NORTH, name, 212, SpringLayout.NORTH, this); layout.putConstraint(SpringLayout.NORTH, btnContainer, 176, SpringLayout.NORTH, this); layout.putConstraint(SpringLayout.NORTH, tabbedPane, 250, SpringLayout.NORTH, this); } public JList getList() { return list; } @Override public Element getSelectedElement() { int i = list.getSelectedIndex(); if(model.getSize() > 0 && i >= 0 && i < model.getSize()) { return model.getElementAt(i).getElement(); } return null; } public ElementCellEntry getSelectedElementEntry() { int i = list.getSelectedIndex(); if(model.getSize() > 0 && i >= 0 && i < model.getSize()) { return model.getElementAt(i); } return null; } @Override public void setSelectedElement(int pos) { if(pos < model.size()) { if(pos >= 0) { list.setSelectedIndex(pos); } else { list.clearSelection(); } updateValues(); } } @Override public List getAllElements() { List list = new ArrayList<>(); for(int i = 0; i < model.size(); i++) { list.add(model.getElementAt(i).getElement()); } return list; } @Override public Element getElement(int index) { //TODO null pointer exception return model.getElementAt(index).getElement(); } @Override public int getElementCount() { return model.size(); } @Override public void updateName() { String newName = name.getText(); if(newName.isEmpty()) { newName = "Cuboid"; } Element selectedElement = getSelectedElement(); if(selectedElement != null) { selectedElement.setName(newName); name.setText(newName); list.repaint(); StateManager.pushState(creator.getElementManager()); } } @Override public void updateValues() { tabbedPane.updateValues(); } public ModelCreator getCreator() { return creator; } @Override public boolean getAmbientOcc() { return ambientOcc; } @Override public void setAmbientOcc(boolean occ) { ambientOcc = occ; } @Override public void clearElements() { model.clear(); } @Override public void addElement(Element e) { model.addElement(new ElementCellEntry(e)); } @Override public void setParticle(TextureEntry particle) { this.particle = particle; } @Override public TextureEntry getParticle() { return particle; } @Override public void reset() { this.clearElements(); ambientOcc = true; particle = null; } @Override public void restoreState(ElementManagerState state) { this.reset(); for(Element element : state.getElements()) { this.model.addElement(new ElementCellEntry(new Element(element))); } this.setSelectedElement(state.getSelectedIndex()); this.ambientOcc = state.isAmbientOcclusion(); this.particle = state.getParticleTexture(); this.updateValues(); } @Override public void setDisplayProperties(DisplayProperties properties) { this.properties = new DisplayProperties(properties); } @Override public DisplayProperties getDisplayProperties() { return properties; } public void newElement() { model.addElement(new ElementCellEntry(new Element(1, 1, 1))); list.setSelectedIndex(model.size() - 1); StateManager.pushState(creator.getElementManager()); } public void deleteElement() { int selected = list.getSelectedIndex(); if(selected != -1) { model.remove(selected); name.setText(""); name.setEnabled(false); tabbedPane.updateValues(); if(selected >= list.getModel().getSize()) { list.setSelectedIndex(list.getModel().getSize() - 1); } else { list.setSelectedIndex(selected); } StateManager.pushState(creator.getElementManager()); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/SizePanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.*; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.util.Parser; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SizePanel extends JPanel implements IElementUpdater { private ElementManager manager; private JButton btnPlusX; private JButton btnPlusY; private JButton btnPlusZ; private JTextField xSizeField; private JTextField ySizeField; private JTextField zSizeField; private JButton btnNegX; private JButton btnNegY; private JButton btnNegZ; public SizePanel(ElementManager manager) { this.manager = manager; this.setBackground(ModelCreator.BACKGROUND); this.setLayout(new GridLayout(3, 3, 4, 4)); this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Size")); this.setMaximumSize(new Dimension(186, 124)); this.initComponents(); this.initProperties(); this.addComponents(); } private void initComponents() { btnPlusX = new JButton(Icons.arrow_up); btnPlusY = new JButton(Icons.arrow_up); btnPlusZ = new JButton(Icons.arrow_up); xSizeField = new JTextField(); ySizeField = new JTextField(); zSizeField = new JTextField(); btnNegX = new JButton(Icons.arrow_down); btnNegY = new JButton(Icons.arrow_down); btnNegZ = new JButton(Icons.arrow_down); } private void initProperties() { Font defaultFont = new Font("SansSerif", Font.BOLD, 20); SidebarPanel.initIncrementableField(xSizeField, defaultFont); xSizeField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setWidth(Parser.parseDouble(xSizeField.getText(), selectedElement.getWidth())); selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushState(manager); } } } }); xSizeField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setWidth(Parser.parseDouble(xSizeField.getText(), selectedElement.getWidth())); selectedElement.updateEndUVs(); manager.updateValues(); } } }); SidebarPanel.initIncrementableField(ySizeField, defaultFont); ySizeField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setHeight(Parser.parseDouble(ySizeField.getText(), selectedElement.getHeight())); selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushState(manager); } } } }); ySizeField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setHeight(Parser.parseDouble(ySizeField.getText(), selectedElement.getHeight())); selectedElement.updateEndUVs(); manager.updateValues(); } } }); SidebarPanel.initIncrementableField(zSizeField, defaultFont); zSizeField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setDepth(Parser.parseDouble(zSizeField.getText(), selectedElement.getDepth())); selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushState(manager); } } } }); zSizeField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setDepth(Parser.parseDouble(zSizeField.getText(), selectedElement.getDepth())); selectedElement.updateEndUVs(); manager.updateValues(); } } }); SidebarPanel.initIncrementButton(btnPlusX, defaultFont, "width", true); btnPlusX.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addWidth(ctrl == 0 ? 0.1 : 0.01); } else { selectedElement.addWidth(1.0); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.SIZE_X); } }); SidebarPanel.initIncrementButton(btnPlusY, defaultFont, "height", true); btnPlusY.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addHeight(ctrl == 0 ? 0.1 : 0.01); } else { selectedElement.addHeight(1.0); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.SIZE_Y); } }); SidebarPanel.initIncrementButton(btnPlusZ, defaultFont, "depth", true); btnPlusZ.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.addDepth(ctrl == 0 ? 0.1 : 0.01); } else { selectedElement.addDepth(1.0); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.SIZE_Z); } }); SidebarPanel.initIncrementButton(btnNegX, defaultFont, "width", false); btnNegX.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.setWidth(Math.max(0.0, selectedElement.getWidth() - (ctrl == 0 ? 0.1 : 0.01))); } else { selectedElement.setWidth(Math.max(0.0, selectedElement.getWidth() - 1.0)); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.SIZE_X); } }); SidebarPanel.initIncrementButton(btnNegY, defaultFont, "height", false); btnNegY.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.setHeight(Math.max(0.0, selectedElement.getHeight() - (ctrl == 0 ? 0.1 : 0.01))); } else { selectedElement.setHeight(Math.max(0.0, selectedElement.getHeight() - 1.0)); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.SIZE_Y); } }); SidebarPanel.initIncrementButton(btnNegZ, defaultFont, "depth", false); btnNegZ.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { selectedElement.setDepth(Math.max(0.0, selectedElement.getDepth() - (ctrl == 0 ? 0.1 : 0.01))); } else { selectedElement.setDepth(Math.max(0.0, selectedElement.getDepth() - 1.0)); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.SIZE_Z); } }); } private void addComponents() { this.add(btnPlusX); this.add(btnPlusY); this.add(btnPlusZ); this.add(xSizeField); this.add(ySizeField); this.add(zSizeField); this.add(btnNegX); this.add(btnNegY); this.add(btnNegZ); } @Override public void updateValues(Element cube) { if(cube != null) { xSizeField.setEnabled(true); ySizeField.setEnabled(true); zSizeField.setEnabled(true); xSizeField.setText(Exporter.FORMAT.format(cube.getWidth())); ySizeField.setText(Exporter.FORMAT.format(cube.getHeight())); zSizeField.setText(Exporter.FORMAT.format(cube.getDepth())); } else { xSizeField.setEnabled(false); ySizeField.setEnabled(false); zSizeField.setEnabled(false); xSizeField.setText(""); ySizeField.setText(""); zSizeField.setText(""); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/TexturePanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.Icons; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.StateManager; import com.mrcrayfish.modelcreator.component.TextureManager; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.texture.Clipboard; import com.mrcrayfish.modelcreator.texture.TextureEntry; import javax.swing.*; import java.awt.*; import java.awt.event.InputEvent; public class TexturePanel extends JPanel { private ElementManager manager; private JButton btnSelect; private JButton btnClear; private JButton btnCopy; private JButton btnPaste; public TexturePanel(ElementManager manager) { this.manager = manager; this.setBackground(ModelCreator.BACKGROUND); this.setLayout(new GridLayout(2, 2, 4, 4)); this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Texture")); this.setMaximumSize(new Dimension(186, 80)); this.initComponents(); this.addComponents(); } private void initComponents() { btnSelect = new JButton("Select..."); btnSelect.setIcon(Icons.texture); btnSelect.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { TextureEntry entry = TextureManager.display(((SidebarPanel) manager).getCreator(), manager, Dialog.ModalityType.APPLICATION_MODAL); if(entry != null) { selectedElement.getSelectedFace().setTexture(entry); StateManager.pushState(manager); } } }); btnSelect.setToolTipText("Opens the Texture Manager"); btnClear = new JButton("Clear"); btnClear.setIcon(Icons.clear_texture); btnClear.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { if((e.getModifiers() & InputEvent.SHIFT_MASK) == 1) { selectedElement.setAllTextures(null); } else { selectedElement.getSelectedFace().setTexture(null); } StateManager.pushState(manager); } }); btnClear.setToolTipText("Clears the texture from this face.
Hold shift to clear all faces"); btnCopy = new JButton("Copy"); btnCopy.setIcon(Icons.copy_small); btnCopy.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); Clipboard.copyTexture(face); } }); btnCopy.setToolTipText("Copies the texture on this face to clipboard"); btnPaste = new JButton("Paste"); btnPaste.setIcon(Icons.clipboard_texture); btnPaste.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { TextureEntry entry = Clipboard.getTexture(); if(entry != null) { if((e.getModifiers() & InputEvent.SHIFT_MASK) == 1) { selectedElement.setAllTextures(entry); } else { Face face = selectedElement.getSelectedFace(); face.setTexture(entry); } StateManager.pushState(manager); } } }); btnPaste.setToolTipText("Pastes the clipboard texture to this face.
Hold shift to paste to all faces"); } private void addComponents() { this.add(btnSelect); this.add(btnClear); this.add(btnCopy); this.add(btnPaste); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/UVPanel.java ================================================ package com.mrcrayfish.modelcreator.panels; import com.mrcrayfish.modelcreator.*; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.util.Parser; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class UVPanel extends JPanel implements IElementUpdater { private ElementManager manager; private JButton btnPlusX; private JButton btnPlusY; private JTextField xStartField; private JTextField yStartField; private JButton btnNegX; private JButton btnNegY; private JButton btnPlusXEnd; private JButton btnPlusYEnd; private JTextField xEndField; private JTextField yEndField; private JButton btnNegXEnd; private JButton btnNegYEnd; public UVPanel(ElementManager manager) { this.manager = manager; this.setBackground(ModelCreator.BACKGROUND); this.setLayout(new GridLayout(3, 4, 4, 4)); this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "UV")); this.setMaximumSize(new Dimension(186, 124)); this.initComponents(); this.initProperties(); this.addComponents(); } private void initComponents() { btnPlusX = new JButton(Icons.arrow_up); btnPlusY = new JButton(Icons.arrow_up); xStartField = new JTextField(); yStartField = new JTextField(); btnNegX = new JButton(Icons.arrow_down); btnNegY = new JButton(Icons.arrow_down); btnPlusXEnd = new JButton(Icons.arrow_up); btnPlusYEnd = new JButton(Icons.arrow_up); xEndField = new JTextField(); yEndField = new JTextField(); btnNegXEnd = new JButton(Icons.arrow_down); btnNegYEnd = new JButton(Icons.arrow_down); } private void initProperties() { Font defaultFont = new Font("SansSerif", Font.BOLD, 20); SidebarPanel.initIncrementableField(xStartField, defaultFont); xStartField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); face.setStartU(Parser.parseDouble(xStartField.getText(), face.getStartU())); face.updateEndUV(); manager.updateValues(); StateManager.pushState(manager); } } } }); xStartField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); face.setStartU(Parser.parseDouble(xStartField.getText(), face.getStartU())); face.updateEndUV(); manager.updateValues(); } } }); SidebarPanel.initIncrementableField(yStartField, defaultFont); yStartField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); face.setStartV(Parser.parseDouble(yStartField.getText(), face.getStartV())); face.updateEndUV(); manager.updateValues(); StateManager.pushState(manager); } } } }); yStartField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); face.setStartV(Parser.parseDouble(yStartField.getText(), face.getStartV())); face.updateEndUV(); manager.updateValues(); } } }); SidebarPanel.initIncrementableField(xEndField, defaultFont); xEndField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); face.setEndU(Parser.parseDouble(xEndField.getText(), face.getEndU())); face.updateEndUV(); manager.updateValues(); StateManager.pushState(manager); } } } }); xEndField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); face.setEndU(Parser.parseDouble(xEndField.getText(), face.getEndU())); face.updateEndUV(); manager.updateValues(); } } }); SidebarPanel.initIncrementableField(yEndField, defaultFont); yEndField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); face.setEndV(Parser.parseDouble(yEndField.getText(), face.getEndV())); face.updateEndUV(); manager.updateValues(); StateManager.pushState(manager); } } } }); yEndField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); face.setEndV(Parser.parseDouble(yEndField.getText(), face.getEndV())); face.updateEndUV(); manager.updateValues(); StateManager.pushState(manager); } } }); SidebarPanel.initIncrementButton(btnPlusX, defaultFont, "start U", true); btnPlusX.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { face.addTextureX(ctrl == 0 ? 0.1 : 0.01); } else { face.addTextureX(1.0); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.START_U); } }); SidebarPanel.initIncrementButton(btnPlusY, defaultFont, "start V", true); btnPlusY.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { face.addTextureY(ctrl == 0 ? 0.1 : 0.01); } else { face.addTextureY(1.0); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.START_V); } }); SidebarPanel.initIncrementButton(btnNegX, defaultFont, "start U", false); btnNegX.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { face.addTextureX(ctrl == 0 ? -0.1 : -0.01); } else { face.addTextureX(-1.0); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.START_U); } }); SidebarPanel.initIncrementButton(btnNegY, defaultFont, "start V", false); btnNegY.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { face.addTextureY(ctrl == 0 ? -0.1 : -0.01); } else { face.addTextureY(-1.0); } selectedElement.updateEndUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.START_V); } }); SidebarPanel.initIncrementButton(btnPlusXEnd, defaultFont, "end U", true); btnPlusXEnd.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { face.addTextureXEnd(ctrl == 0 ? 0.1 : 0.01); } else { face.addTextureXEnd(1.0); } selectedElement.updateStartUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.END_U); } }); SidebarPanel.initIncrementButton(btnPlusYEnd, defaultFont, "end V", true); btnPlusYEnd.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { face.addTextureYEnd(ctrl == 0 ? 0.1 : 0.01); } else { face.addTextureYEnd(1.0); } selectedElement.updateStartUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.END_V); } }); SidebarPanel.initIncrementButton(btnNegXEnd, defaultFont, "end U", false); btnNegXEnd.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { face.addTextureXEnd(ctrl == 0 ? -0.1 : -0.01); } else { face.addTextureXEnd(-1.0); } selectedElement.updateStartUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.END_U); } }); SidebarPanel.initIncrementButton(btnNegYEnd, defaultFont, "end V", false); btnNegYEnd.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getSelectedFace(); int ctrl = e.getModifiers() & InputEvent.CTRL_MASK; if((e.getModifiers() & InputEvent.SHIFT_MASK) > 0 && ctrl >= 0) { face.addTextureYEnd(ctrl == 0 ? -0.1 : -0.01); } else { face.addTextureYEnd(-1.0); } selectedElement.updateStartUVs(); manager.updateValues(); StateManager.pushStateDelayed(manager, PropertyIdentifiers.END_V); } }); } private void addComponents() { this.add(btnPlusX); this.add(btnPlusY); this.add(btnPlusXEnd); this.add(btnPlusYEnd); this.add(xStartField); this.add(yStartField); this.add(xEndField); this.add(yEndField); this.add(btnNegX); this.add(btnNegY); this.add(btnNegXEnd); this.add(btnNegYEnd); } @Override public void updateValues(Element cube) { if(cube != null) { xStartField.setEnabled(true); yStartField.setEnabled(true); xEndField.setEnabled(true); yEndField.setEnabled(true); xStartField.setText(Exporter.FORMAT.format(cube.getSelectedFace().getStartU())); yStartField.setText(Exporter.FORMAT.format(cube.getSelectedFace().getStartV())); xEndField.setText(Exporter.FORMAT.format(cube.getSelectedFace().getEndU())); yEndField.setText(Exporter.FORMAT.format(cube.getSelectedFace().getEndV())); } else { xStartField.setEnabled(false); yStartField.setEnabled(false); xEndField.setEnabled(false); yEndField.setEnabled(false); xStartField.setText(""); yStartField.setText(""); xEndField.setText(""); yEndField.setText(""); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/tabs/ElementPanel.java ================================================ package com.mrcrayfish.modelcreator.panels.tabs; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.panels.*; import javax.swing.*; import java.awt.*; public class ElementPanel extends JPanel implements IElementUpdater { private ElementManager manager; private SizePanel panelSize; private PositionPanel panelPosition; private ElementExtraPanel panelExtras; private GlobalPanel panelGlobal; public ElementPanel(ElementManager manager) { this.manager = manager; setBackground(ModelCreator.BACKGROUND); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); initComponents(); addComponents(); } private void initComponents() { panelSize = new SizePanel(manager); panelPosition = new PositionPanel(manager); panelExtras = new ElementExtraPanel(manager); panelGlobal = new GlobalPanel(manager); } private void addComponents() { add(Box.createRigidArea(new Dimension(188, 5))); add(panelSize); add(Box.createRigidArea(new Dimension(188, 5))); add(panelPosition); add(Box.createRigidArea(new Dimension(188, 5))); add(panelExtras); add(Box.createRigidArea(new Dimension(188, 70))); add(new JSeparator(JSeparator.HORIZONTAL)); add(panelGlobal); } @Override public void updateValues(Element cube) { panelSize.updateValues(cube); panelPosition.updateValues(cube); panelExtras.updateValues(cube); panelGlobal.updateValues(cube); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/tabs/FacePanel.java ================================================ package com.mrcrayfish.modelcreator.panels.tabs; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.StateManager; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.panels.FaceExtrasPanel; import com.mrcrayfish.modelcreator.panels.IElementUpdater; import com.mrcrayfish.modelcreator.panels.TexturePanel; import com.mrcrayfish.modelcreator.panels.UVPanel; import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Hashtable; public class FacePanel extends JPanel implements IElementUpdater { private ElementManager manager; private JPanel menuPanel; private JComboBox menuList; private UVPanel panelUV; private JPanel sliderPanel; private JSlider rotation; private TexturePanel panelTexture; private FaceExtrasPanel panelProperties; private final int ROTATION_MIN = 0; private final int ROTATION_MAX = 3; private final int ROTATION_INIT = 0; private DefaultComboBoxModel model; public FacePanel(ElementManager manager) { this.manager = manager; setBackground(ModelCreator.BACKGROUND); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); initMenu(); initComponents(); addComponents(); } private void initMenu() { model = new DefaultComboBoxModel<>(); model.addElement("
North"); model.addElement("
East"); model.addElement("
South"); model.addElement("
West"); model.addElement("
Up"); model.addElement("
Down"); } private void initComponents() { menuPanel = new JPanel(new GridLayout(1, 1)); menuPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Side")); menuPanel.setMaximumSize(new Dimension(186, 56)); menuPanel.setBackground(ModelCreator.BACKGROUND); menuList = new JComboBox<>(); menuList.setModel(model); menuList.setToolTipText("The face to edit."); menuList.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setSelectedFace(menuList.getSelectedIndex()); updateValues(selectedElement); } }); menuPanel.add(menuList); panelTexture = new TexturePanel(manager); panelUV = new UVPanel(manager); panelProperties = new FaceExtrasPanel(manager); Hashtable labelTable = new Hashtable<>(); labelTable.put(0, new JLabel("0\u00b0")); labelTable.put(1, new JLabel("90\u00b0")); labelTable.put(2, new JLabel("180\u00b0")); labelTable.put(3, new JLabel("270\u00b0")); sliderPanel = new JPanel(new GridLayout(1, 1)); sliderPanel.setBackground(ModelCreator.BACKGROUND); sliderPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Rotation")); rotation = new JSlider(JSlider.HORIZONTAL, ROTATION_MIN, ROTATION_MAX, ROTATION_INIT); rotation.setBackground(ModelCreator.BACKGROUND); rotation.setMajorTickSpacing(4); rotation.setPaintTicks(true); rotation.setPaintLabels(true); rotation.setLabelTable(labelTable); rotation.addChangeListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.getSelectedFace().setRotation(rotation.getValue()); } }); rotation.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { StateManager.pushState(manager); } }); rotation.setToolTipText("The rotation of the texture
Default: 0\u00b0"); sliderPanel.setMaximumSize(new Dimension(190, 80)); sliderPanel.add(rotation); } private void addComponents() { add(Box.createRigidArea(new Dimension(192, 5))); add(menuPanel); add(panelTexture); add(panelUV); add(sliderPanel); add(panelProperties); } @Override public void updateValues(Element cube) { if(cube != null) { menuList.setSelectedItem(model.getElementAt(cube.getSelectedFaceIndex())); menuList.repaint(); rotation.setEnabled(true); rotation.setValue(cube.getSelectedFace().getRotation()); } else { rotation.setEnabled(false); rotation.setValue(0); } panelUV.updateValues(cube); panelProperties.updateValues(cube); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/panels/tabs/RotationPanel.java ================================================ package com.mrcrayfish.modelcreator.panels.tabs; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.StateManager; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.panels.IElementUpdater; import com.mrcrayfish.modelcreator.panels.OriginPanel; import com.mrcrayfish.modelcreator.util.ComponentUtil; import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Hashtable; public class RotationPanel extends JPanel implements IElementUpdater { private ElementManager manager; private OriginPanel panelOrigin; private JPanel axisPanel; private JComboBox axisList; private JPanel sliderPanel; private JSlider rotation; private JPanel extraPanel; private JRadioButton btnRescale; private DefaultComboBoxModel model; private final int ROTATION_MIN = -2; private final int ROTATION_MAX = 2; private final int ROTATION_INIT = 0; public RotationPanel(ElementManager manager) { this.manager = manager; this.setBackground(ModelCreator.BACKGROUND); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.initMenu(); this.initComponents(); this.addComponents(); } private void initMenu() { model = new DefaultComboBoxModel<>(); model.addElement("
X"); model.addElement("
Y"); model.addElement("
Z"); } private void initComponents() { panelOrigin = new OriginPanel(manager); panelOrigin.setBackground(ModelCreator.BACKGROUND); axisPanel = new JPanel(new GridLayout(1, 1)); axisPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Axis")); axisPanel.setBackground(ModelCreator.BACKGROUND); axisList = new JComboBox<>(); axisList.setModel(model); axisList.setToolTipText("The axis the element will rotate around"); axisList.addItemListener(e -> { if(e.getStateChange() == ItemEvent.SELECTED) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null && selectedElement.getRotationAxis() != axisList.getSelectedIndex()) { selectedElement.setRotationAxis(axisList.getSelectedIndex()); StateManager.pushState(manager); } } }); axisList.setMaximumSize(new Dimension(186, 55)); axisPanel.setMaximumSize(new Dimension(186, 55)); axisPanel.add(axisList); Hashtable labelTable = new Hashtable<>(); labelTable.put(-2, new JLabel("-45\u00b0")); labelTable.put(-1, new JLabel("-22.5\u00b0")); labelTable.put(0, new JLabel("0\u00b0")); labelTable.put(1, new JLabel("22.5\u00b0")); labelTable.put(2, new JLabel("45\u00b0")); sliderPanel = new JPanel(new GridLayout(1, 1)); sliderPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Rotation")); sliderPanel.setBackground(ModelCreator.BACKGROUND); rotation = new JSlider(JSlider.HORIZONTAL, ROTATION_MIN, ROTATION_MAX, ROTATION_INIT); rotation.setBackground(ModelCreator.BACKGROUND); rotation.setMajorTickSpacing(1); rotation.setPaintTicks(true); rotation.setPaintLabels(true); rotation.setLabelTable(labelTable); rotation.addChangeListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setRotation(rotation.getValue() * 22.5D); } }); rotation.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { StateManager.pushState(manager); } }); rotation.setToolTipText("The rotation of the element
Default: 0"); sliderPanel.setMaximumSize(new Dimension(190, 80)); sliderPanel.add(rotation); extraPanel = new JPanel(new GridLayout(1, 2)); extraPanel.setBackground(ModelCreator.BACKGROUND); extraPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Extras")); btnRescale = ComponentUtil.createRadioButton("Rescale", "Should scale faces across whole block
Default: Off"); btnRescale.setBackground(ModelCreator.BACKGROUND); btnRescale.addActionListener(e -> { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setRescale(btnRescale.isSelected()); StateManager.pushState(manager); } }); extraPanel.setMaximumSize(new Dimension(186, 50)); extraPanel.add(btnRescale); } private void addComponents() { add(Box.createRigidArea(new Dimension(188, 5))); add(panelOrigin); add(axisPanel); add(sliderPanel); add(extraPanel); } @Override public void updateValues(Element cube) { panelOrigin.updateValues(cube); if(cube != null) { axisList.setSelectedIndex(cube.getRotationAxis()); rotation.setEnabled(true); rotation.setValue((int) (cube.getRotation() / 22.5)); btnRescale.setEnabled(true); btnRescale.setSelected(cube.shouldRescale()); } else { rotation.setValue(0); rotation.setEnabled(false); btnRescale.setSelected(false); btnRescale.setEnabled(false); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/screenshot/PendingScreenshot.java ================================================ package com.mrcrayfish.modelcreator.screenshot; import java.io.File; public class PendingScreenshot { private File file = null; private ScreenshotCallback callback; public PendingScreenshot(File file, ScreenshotCallback callback) { this.file = file; this.callback = callback; } public File getFile() { return file; } public ScreenshotCallback getCallback() { return callback; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/screenshot/Screenshot.java ================================================ package com.mrcrayfish.modelcreator.screenshot; import com.mrcrayfish.modelcreator.util.Util; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.net.URLEncoder; import java.nio.ByteBuffer; public class Screenshot { public static void getScreenshot(int width, int height, ScreenshotCallback callback) { try { getScreenshot(width, height, callback, File.createTempFile("screenshot", ".png")); } catch(IOException e) { e.printStackTrace(); } } public static void getScreenshot(int width, int height, ScreenshotCallback callback, File file) { GL11.glReadBuffer(GL11.GL_FRONT); int bpp = 4; ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp); GL11.glReadPixels(0, 0, width, height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); try { String format = "PNG"; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { int i = (x + (width * y)) * bpp; int r = buffer.get(i) & 0xFF; int g = buffer.get(i + 1) & 0xFF; int b = buffer.get(i + 2) & 0xFF; image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); } } ImageIO.write(image, format, file); if(callback != null) { callback.callback(file); } } catch(IOException e) { e.printStackTrace(); } } private static boolean isUrl(String url) { if(url == null | (url != null && url.equals("null"))) { JOptionPane message = new JOptionPane(); message.setMessage("Failed to upload screenshot. Check your internet connection then try again."); JDialog dialog = message.createDialog(null, "Error"); dialog.setLocationRelativeTo(null); dialog.setModal(false); dialog.setVisible(true); return false; } return true; } public static void shareToFacebook(String link) { try { if(isUrl(link)) { String url = "https://www.facebook.com/sharer/sharer.php?"; url += "u=" + URLEncoder.encode(link, "UTF-8"); Util.openUrl(url); } } catch(Exception e) { e.printStackTrace(); } } public static void shareToTwitter(String link) { try { if(isUrl(link)) { String url = "https://twitter.com/intent/tweet?"; url += "text=" + URLEncoder.encode("Check out this awesome model I created with @MrCraayfish's Model Creator", "UTF-8"); url += "&url=" + URLEncoder.encode(link, "UTF-8"); Util.openUrl(url); } } catch(Exception e) { e.printStackTrace(); } } public static void shareToReddit(String link) { try { if(isUrl(link)) { String url = "http://www.reddit.com/r/Minecraft/submit?"; url += "title=" + URLEncoder.encode("[Model] (Created using MrCrayfish's Model Creator)", "UTF-8"); url += "&url=" + URLEncoder.encode(link, "UTF-8"); Util.openUrl(url); } } catch(Exception e) { e.printStackTrace(); } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/screenshot/ScreenshotCallback.java ================================================ package com.mrcrayfish.modelcreator.screenshot; import java.io.File; public interface ScreenshotCallback { void callback(File file); } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/screenshot/Uploader.java ================================================ package com.mrcrayfish.modelcreator.screenshot; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mrcrayfish.modelcreator.util.StreamUtils; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; public class Uploader { private static final String UPLOAD_URL = "https://api.imgur.com/3/image"; private static final String CLIENT_ID = "5cd0235db91ac6e"; public static String upload(File file) { HttpURLConnection conn; InputStream responseIn; try { conn = (HttpURLConnection) new URL(UPLOAD_URL).openConnection(); conn.setDoOutput(true); conn.setRequestProperty("Authorization", "Client-ID " + CLIENT_ID); OutputStream out = conn.getOutputStream(); upload(new FileInputStream(file), out); out.flush(); out.close(); if(conn.getResponseCode() == HttpURLConnection.HTTP_OK) { responseIn = conn.getInputStream(); return getImageLink(responseIn); } } catch(Exception e) { e.printStackTrace(); } return null; } private static void upload(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[8192]; int n; while((n = input.read(buffer)) != -1) { output.write(buffer, 0, n); } } private static String getImageLink(InputStream input) throws IOException { String json = StreamUtils.convertToString(input); JsonParser parser = new JsonParser(); JsonElement read = parser.parse(json); if(read.isJsonObject()) { JsonObject obj = read.getAsJsonObject(); if(obj.has("data") && obj.get("data").isJsonObject()) { JsonObject data = obj.getAsJsonObject("data"); return "http://imgur.com/" + data.get("id").getAsString(); } } return null; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/sidebar/Sidebar.java ================================================ package com.mrcrayfish.modelcreator.sidebar; import com.mrcrayfish.modelcreator.util.FontManager; import org.newdawn.slick.Color; import static org.lwjgl.opengl.GL11.*; public abstract class Sidebar { private String title; public Sidebar(String title) { this.title = title; } public void draw(int sidebarWidth, int canvasWidth, int canvasHeight, int frameHeight) { glColor3f(0.866F, 0.866F, 0.894F); glBegin(GL_QUADS); { glVertex2i(0, 0); glVertex2i(sidebarWidth, 0); glVertex2i(sidebarWidth, canvasHeight); glVertex2i(0, canvasHeight); } glEnd(); drawTitle(); } private void drawTitle() { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); FontManager.BEBAS_NEUE_20.drawString(10, 5, title, new Color(0.5F, 0.5F, 0.6F)); glDisable(GL_BLEND); } public abstract void handleMouseInput(int button, int mouseX, int mouseY, boolean pressed); public abstract void handleInput(int canvasHeight); } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/sidebar/UVSidebar.java ================================================ package com.mrcrayfish.modelcreator.sidebar; import com.mrcrayfish.modelcreator.ModelCreator; import com.mrcrayfish.modelcreator.element.Element; import com.mrcrayfish.modelcreator.element.ElementManager; import com.mrcrayfish.modelcreator.element.Face; import com.mrcrayfish.modelcreator.util.FontManager; import org.lwjgl.input.Mouse; import org.newdawn.slick.Color; import org.newdawn.slick.opengl.TextureImpl; import static org.lwjgl.opengl.GL11.*; public class UVSidebar extends Sidebar { private ElementManager manager; private final int LENGTH = 110; private final Color BLACK_ALPHA = new Color(0, 0, 0, 0.75F); private final Color BLACK_ALPHA_HOVER = new Color(0, 0, 0, 0.25F); public static final java.awt.Color BACKGROUND = new java.awt.Color(230, 230, 240); private int[] startX = {0, 0, 0, 0, 0, 0}; private int[] startY = {0, 0, 0, 0, 0, 0}; private int hoveredFace = -1; private int canvasHeight; public UVSidebar(String title, ElementManager manager) { super(title); this.manager = manager; } @Override public void draw(int sidebarWidth, int canvasWidth, int canvasHeight, int frameHeight) { super.draw(sidebarWidth, canvasWidth, canvasHeight, frameHeight); this.canvasHeight = frameHeight; if(!grabbing) { hoveredFace = getFace(frameHeight, Mouse.getX(), Mouse.getY()); } glPushMatrix(); { glTranslatef(10, 30, 0); int count = 0; for(int i = 0; i < 6; i++) { glPushMatrix(); { if(30 + i * (LENGTH + 10) + (LENGTH + 10) > canvasHeight) { glTranslatef(10 + LENGTH, count * (LENGTH + 10), 0); startX[i] = 20 + LENGTH; startY[i] = count * (LENGTH + 10) + 40; count++; } else { glTranslatef(0, i * (LENGTH + 10), 0); startX[i] = 10; startY[i] = i * (LENGTH + 10) + 40; } Face[] faces = null; Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { faces = selectedElement.getAllFaces(); } if(faces != null) { glDisable(GL_TEXTURE_2D); int color = ModelCreator.BACKGROUND.getRGB(); float b = (float) (color & 0xFF) / 0xFF; float g = (float) ((color >>> 8) & 0xFF) / 0xFF; float r = (float) ((color >>> 16) & 0xFF) / 0xFF; glColor3f(r * 0.85F, g * 0.85F, b * 0.85F); glBegin(GL_QUADS); { glVertex2i(-1, LENGTH + 1); glVertex2i(LENGTH + 1, LENGTH + 1); glVertex2i(LENGTH + 1, -1); glVertex2i(-1, -1); } glEnd(); b = (float) (color & 0xFF) / 0xFF; g = (float) ((color >>> 8) & 0xFF) / 0xFF; r = (float) ((color >>> 16) & 0xFF) / 0xFF; glColor3f(r, g, b); glBegin(GL_QUADS); { glVertex2i(0, LENGTH); glVertex2i(LENGTH, LENGTH); glVertex2i(LENGTH, 0); glVertex2i(0, 0); } glEnd(); faces[i].bindTexture(0); glBegin(GL_QUADS); { if(faces[i].isBinded()) { glTexCoord2f(0, 1); } glVertex2i(0, LENGTH); if(faces[i].isBinded()) { glTexCoord2f(1, 1); } glVertex2i(LENGTH, LENGTH); if(faces[i].isBinded()) { glTexCoord2f(1, 0); } glVertex2i(LENGTH, 0); if(faces[i].isBinded()) { glTexCoord2f(0, 0); } glVertex2i(0, 0); } glEnd(); TextureImpl.bindNone(); glColor3f(1, 1, 1); glLineWidth(1.25F); glBegin(GL_LINES); { glVertex2d(faces[i].getStartU() * (LENGTH / 16D), faces[i].getStartV() * (LENGTH / 16D)); glVertex2d(faces[i].getStartU() * (LENGTH / 16D), faces[i].getEndV() * (LENGTH / 16D)); glVertex2d(faces[i].getStartU() * (LENGTH / 16D), faces[i].getEndV() * (LENGTH / 16D)); glVertex2d(faces[i].getEndU() * (LENGTH / 16D), faces[i].getEndV() * (LENGTH / 16D)); glVertex2d(faces[i].getEndU() * (LENGTH / 16D), faces[i].getEndV() * (LENGTH / 16D)); glVertex2d(faces[i].getEndU() * (LENGTH / 16D), faces[i].getStartV() * (LENGTH / 16D)); glVertex2d(faces[i].getEndU() * (LENGTH / 16D), faces[i].getStartV() * (LENGTH / 16D)); glVertex2d(faces[i].getStartU() * (LENGTH / 16D), faces[i].getStartV() * (LENGTH / 16D)); } glEnd(); Color colorText = BLACK_ALPHA; if(hoveredFace == faces[i].getSide()) { colorText = BLACK_ALPHA_HOVER; } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); FontManager.BEBAS_NEUE_20.drawString(5, 5, Face.getFaceName(i), colorText); glDisable(GL_BLEND); } } glPopMatrix(); } } glPopMatrix(); } private int lastMouseX, lastMouseY; private int selected = -1; private boolean grabbing = false; @Override public void handleMouseInput(int button, int mouseX, int mouseY, boolean pressed) { if(pressed && (Mouse.isButtonDown(0) || Mouse.isButtonDown(1))) { if(!grabbing && hoveredFace != -1) { this.lastMouseX = mouseX; this.lastMouseY = mouseY; this.grabbing = true; this.hoveredFace = getFace(canvasHeight, Mouse.getX(), Mouse.getY()); Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { selectedElement.setSelectedFace(this.hoveredFace); manager.updateValues(); } } } else { this.grabbing = false; } } @Override public void handleInput(int canvasHeight) { int newMouseX = Mouse.getX(); int newMouseY = Mouse.getY(); if(grabbing) { if(hoveredFace != -1 || selected != -1) { Element selectedElement = manager.getSelectedElement(); if(selectedElement != null) { Face face = selectedElement.getAllFaces()[(selected != -1 ? selected : hoveredFace)]; int xMovement = (newMouseX - this.lastMouseX) / 6; int yMovement = (newMouseY - this.lastMouseY) / 6; if(xMovement != 0 || yMovement != 0) { if(Mouse.isButtonDown(0)) { if((face.getStartU() + xMovement) >= 0.0 && (face.getEndU() + xMovement) <= 16.0) { face.moveTextureU(xMovement); } if((face.getStartV() - yMovement) >= 0.0 && (face.getEndV() - yMovement) <= 16.0) { face.moveTextureV(-yMovement); } } else { face.setAutoUVEnabled(false); double uMovement = (face.getEndU() + xMovement); if(uMovement >= 0 && uMovement <= 16.0) { face.addTextureXEnd(xMovement); } double vMovement = (face.getEndV() - yMovement); if(vMovement >= 0 && vMovement <= 16.0) { face.addTextureYEnd(-yMovement); } face.setAutoUVEnabled(false); } face.updateEndUV(); if(xMovement != 0) { this.lastMouseX = newMouseX; } if(yMovement != 0) { this.lastMouseY = newMouseY; } } manager.updateValues(); } } } else { selected = -1; } } private int getFace(int canvasHeight, int mouseX, int mouseY) { for(int i = 0; i < 6; i++) { if(mouseX >= startX[i] && mouseX <= startX[i] + LENGTH) { if((canvasHeight - mouseY - 45) >= startY[i] && (canvasHeight - mouseY - 45) <= startY[i] + LENGTH) { return i; } } } return -1; } public int getHoveredFace() { return hoveredFace; } public boolean isGrabbing() { return grabbing; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/texture/Clipboard.java ================================================ package com.mrcrayfish.modelcreator.texture; import com.mrcrayfish.modelcreator.element.Face; public class Clipboard { // TODO make it so you can copy and paste certain properties. Eg Copy only texture and tint index, not UV. private static TextureEntry entry; public static void copyTexture(Face face) { entry = face.getTexture(); } public static TextureEntry getTexture() { return entry; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/texture/TextureAnimation.java ================================================ package com.mrcrayfish.modelcreator.texture; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TextureAnimation { private int width = 16, height = 16; private List frames = new ArrayList<>(); private Map customTimes = new HashMap<>(); private int frametime = 1; private boolean interpolate = false; public void setSize(int width, int height) { this.width = width; this.height = height; } public int getWidth() { return width; } public int getHeight() { return height; } public void setFrameTime(int frametime) { this.frametime = frametime; } public void setFrames(List frameList) { frames = new ArrayList<>(); frames.addAll(frameList); } public void setCustomTimes(Map times) { customTimes = new HashMap<>(); customTimes.putAll(times); } public void setInterpolate(boolean interpolate) { this.interpolate = interpolate; } public boolean isInterpolated() { return interpolate; } public int getFrameCount() { return frames.size(); } public long getMaxTime() { long maxTime = 0; for(int i = 0; i < frames.size(); i++) { maxTime += getFrameTime(i); } return maxTime; } public int getCurrentAnimationFrame() { long maxTime = this.getMaxTime(); if(maxTime > 0) { long animTime = System.currentTimeMillis() % maxTime; for(int i = 0; i < frames.size(); i++) { if(animTime < getFrameTime(i)) { return frames.get(i); } animTime -= getFrameTime(i); } } return 0; } public int getNextAnimationFrame() { if(frames.size() < 1) { return 0; } long maxTime = 0; for(int i = 0; i < frames.size(); i++) { maxTime += getFrameTime(i); } long animTime = System.currentTimeMillis() % maxTime; for(int i = 0; i < frames.size(); i++) { if(animTime <= getFrameTime(i)) { if(i < frames.size() - 1) { return frames.get(i + 1); } else { return frames.get(0); } } animTime -= getFrameTime(i); } return 0; } public long getFrameTime(int frame) { if(customTimes != null && customTimes.containsKey(frame)) { return customTimes.get(frame) * 50L; } return frametime * 50L; } public double getFrameInterpolation() { long maxTime = 0; for(int i = 0; i < frames.size(); i++) { maxTime += getFrameTime(i); } long animTime = System.currentTimeMillis() % maxTime; for(int i = 0; i < frames.size(); i++) { if(animTime <= getFrameTime(i)) { return animTime / (double) getFrameTime(i); } animTime -= getFrameTime(i); } return 0; } public int getPasses() { if(isInterpolated() && getFrameCount() > 1) { return 2; } return 1; } public static TextureAnimation getAnimationForTexture(File file, int width, int height) { try { file = new File(file.getAbsolutePath() + ".mcmeta"); if(file.exists()) { TextureAnimation anim = null; JsonObject animationObj = null; JsonParser parser = new JsonParser(); JsonElement read = parser.parse(new FileReader(file)); if(read.isJsonObject()) { JsonObject mcMeta = read.getAsJsonObject(); if(mcMeta.has("animation") && mcMeta.get("animation").isJsonObject()) { animationObj = mcMeta.get("animation").getAsJsonObject(); anim = new TextureAnimation(); } } if(anim != null && animationObj != null) { int frametime = 1; if(animationObj.has("frametime") && animationObj.get("frametime").isJsonPrimitive()) { frametime = animationObj.get("frametime").getAsInt(); } anim.setFrameTime(frametime); if(animationObj.has("interpolate") && animationObj.get("interpolate").isJsonPrimitive()) { boolean interpolate = animationObj.get("interpolate").getAsBoolean(); anim.setInterpolate(interpolate); } if(animationObj.has("frames") && animationObj.get("frames").isJsonArray()) { JsonArray frames = animationObj.get("frames").getAsJsonArray(); if(frames.size() > 0) { List frameList = new ArrayList<>(); Map customTimes = new HashMap<>(); for(int i = 0; i < frames.size(); i++) { JsonElement frame = frames.get(i); int index = 0; int time = frametime; if(frame.isJsonPrimitive()) { index = frame.getAsInt(); } else if(frame.isJsonObject()) { JsonObject frameObj = frame.getAsJsonObject(); if(frameObj.has("index") && frameObj.get("index").isJsonPrimitive()) { index = frameObj.get("index").getAsInt(); } if(frameObj.has("time") && frameObj.get("time").isJsonPrimitive()) { time = frameObj.get("time").getAsInt(); } } frameList.add(index); if(time != frametime) { customTimes.put(frameList.size() - 1, time); } } anim.setFrames(frameList); anim.setCustomTimes(customTimes); } } else { int columns = width / 16; List frameList = new ArrayList<>(); for(int i = 0; i < (height / 16) * columns; i++) { frameList.add(i); } anim.setFrames(frameList); } return anim; } } } catch(FileNotFoundException e) { e.printStackTrace(); } return null; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/texture/TextureAtlas.java ================================================ package com.mrcrayfish.modelcreator.texture; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.newdawn.slick.opengl.Texture; import org.newdawn.slick.util.BufferedImageUtil; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.net.URL; import java.nio.ByteBuffer; /** * Author: MrCrayfish */ public class TextureAtlas { private static final int ATLAS_WIDTH = 1024; private static final int ATLAS_HEIGHT = 1024; private static int atlasTextureId; public static final Entry GUI_SLOT; public static final Entry FIRST_PERSON_PREVIEW; static { GUI_SLOT = new Entry(0, 0, 20, 20); FIRST_PERSON_PREVIEW = new Entry(0, 20, 512, 288); } public static void load() { try { URL url = TextureAtlas.class.getClassLoader().getResource("atlas.png"); if(url != null) { BufferedImage bufferedImage = ImageIO.read(url); atlasTextureId = loadTexture(bufferedImage); } } catch(Exception e) { e.printStackTrace(); } } public static void bind() { GL11.glBindTexture(GL11.GL_TEXTURE_2D, atlasTextureId); } public static class Entry { int u, v; int width, height; private Entry(int u, int v, int width, int height) { this.u = u; this.v = v; this.width = width; this.height = height; } public double getU() { return u / (double) ATLAS_WIDTH; } public double getV() { return v / (double) ATLAS_HEIGHT; } public double getWidth() { return width / (double) ATLAS_WIDTH; } public double getHeight() { return height / (double) ATLAS_HEIGHT; } } private static int loadTexture(BufferedImage image) { int[] pixels = new int[image.getWidth() * image.getHeight()]; image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth()); ByteBuffer buffer = BufferUtils.createByteBuffer(pixels.length * 4); for(int y = 0; y < image.getHeight(); y++) { for(int x = 0; x < image.getWidth(); x++) { int pixel = pixels[y * image.getWidth() + x]; buffer.put((byte) ((pixel >> 16) & 0xFF)); buffer.put((byte) ((pixel >> 8) & 0xFF)); buffer.put((byte) (pixel & 0xFF)); buffer.put((byte) ((pixel >> 24) & 0xFF)); } } buffer.flip(); int textureId = GL11.glGenTextures(); GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); return textureId; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/texture/TextureEntry.java ================================================ package com.mrcrayfish.modelcreator.texture; import com.mrcrayfish.modelcreator.TexturePath; import com.mrcrayfish.modelcreator.component.TextureManager; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Pattern; public class TextureEntry { public static final Pattern KEY_PATTERN = Pattern.compile("[a-z_0-9]+"); private String key; private TexturePath path; private BufferedImage source; private ImageIcon icon; private List textures; private File textureFile; private File metaFile; private TextureAnimation anim; public TextureEntry(File texture) throws IOException { this.path = new TexturePath(texture); this.key = path.getName(); this.textureFile = texture; this.source = ImageIO.read(texture); this.anim = TextureAnimation.getAnimationForTexture(texture, this.source.getWidth(), this.source.getHeight()); this.icon = createIcon(this.source); File metaFile = new File(texture.getAbsolutePath() + ".mcmeta"); if(metaFile.exists()) { this.metaFile = metaFile; } } public TextureEntry(String key, File texture) throws IOException { this.key = key; this.path = new TexturePath(texture); this.textureFile = texture; this.source = ImageIO.read(texture); this.anim = TextureAnimation.getAnimationForTexture(texture, this.source.getWidth(), this.source.getHeight()); this.icon = createIcon(this.source); File metaFile = new File(texture.getAbsolutePath() + ".mcmeta"); if(metaFile.exists()) { this.metaFile = metaFile; } } public TextureEntry(String key, TexturePath path, File texture) throws IOException { this.key = key; this.path = path; this.textureFile = texture; this.source = ImageIO.read(texture); this.anim = TextureAnimation.getAnimationForTexture(texture, this.source.getWidth(), this.source.getHeight()); this.icon = createIcon(this.source); File metaFile = new File(texture.getAbsolutePath() + ".mcmeta"); if(metaFile.exists()) { this.metaFile = metaFile; } } public void setTexturePath(TexturePath path) { this.path = path; } public TexturePath getTexturePath() { return path; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getModId() { return path.getModId(); } public String getDirectory() { return path.getDirectory(); } public String getName() { return path.getName(); } public void bindTexture() { if(textures != null) { GL11.glBindTexture(GL11.GL_TEXTURE_2D, textures.get(this.isAnimated() ? anim.getCurrentAnimationFrame() : 0)); } } public void bindNextTexture() { if(textures != null) { GL11.glBindTexture(GL11.GL_TEXTURE_2D, textures.get(this.isAnimated() ? anim.getNextAnimationFrame() : 0)); } } public BufferedImage getSource() { return source; } public ImageIcon getIcon() { return icon; } public TextureAnimation getAnimation() { return anim; } public boolean isAnimated() { return anim != null; } public int getPasses() { if(anim != null) { return anim.getPasses(); } return 1; } public File getTextureFile() { return textureFile; } public void setTextureFile(File texture) { try { this.textureFile = texture; this.source = ImageIO.read(texture); this.icon = createIcon(this.source); this.anim = TextureAnimation.getAnimationForTexture(texture, source.getWidth(), source.getHeight()); TextureManager.loadTexture(this); } catch(IOException e) { e.printStackTrace(); } } public void deleteTexture() { if(textures != null) { for(int i : textures) { GL11.glDeleteTextures(i); } textures = null; } } private static ImageIcon createIcon(BufferedImage source) { source = source.getSubimage(0, 0, source.getWidth(), source.getWidth()); Image scaledImage = source.getScaledInstance(64, 64, java.awt.Image.SCALE_FAST); return new ImageIcon(scaledImage); } public void loadTexture() { if(textures == null) { if(anim == null) { this.textures = Collections.singletonList(loadTexture(source)); } else { List textures = new ArrayList<>(); int width = anim.getWidth(); int height = anim.getHeight(); int x = 0; while(x + width <= source.getWidth()) { int y = 0; while(y + height <= source.getHeight()) { BufferedImage subImage = source.getSubimage(x, y, width, height); textures.add(loadTexture(subImage)); y += height; } x += width; } this.textures = textures; } } } private int loadTexture(BufferedImage image) { int[] pixels = new int[image.getWidth() * image.getHeight()]; image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth()); ByteBuffer buffer = BufferUtils.createByteBuffer(pixels.length * 4); for(int y = 0; y < image.getHeight(); y++) { for(int x = 0; x < image.getWidth(); x++) { int pixel = pixels[y * image.getWidth() + x]; buffer.put((byte) ((pixel >> 16) & 0xFF)); buffer.put((byte) ((pixel >> 8) & 0xFF)); buffer.put((byte) (pixel & 0xFF)); buffer.put((byte) ((pixel >> 24) & 0xFF)); } } buffer.flip(); int textureId = GL11.glGenTextures(); GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); return textureId; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/AssetsUtil.java ================================================ package com.mrcrayfish.modelcreator.util; import java.io.File; /** * Author: MrCrayfish */ public class AssetsUtil { public static String getTextureDirectory(File file) { StringBuilder builder = new StringBuilder(); File parent = file; while((parent = parent.getParentFile()) != null) { if(!parent.getName().equals("textures")) { builder.insert(0, parent.getName()).insert(0, "/"); continue; } return builder.length() > 0 ? builder.substring(1, builder.length()) : ""; } return "blocks"; } public static String getModId(File file) { File previous = null; File parent = file; while((parent = parent.getParentFile()) != null) { if(parent.getName().equals("assets")) { break; } previous = parent; } return previous != null && Util.hasFolder(previous, "textures") ? previous.getName() : "minecraft"; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/AtlasRenderUtil.java ================================================ package com.mrcrayfish.modelcreator.util; import com.mrcrayfish.modelcreator.texture.TextureAtlas; import static org.lwjgl.opengl.GL11.*; /** * Author: MrCrayfish */ public class AtlasRenderUtil { private static TextureAtlas.Entry entry; public static void bindTexture(TextureAtlas.Entry entry) { AtlasRenderUtil.entry = entry; } public static void drawQuad(int startX, int startY, int endX, int endY) { TextureAtlas.bind(); glBegin(GL_QUADS); { if(entry != null) { glTexCoord2d(entry.getU(), entry.getV()); } glVertex2f(startX, startY); if(entry != null) { glTexCoord2d(entry.getU() + entry.getWidth(), entry.getV()); } glVertex2f(endX, startY); if(entry != null) { glTexCoord2d(entry.getU() + entry.getWidth(), entry.getV() + entry.getHeight()); } glVertex2f(endX, endY); if(entry != null) { glTexCoord2d(entry.getU(), entry.getV() + entry.getHeight()); } glVertex2f(startX, endY); } glEnd(); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/ComponentUtil.java ================================================ package com.mrcrayfish.modelcreator.util; import com.mrcrayfish.modelcreator.Icons; import com.mrcrayfish.modelcreator.Processor; import javax.swing.*; import javax.swing.filechooser.FileFilter; import java.awt.*; import java.io.File; public class ComponentUtil { public static JRadioButton createRadioButton(String label, String toolTip) { JRadioButton radioButton = new JRadioButton(label); radioButton.setToolTipText(toolTip); radioButton.setIcon(Icons.light_off); radioButton.setRolloverIcon(Icons.light_off); radioButton.setSelectedIcon(Icons.light_on); radioButton.setRolloverSelectedIcon(Icons.light_on); return radioButton; } public static JCheckBox createCheckBox(String text, String tooltip, boolean selected) { JCheckBox checkBox = new JCheckBox(text); checkBox.setToolTipText(tooltip); checkBox.setSelected(selected); checkBox.setIcon(Icons.light_off); checkBox.setRolloverIcon(Icons.light_off); checkBox.setSelectedIcon(Icons.light_on); checkBox.setRolloverSelectedIcon(Icons.light_on); return checkBox; } public static JPanel createDirectorySelector(String label, Component parent, String defaultDir, Processor processor) { SpringLayout layout = new SpringLayout(); JPanel panel = new JPanel(layout); panel.setPreferredSize(new Dimension(100, 24)); JTextField textFieldDestination = new JTextField(); textFieldDestination.setPreferredSize(new Dimension(100, 24)); textFieldDestination.setText(defaultDir); textFieldDestination.setEditable(false); textFieldDestination.setFocusable(false); textFieldDestination.setCaretPosition(0); panel.add(textFieldDestination); JButton btnBrowserDir = new JButton("Browse"); btnBrowserDir.setPreferredSize(new Dimension(80, 24)); btnBrowserDir.setIcon(Icons.load); btnBrowserDir.addActionListener(e -> { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Select a Folder"); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setApproveButtonText("Select"); chooser.setCurrentDirectory(new File(defaultDir)); int returnVal = chooser.showOpenDialog(parent); if(returnVal == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); if(file != null) { if(processor != null) { if(processor.run(file)) { return; } } textFieldDestination.setText(file.getAbsolutePath()); } } }); panel.add(btnBrowserDir); JLabel labelExportDir = new JLabel(label); panel.add(labelExportDir); layout.putConstraint(SpringLayout.NORTH, textFieldDestination, 0, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.WEST, textFieldDestination, 10, SpringLayout.EAST, labelExportDir); layout.putConstraint(SpringLayout.EAST, textFieldDestination, -10, SpringLayout.WEST, btnBrowserDir); layout.putConstraint(SpringLayout.NORTH, labelExportDir, 3, SpringLayout.NORTH, textFieldDestination); layout.putConstraint(SpringLayout.WEST, labelExportDir, 0, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, btnBrowserDir, 0, SpringLayout.NORTH, textFieldDestination); layout.putConstraint(SpringLayout.EAST, btnBrowserDir, 0, SpringLayout.EAST, panel); return panel; } public static JPanel createFileSelector(String label, Component parent, String defaultDir, FileFilter filter, Processor processor) { SpringLayout layout = new SpringLayout(); JPanel panel = new JPanel(layout); panel.setPreferredSize(new Dimension(100, 24)); JTextField textFieldDestination = new JTextField(); textFieldDestination.setPreferredSize(new Dimension(100, 24)); textFieldDestination.setText(defaultDir); textFieldDestination.setEditable(false); textFieldDestination.setFocusable(false); textFieldDestination.setCaretPosition(0); panel.add(textFieldDestination); JButton btnBrowserDir = new JButton("Browse"); btnBrowserDir.setPreferredSize(new Dimension(80, 24)); btnBrowserDir.setIcon(Icons.load); btnBrowserDir.addActionListener(e -> { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Select a File"); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setApproveButtonText("Select"); chooser.setCurrentDirectory(new File(defaultDir)); if(filter != null) { chooser.setFileFilter(filter); } int returnVal = chooser.showOpenDialog(parent); if(returnVal == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); if(file != null) { if(processor != null) { if(processor.run(file)) { return; } } textFieldDestination.setText(file.getAbsolutePath()); } } }); panel.add(btnBrowserDir); JLabel labelExportDir = new JLabel(label); panel.add(labelExportDir); layout.putConstraint(SpringLayout.NORTH, textFieldDestination, 0, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.WEST, textFieldDestination, 10, SpringLayout.EAST, labelExportDir); layout.putConstraint(SpringLayout.EAST, textFieldDestination, -10, SpringLayout.WEST, btnBrowserDir); layout.putConstraint(SpringLayout.NORTH, labelExportDir, 3, SpringLayout.NORTH, textFieldDestination); layout.putConstraint(SpringLayout.WEST, labelExportDir, 0, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, btnBrowserDir, 0, SpringLayout.NORTH, textFieldDestination); layout.putConstraint(SpringLayout.EAST, btnBrowserDir, 0, SpringLayout.EAST, panel); return panel; } public static Rectangle expandRectangle(Rectangle r, int amount) { return new Rectangle(r.x - amount, r.y - amount, r.width + amount * 2, r.height + amount * 2); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/FontManager.java ================================================ package com.mrcrayfish.modelcreator.util; import com.mrcrayfish.modelcreator.ModelCreator; import org.newdawn.slick.Color; import org.newdawn.slick.TrueTypeFont; import java.awt.*; import java.io.InputStream; public enum FontManager { BEBAS_NEUE_20("bebas_neue.otf", 20), BEBAS_NEUE_50("bebas_neue.otf", 50); private TrueTypeFont font; FontManager(String name, float size) { loadFont(name, size); } private void loadFont(String name, float size) { try { InputStream is = ModelCreator.class.getClassLoader().getResourceAsStream(name); Font font = Font.createFont(Font.TRUETYPE_FONT, is); this.font = new TrueTypeFont(font.deriveFont(size), true); } catch(Exception e) { e.printStackTrace(); } } public void drawString(int x, int y, String text, Color color) { font.drawString(x, y, text, color); } public int getWidth(String s) { return font.getWidth(s); } public int getHeight() { return font.getHeight(); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/KeyboardUtil.java ================================================ package com.mrcrayfish.modelcreator.util; import org.lwjgl.input.Keyboard; import javax.swing.*; import java.awt.event.KeyEvent; /** * Author: MrCrayfish */ public class KeyboardUtil { public static String convertKeyStokeToString(KeyStroke keyStroke) { String shortcutText = ""; int modifiers = keyStroke.getModifiers(); if(modifiers > 0) { shortcutText = KeyEvent.getKeyModifiersText(modifiers); shortcutText += "+"; } shortcutText += KeyEvent.getKeyText(keyStroke.getKeyCode()); return shortcutText; } public static boolean isCtrlKeyDown() { if(OperatingSystem.get() == OperatingSystem.MAC) { return Keyboard.isKeyDown(Keyboard.KEY_LMETA) || Keyboard.isKeyDown(Keyboard.KEY_RMETA); } else { return Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL); } } public static boolean isShiftKeyDown() { return Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT); } public static boolean isAltKeyDown() { return Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU); } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/OperatingSystem.java ================================================ package com.mrcrayfish.modelcreator.util; /** * Author: MrCrayfish */ public enum OperatingSystem { WINDOWS, MAC, LINUX, SOLARIS, UNKNOWN; private static final OperatingSystem OS; static { String name = System.getProperty("os.name").toLowerCase(); if(name.contains("win")) { OS = OperatingSystem.WINDOWS; } else if(name.contains("mac")) { OS = OperatingSystem.MAC; } else if(name.contains("solaris")) { OS = OperatingSystem.SOLARIS; } else if(name.contains("sunos")) { OS = OperatingSystem.SOLARIS; } else if(name.contains("linux")) { OS = OperatingSystem.LINUX; } else if(name.contains("unix")) { OS = OperatingSystem.LINUX; } else { OS = OperatingSystem.UNKNOWN; } } public static OperatingSystem get() { return OS; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/Parser.java ================================================ package com.mrcrayfish.modelcreator.util; import com.mrcrayfish.modelcreator.Exporter; import java.text.ParseException; public class Parser { public static double parseDouble(String text, double def) { try { return Exporter.FORMAT.parse(text).doubleValue(); } catch(NumberFormatException | ParseException e) { e.printStackTrace(); } return def; } public static int parseInt(String text, int def) { try { return Integer.parseInt(text); } catch(NumberFormatException e) { e.printStackTrace(); } return def; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/SharedLibraryLoader.java ================================================ package com.mrcrayfish.modelcreator.util; /******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 java.io.*; import java.lang.reflect.Method; import java.util.UUID; import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Loads shared libraries from JAR files. Call {@link SharedLibraryLoader#load() * to load the required LWJGL 3 native shared libraries. * * @author mzechner * @author Nathan Sweet */ public class SharedLibraryLoader { public static final boolean isWindows = System.getProperty("os.name").contains("Windows"); public static final boolean isLinux = System.getProperty("os.name").contains("Linux"); public static final boolean isMac = System.getProperty("os.name").contains("Mac"); public static final boolean is64Bit = System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64"); private static final boolean usingJws; static { if (!isWindows && !isLinux && !isMac) { throw new UnsupportedOperationException("Unknown platform: " + System.getProperty("os.name")); } // Don't extract natives if using JWS. boolean failed = false; try { Method method = Class.forName("javax.jnlp.ServiceManager").getDeclaredMethod("lookup", new Class[] { String.class }); method.invoke(null, "javax.jnlp.PersistenceService"); } catch (Throwable ex) { failed = true; } usingJws = !failed; } /** * Extracts the LWJGL native libraries from the classpath and sets the * "org.lwjgl.librarypath" system property. */ public static synchronized void load(boolean disableOpenAL) { if (usingJws) return; SharedLibraryLoader loader = new SharedLibraryLoader(); File nativesDir = null; try { if (SharedLibraryLoader.isWindows) { nativesDir = loader.extractFile(SharedLibraryLoader.is64Bit ? "lwjgl64.dll" : "lwjgl.dll", null) .getParentFile(); if (!disableOpenAL) loader.extractFile(SharedLibraryLoader.is64Bit ? "OpenAL64.dll" : "OpenAL32.dll", nativesDir.getName()); } else if (SharedLibraryLoader.isMac) { nativesDir = loader.extractFile("liblwjgl.dylib", null).getParentFile(); if (!disableOpenAL) loader.extractFile("openal.dylib", nativesDir.getName()); } else if (SharedLibraryLoader.isLinux) { nativesDir = loader.extractFile(SharedLibraryLoader.is64Bit ? "liblwjgl64.so" : "liblwjgl.so", null) .getParentFile(); if (!disableOpenAL) loader.extractFile(SharedLibraryLoader.is64Bit ? "libopenal64.so" : "libopenal.so", nativesDir.getName()); } else { throw new UnsupportedOperationException("Unknown platform: " + System.getProperty("os.name")); } } catch (Throwable ex) { throw new Error("Unable to extract LWJGL natives.", ex); } System.setProperty("org.lwjgl.librarypath", nativesDir.getAbsolutePath()); } private String nativesJar; private SharedLibraryLoader() { } /** Returns a CRC of the remaining bytes in the stream. */ private String crc(InputStream input) { if (input == null) throw new IllegalArgumentException("input cannot be null."); CRC32 crc = new CRC32(); byte[] buffer = new byte[4096]; try { while (true) { int length = input.read(buffer); if (length == -1) break; crc.update(buffer, 0, length); } } catch (Exception ex) { if (input != null) { try { input.close(); } catch (IOException e) { } } } return Long.toString(crc.getValue(), 16); } private InputStream readFile(String path) { if (nativesJar == null) { InputStream input = SharedLibraryLoader.class.getResourceAsStream("/" + path); if (input == null) throw new RuntimeException("Unable to read file for extraction: " + path); return input; } // Read from JAR. ZipFile file = null; try { file = new ZipFile(nativesJar); ZipEntry entry = file.getEntry(path); if (entry == null) throw new RuntimeException("Couldn't find '" + path + "' in JAR: " + nativesJar); return file.getInputStream(entry); } catch (IOException ex) { throw new RuntimeException("Error reading '" + path + "' in JAR: " + nativesJar, ex); } finally { if (file != null) { try { file.close(); } catch (IOException e) { } } } } /** * Extracts the specified file into the temp directory if it does not already * exist or the CRC does not match. If file extraction fails and the file exists * at java.library.path, that file is returned. * * @param sourcePath The file to extract from the classpath or JAR. * @param dirName The name of the subdirectory where the file will be * extracted. If null, the file's CRC will be used. * @return The extracted file. */ private File extractFile(String sourcePath, String dirName) throws IOException { try { String sourceCrc = crc(readFile(sourcePath)); if (dirName == null) dirName = sourceCrc; File extractedFile = getExtractedFile(dirName, new File(sourcePath).getName()); return extractFile(sourcePath, sourceCrc, extractedFile); } catch (RuntimeException ex) { // Fallback to file at java.library.path location, eg for applets. File file = new File(System.getProperty("java.library.path"), sourcePath); if (file.exists()) return file; throw ex; } } /** * Returns a path to a file that can be written. Tries multiple locations and * verifies writing succeeds. */ private File getExtractedFile(String dirName, String fileName) { // Temp directory with username in path. File idealFile = new File( System.getProperty("java.io.tmpdir") + "/lwjgl" + System.getProperty("user.name") + "/" + dirName, fileName); if (canWrite(idealFile)) return idealFile; // System provided temp directory. try { File file = File.createTempFile(dirName, null); if (file.delete()) { file = new File(file, fileName); if (canWrite(file)) return file; } } catch (IOException ignored) { } // User home. File file = new File(System.getProperty("user.home") + "/.lwjgl/" + dirName, fileName); if (canWrite(file)) return file; // Relative directory. file = new File(".temp/" + dirName, fileName); if (canWrite(file)) return file; return idealFile; // Will likely fail, but we did our best. } /** * Returns true if the parent directories of the file can be created and the * file can be written. */ private boolean canWrite(File file) { File parent = file.getParentFile(); File testFile; if (file.exists()) { if (!file.canWrite() || !canExecute(file)) return false; // Don't overwrite existing file just to check if we can write to directory. testFile = new File(parent, UUID.randomUUID().toString()); } else { parent.mkdirs(); if (!parent.isDirectory()) return false; testFile = file; } try { new FileOutputStream(testFile).close(); if (!canExecute(testFile)) return false; return true; } catch (Throwable ex) { return false; } finally { testFile.delete(); } } private boolean canExecute(File file) { try { if (file.canExecute()) return true; file.setExecutable(true, false); return file.canExecute(); } catch (Exception ignored) { } return false; } private File extractFile(String sourcePath, String sourceCrc, File extractedFile) throws IOException { String extractedCrc = null; if (extractedFile.exists()) { try { extractedCrc = crc(new FileInputStream(extractedFile)); } catch (FileNotFoundException ignored) { } } // If file doesn't exist or the CRC doesn't match, extract it to the temp dir. if (extractedCrc == null || !extractedCrc.equals(sourceCrc)) { try { InputStream input = readFile(sourcePath); extractedFile.getParentFile().mkdirs(); FileOutputStream output = new FileOutputStream(extractedFile); byte[] buffer = new byte[4096]; while (true) { int length = input.read(buffer); if (length == -1) break; output.write(buffer, 0, length); } input.close(); output.close(); } catch (IOException ex) { throw new RuntimeException( "Error extracting file: " + sourcePath + "\nTo: " + extractedFile.getAbsolutePath(), ex); } } return extractedFile; } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/StreamUtils.java ================================================ package com.mrcrayfish.modelcreator.util; import java.io.*; public class StreamUtils { public static String convertToString(InputStream inputStream) throws IOException { if(inputStream != null) { Writer writer = new StringWriter(); char[] buffer = new char[1024]; try { Reader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 1024); int n; while((n = reader.read(buffer)) != -1) { writer.write(buffer, 0, n); } } finally { inputStream.close(); } return writer.toString(); } else { return ""; } } } ================================================ FILE: src/main/java/com/mrcrayfish/modelcreator/util/Util.java ================================================ package com.mrcrayfish.modelcreator.util; import com.google.gson.Gson; import com.mrcrayfish.modelcreator.ProjectManager; import com.mrcrayfish.modelcreator.element.ElementManager; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.FileImageInputStream; import javax.imageio.stream.ImageInputStream; import javax.swing.*; import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.*; import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.function.Predicate; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; public class Util { private static final List minecraftVersions; static { List versionList = new ArrayList<>(); File file = getMinecraftDirectory(); if(file != null && file.exists() && file.isDirectory()) { File versions = null; for(File folder : getSubFolders(file)) { if(folder.getName().equals("versions")) { versions = folder; break; } } if(versions != null) { for(File folder : getSubFolders(versions)) { File json = getFile(folder, folder.getName() + ".json"); if(json != null && !isLegacyAssets(json)) { if(hasFile(folder, folder.getName() + ".jar")) { versionList.add(folder.getName()); } } } } } minecraftVersions = versionList; } public static List getMinecraftVersions() { return minecraftVersions; } public static Dimension getImageDimension(File image) throws IOException { int pos = image.getName().lastIndexOf("."); if(pos != -1) { String suffix = image.getName().substring(pos + 1); Iterator it = ImageIO.getImageReadersBySuffix(suffix); while(it.hasNext()) { ImageReader reader = it.next(); try { ImageInputStream stream = new FileImageInputStream(image); reader.setInput(stream); int width = reader.getWidth(reader.getMinIndex()); int height = reader.getHeight(reader.getMinIndex()); stream.flush(); stream.close(); return new Dimension(width, height); } catch(IOException e) { e.printStackTrace(); } finally { reader.dispose(); } } } throw new IOException("Not a known image file: " + image.getAbsolutePath()); } public static void openUrl(String url) { Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; if(desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { try { desktop.browse(new URL(url).toURI()); } catch(Exception e) { e.printStackTrace(); } } } public static void loadModelFromJar(ElementManager manager, Class clazz, String name) { try { InputStream is = clazz.getClassLoader().getResourceAsStream(name + ".model"); File file = File.createTempFile(name + ".model", ""); FileOutputStream fos = new FileOutputStream(file); byte[] buffer = new byte[1024]; int len; while((len = is.read(buffer)) > 0) { fos.write(buffer, 0, len); } fos.close(); is.close(); ProjectManager.loadProject(manager, file.getAbsolutePath()); file.delete(); } catch(IOException e) { e.printStackTrace(); } } public static void extractMinecraftAssets(String version, Window window) { JFileChooser chooser = new JFileChooser(); chooser.setDialogTitle("Extract Destination"); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setApproveButtonText("Select"); int returnVal = chooser.showOpenDialog(window); if(returnVal == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); if(file.isDirectory()) { File extractionFolder = new File(file, version); File jar = new File(getMinecraftDirectory(), "versions/" + version + "/" + version + ".jar"); extractZipFiles(jar, zipEntry -> zipEntry.getName().startsWith("assets/"), window, extractionFolder); } } } private static void extractZipFiles(File zipFile, Predicate conditions, Window window, File extractionFolder) { final boolean[] cancelled = {false}; JDialog dialog = new JDialog(window, "Extracting Assets", Dialog.ModalityType.APPLICATION_MODAL); dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { cancelled[0] = true; } }); SpringLayout layout = new SpringLayout(); JPanel panel = new JPanel(layout); panel.setPreferredSize(new Dimension(300, 60)); dialog.add(panel); JLabel labelProcessing = new JLabel("Processing"); panel.add(labelProcessing); JLabel labelFile = new JLabel(); panel.add(labelFile); JProgressBar progressBar = new JProgressBar(); progressBar.setForeground(new Color(129, 192, 0)); panel.add(progressBar); layout.putConstraint(SpringLayout.NORTH, labelProcessing, 10, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.WEST, labelProcessing, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.NORTH, labelFile, 10, SpringLayout.NORTH, panel); layout.putConstraint(SpringLayout.WEST, labelFile, 5, SpringLayout.EAST, labelProcessing); layout.putConstraint(SpringLayout.EAST, labelFile, -10, SpringLayout.EAST, panel); layout.putConstraint(SpringLayout.NORTH, progressBar, 10, SpringLayout.SOUTH, labelProcessing); layout.putConstraint(SpringLayout.WEST, progressBar, 10, SpringLayout.WEST, panel); layout.putConstraint(SpringLayout.EAST, progressBar, -10, SpringLayout.EAST, panel); dialog.pack(); dialog.setResizable(false); dialog.setLocationRelativeTo(null); new Thread(() -> { List entries = new ArrayList<>(); try { ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile)); ZipEntry ze; while((ze = zis.getNextEntry()) != null) { if(cancelled[0]) { return; } if(conditions != null && !conditions.test(ze)) { continue; } entries.add(ze); } zis.closeEntry(); zis.close(); } catch(IOException e) { e.printStackTrace(); } if(entries.size() > 0) { SwingUtilities.invokeLater(() -> progressBar.setMaximum(entries.size())); } if(cancelled[0]) { return; } try { ZipFile f = new ZipFile(zipFile); for(int i = 0; i < entries.size(); i++) { if(cancelled[0]) { return; } ZipEntry entry = entries.get(i); SwingUtilities.invokeLater(() -> labelFile.setText(entry.getName())); InputStream is = f.getInputStream(entry); File file = new File(extractionFolder, entry.getName()); file.getParentFile().mkdirs(); file.createNewFile(); byte[] buffer = new byte[8192]; FileOutputStream fos = new FileOutputStream(file); int len; while((len = is.read(buffer)) > 0) { fos.write(buffer, 0, len); } fos.close(); final int value = i; SwingUtilities.invokeLater(() -> progressBar.setValue(value + 1)); } SwingUtilities.invokeLater(window::dispose); } catch(IOException e) { e.printStackTrace(); } }).start(); dialog.setVisible(true); } public static File getMinecraftDirectory() { String userHome = System.getProperty("user.home", "."); OperatingSystem os = OperatingSystem.get(); switch(os) { case WINDOWS: String appDataDir = System.getenv("APPDATA"); if(appDataDir != null) { return new File(appDataDir, ".minecraft"); } case MAC: return new File(userHome, "Library/Application Support/minecraft"); case LINUX: return new File(userHome, ".minecraft"); default: return null; } } private static File[] getSubFolders(File parent) { return parent.listFiles((dir, name) -> dir.isDirectory()); } private static boolean hasFile(File parent, String targetName) { File[] files = parent.listFiles((dir, name) -> name.equals(targetName)); return files != null && files.length == 1; } private static File getFile(File parent, String targetName) { File[] files = parent.listFiles((dir, name) -> name.equals(targetName)); if(files != null) { return Arrays.stream(files).filter(file -> !file.isDirectory() && file.getName().equals(targetName)).findFirst().orElse(null); } return null; } public static boolean hasFolder(File parent, String targetName) { File[] files = parent.listFiles((dir, name) -> name.equals(targetName)); return files != null && Arrays.stream(files).anyMatch(File::isDirectory); } private static boolean isLegacyAssets(File file) { try { String json = new String(Files.readAllBytes(Paths.get(file.getAbsolutePath()))); Gson gson = new Gson(); VersionProperties properties = gson.fromJson(json, VersionProperties.class); return properties != null && properties.assetIndex != null && "legacy".equals(properties.assetIndex.id); } catch(IOException e) { e.printStackTrace(); } return false; } private static class VersionProperties { public AssetIndex assetIndex; } private static class AssetIndex { private String id; } }