├── src └── main │ ├── resources │ ├── atlas.png │ ├── remove.png │ ├── duplicate.png │ ├── icons │ │ ├── add.png │ │ ├── bin.png │ │ ├── new.png │ │ ├── bin2.png │ │ ├── coin.png │ │ ├── copy.png │ │ ├── cube.png │ │ ├── disk.png │ │ ├── edit.png │ │ ├── exit.png │ │ ├── imgur.png │ │ ├── java.png │ │ ├── load.png │ │ ├── paste.png │ │ ├── redo.png │ │ ├── undo.png │ │ ├── arrow_up.png │ │ ├── bin_open.png │ │ ├── box_off.png │ │ ├── box_on.png │ │ ├── cancel.png │ │ ├── export.png │ │ ├── extract.png │ │ ├── facebook.png │ │ ├── gallery.png │ │ ├── github.png │ │ ├── import.png │ │ ├── mojang.png │ │ ├── optimize.png │ │ ├── patreon.png │ │ ├── reddit.png │ │ ├── refresh.png │ │ ├── rotate.png │ │ ├── settings.png │ │ ├── texture.png │ │ ├── twitter.png │ │ ├── arrow_down.png │ │ ├── clipboard.png │ │ ├── copy_small.png │ │ ├── edit_image.png │ │ ├── add_rollover.png │ │ ├── clear_texture.png │ │ ├── model_chair.png │ │ ├── paste_texture.png │ │ ├── set │ │ │ ├── icon_128x.png │ │ │ ├── icon_16x.png │ │ │ ├── icon_32x.png │ │ │ └── icon_64x.png │ │ ├── transparent.png │ │ ├── minecraft_forum.png │ │ ├── model_cauldron.png │ │ ├── planet_minecraft.png │ │ ├── rotate_clockwise.png │ │ └── rotate_anticlockwise.png │ ├── sticker.png │ ├── bebas_neue.otf │ ├── remove_rollover.png │ ├── duplicate_rollover.png │ └── models │ │ ├── cauldron.model │ │ └── modern_chair.model │ └── java │ └── com │ └── mrcrayfish │ └── modelcreator │ ├── screenshot │ ├── ScreenshotCallback.java │ ├── PendingScreenshot.java │ ├── Uploader.java │ └── Screenshot.java │ ├── panels │ ├── IElementUpdater.java │ ├── CuboidTabbedPane.java │ ├── tabs │ │ ├── ElementPanel.java │ │ ├── FacePanel.java │ │ └── RotationPanel.java │ ├── ElementExtraPanel.java │ ├── GlobalPanel.java │ ├── TexturePanel.java │ └── FaceExtrasPanel.java │ ├── Processor.java │ ├── object │ └── FaceDimension.java │ ├── texture │ ├── Clipboard.java │ ├── TextureAtlas.java │ ├── TextureEntry.java │ └── TextureAnimation.java │ ├── component │ ├── MenuAdapter.java │ ├── JElementList.java │ └── DisplayPropertiesDialog.java │ ├── Constants.java │ ├── Animation.java │ ├── PropertyIdentifiers.java │ ├── element │ ├── ElementCellRenderer.java │ ├── ElementManager.java │ ├── ElementManagerState.java │ └── ElementCellEntry.java │ ├── display │ ├── CanvasRenderer.java │ ├── render │ │ ├── DisplayPropertyRenderer.java │ │ ├── GroundPropertyRenderer.java │ │ ├── GuiPropertyRenderer.java │ │ ├── FixedPropertyRenderer.java │ │ ├── FirstPersonPropertyRenderer.java │ │ ├── HeadPropertyRenderer.java │ │ ├── ThirdPersonPropertyRenderer.java │ │ └── StandardRenderer.java │ └── DisplayProperties.java │ ├── util │ ├── Parser.java │ ├── StreamUtils.java │ ├── AssetsUtil.java │ ├── OperatingSystem.java │ ├── FontManager.java │ ├── AtlasRenderUtil.java │ ├── KeyboardUtil.java │ ├── ComponentUtil.java │ └── SharedLibraryLoader.java │ ├── sidebar │ └── Sidebar.java │ ├── TexturePath.java │ ├── Start.java │ ├── Exporter.java │ ├── Camera.java │ ├── StateManager.java │ ├── Actions.java │ ├── dialog │ └── WelcomeDialog.java │ ├── Icons.java │ ├── Settings.java │ └── ProjectManager.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── LICENSE ├── .gitignore ├── gradlew.bat └── gradlew /src/main/resources/atlas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/atlas.png -------------------------------------------------------------------------------- /src/main/resources/remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/remove.png -------------------------------------------------------------------------------- /src/main/resources/duplicate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/duplicate.png -------------------------------------------------------------------------------- /src/main/resources/icons/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/add.png -------------------------------------------------------------------------------- /src/main/resources/icons/bin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/bin.png -------------------------------------------------------------------------------- /src/main/resources/icons/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/new.png -------------------------------------------------------------------------------- /src/main/resources/sticker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/sticker.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/bebas_neue.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/bebas_neue.otf -------------------------------------------------------------------------------- /src/main/resources/icons/bin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/bin2.png -------------------------------------------------------------------------------- /src/main/resources/icons/coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/coin.png -------------------------------------------------------------------------------- /src/main/resources/icons/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/copy.png -------------------------------------------------------------------------------- /src/main/resources/icons/cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/cube.png -------------------------------------------------------------------------------- /src/main/resources/icons/disk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/disk.png -------------------------------------------------------------------------------- /src/main/resources/icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/edit.png -------------------------------------------------------------------------------- /src/main/resources/icons/exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/exit.png -------------------------------------------------------------------------------- /src/main/resources/icons/imgur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/imgur.png -------------------------------------------------------------------------------- /src/main/resources/icons/java.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/java.png -------------------------------------------------------------------------------- /src/main/resources/icons/load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/load.png -------------------------------------------------------------------------------- /src/main/resources/icons/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/paste.png -------------------------------------------------------------------------------- /src/main/resources/icons/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/redo.png -------------------------------------------------------------------------------- /src/main/resources/icons/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/undo.png -------------------------------------------------------------------------------- /src/main/resources/icons/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/arrow_up.png -------------------------------------------------------------------------------- /src/main/resources/icons/bin_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/bin_open.png -------------------------------------------------------------------------------- /src/main/resources/icons/box_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/box_off.png -------------------------------------------------------------------------------- /src/main/resources/icons/box_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/box_on.png -------------------------------------------------------------------------------- /src/main/resources/icons/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/cancel.png -------------------------------------------------------------------------------- /src/main/resources/icons/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/export.png -------------------------------------------------------------------------------- /src/main/resources/icons/extract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/extract.png -------------------------------------------------------------------------------- /src/main/resources/icons/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/facebook.png -------------------------------------------------------------------------------- /src/main/resources/icons/gallery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/gallery.png -------------------------------------------------------------------------------- /src/main/resources/icons/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/github.png -------------------------------------------------------------------------------- /src/main/resources/icons/import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/import.png -------------------------------------------------------------------------------- /src/main/resources/icons/mojang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/mojang.png -------------------------------------------------------------------------------- /src/main/resources/icons/optimize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/optimize.png -------------------------------------------------------------------------------- /src/main/resources/icons/patreon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/patreon.png -------------------------------------------------------------------------------- /src/main/resources/icons/reddit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/reddit.png -------------------------------------------------------------------------------- /src/main/resources/icons/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/refresh.png -------------------------------------------------------------------------------- /src/main/resources/icons/rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/rotate.png -------------------------------------------------------------------------------- /src/main/resources/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/settings.png -------------------------------------------------------------------------------- /src/main/resources/icons/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/texture.png -------------------------------------------------------------------------------- /src/main/resources/icons/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/twitter.png -------------------------------------------------------------------------------- /src/main/resources/icons/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/arrow_down.png -------------------------------------------------------------------------------- /src/main/resources/icons/clipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/clipboard.png -------------------------------------------------------------------------------- /src/main/resources/icons/copy_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/copy_small.png -------------------------------------------------------------------------------- /src/main/resources/icons/edit_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/edit_image.png -------------------------------------------------------------------------------- /src/main/resources/remove_rollover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/remove_rollover.png -------------------------------------------------------------------------------- /src/main/resources/duplicate_rollover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/duplicate_rollover.png -------------------------------------------------------------------------------- /src/main/resources/icons/add_rollover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/add_rollover.png -------------------------------------------------------------------------------- /src/main/resources/icons/clear_texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/clear_texture.png -------------------------------------------------------------------------------- /src/main/resources/icons/model_chair.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/model_chair.png -------------------------------------------------------------------------------- /src/main/resources/icons/paste_texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/paste_texture.png -------------------------------------------------------------------------------- /src/main/resources/icons/set/icon_128x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/set/icon_128x.png -------------------------------------------------------------------------------- /src/main/resources/icons/set/icon_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/set/icon_16x.png -------------------------------------------------------------------------------- /src/main/resources/icons/set/icon_32x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/set/icon_32x.png -------------------------------------------------------------------------------- /src/main/resources/icons/set/icon_64x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/set/icon_64x.png -------------------------------------------------------------------------------- /src/main/resources/icons/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/transparent.png -------------------------------------------------------------------------------- /src/main/resources/models/cauldron.model: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/models/cauldron.model -------------------------------------------------------------------------------- /src/main/resources/icons/minecraft_forum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/minecraft_forum.png -------------------------------------------------------------------------------- /src/main/resources/icons/model_cauldron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/model_cauldron.png -------------------------------------------------------------------------------- /src/main/resources/models/modern_chair.model: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/models/modern_chair.model -------------------------------------------------------------------------------- /src/main/resources/icons/planet_minecraft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/planet_minecraft.png -------------------------------------------------------------------------------- /src/main/resources/icons/rotate_clockwise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/rotate_clockwise.png -------------------------------------------------------------------------------- /src/main/resources/icons/rotate_anticlockwise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCrayfish/ModelCreator/HEAD/src/main/resources/icons/rotate_anticlockwise.png -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/screenshot/ScreenshotCallback.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.screenshot; 2 | 3 | import java.io.File; 4 | 5 | public interface ScreenshotCallback 6 | { 7 | void callback(File file); 8 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/panels/IElementUpdater.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.panels; 2 | 3 | import com.mrcrayfish.modelcreator.element.Element; 4 | 5 | public interface IElementUpdater 6 | { 7 | void updateValues(Element cube); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/Processor.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | /** 4 | * Author: MrCrayfish 5 | */ 6 | public interface Processor 7 | { 8 | /** 9 | * Processes the given argument. 10 | * 11 | * @param t the object to process 12 | * @return if the object was processed successfully 13 | */ 14 | boolean run(T t); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/object/FaceDimension.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.object; 2 | 3 | public class FaceDimension 4 | { 5 | private double width, height; 6 | 7 | public FaceDimension(double width, double height) 8 | { 9 | this.width = width; 10 | this.height = height; 11 | } 12 | 13 | public double getWidth() 14 | { 15 | return width; 16 | } 17 | 18 | public double getHeight() 19 | { 20 | return height; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/texture/Clipboard.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.texture; 2 | 3 | import com.mrcrayfish.modelcreator.element.Face; 4 | 5 | public class Clipboard 6 | { 7 | // TODO make it so you can copy and paste certain properties. Eg Copy only texture and tint index, not UV. 8 | private static TextureEntry entry; 9 | 10 | public static void copyTexture(Face face) 11 | { 12 | entry = face.getTexture(); 13 | } 14 | 15 | public static TextureEntry getTexture() 16 | { 17 | return entry; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2016 MrCrayfish 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/component/MenuAdapter.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.component; 2 | 3 | import javax.swing.event.MenuEvent; 4 | import javax.swing.event.MenuListener; 5 | 6 | /** 7 | * Author: MrCrayfish 8 | */ 9 | public abstract class MenuAdapter implements MenuListener 10 | { 11 | @Override 12 | public void menuSelected(MenuEvent e) 13 | { 14 | 15 | } 16 | 17 | @Override 18 | public void menuDeselected(MenuEvent e) 19 | { 20 | 21 | } 22 | 23 | @Override 24 | public void menuCanceled(MenuEvent e) 25 | { 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/Constants.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | public class Constants 4 | { 5 | public static final String NAME = "MrCrayfish's Model Creator"; 6 | public static final String VERSION = "0.7.0"; 7 | 8 | public static final String URL_DONATE = "https://www.patreon.com/mrcrayfish?ty=h"; 9 | public static final String URL_TWITTER = "https://www.twitter.com/MrCraayfish"; 10 | public static final String URL_FACEBOOK = "https://www.facebook.com/MrCrayfish"; 11 | public static final String URL_GITHUB = "https://github.com/MrCrayfish/ModelCreator"; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/screenshot/PendingScreenshot.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.screenshot; 2 | 3 | import java.io.File; 4 | 5 | public class PendingScreenshot 6 | { 7 | private File file = null; 8 | private ScreenshotCallback callback; 9 | 10 | public PendingScreenshot(File file, ScreenshotCallback callback) 11 | { 12 | this.file = file; 13 | this.callback = callback; 14 | } 15 | 16 | public File getFile() 17 | { 18 | return file; 19 | } 20 | 21 | public ScreenshotCallback getCallback() 22 | { 23 | return callback; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/Animation.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | /** 4 | * Author: MrCrayfish 5 | */ 6 | public class Animation 7 | { 8 | private static int counter; 9 | private static float partialTicks; 10 | 11 | public static void tick() 12 | { 13 | Animation.counter++; 14 | } 15 | 16 | public static void setPartialTicks(float partialTicks) 17 | { 18 | Animation.partialTicks = partialTicks; 19 | } 20 | 21 | public static int getCounter() 22 | { 23 | return Animation.counter; 24 | } 25 | 26 | public static float getPartialTicks() 27 | { 28 | return partialTicks; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/PropertyIdentifiers.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | /** 4 | * Author: MrCrayfish 5 | */ 6 | public class PropertyIdentifiers 7 | { 8 | public static final int SIZE_X = 0; 9 | public static final int SIZE_Y = 1; 10 | public static final int SIZE_Z = 2; 11 | public static final int POS_X = 3; 12 | public static final int POS_Y = 4; 13 | public static final int POS_Z = 5; 14 | public static final int ORIGIN_X = 6; 15 | public static final int ORIGIN_Y = 7; 16 | public static final int ORIGIN_Z = 8; 17 | public static final int START_U = 9; 18 | public static final int START_V = 10; 19 | public static final int END_U = 11; 20 | public static final int END_V = 12; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/element/ElementCellRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.element; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | 6 | /** 7 | * Author: MrCrayfish 8 | */ 9 | public class ElementCellRenderer extends DefaultListCellRenderer 10 | { 11 | @Override 12 | public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) 13 | { 14 | ElementCellEntry entry = (ElementCellEntry) value; 15 | JPanel panel = entry.getPanel(); 16 | panel.setBackground(isSelected ? new Color(186, 193, 211) : new Color(234, 234, 242)); 17 | entry.getName().setText(entry.getElement().getName()); 18 | return panel; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/CanvasRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display; 2 | 3 | import com.mrcrayfish.modelcreator.Camera; 4 | import com.mrcrayfish.modelcreator.ModelCreator; 5 | import com.mrcrayfish.modelcreator.element.Element; 6 | import com.mrcrayfish.modelcreator.element.ElementManager; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * Author: MrCrayfish 13 | */ 14 | public abstract class CanvasRenderer 15 | { 16 | protected List elements = new ArrayList<>(); 17 | 18 | public void onInit(Camera camera) {} 19 | 20 | public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) {} 21 | 22 | public void onRenderOverlay(ElementManager manager, Camera camera, ModelCreator creator) {} 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/render/DisplayPropertyRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display.render; 2 | 3 | import com.mrcrayfish.modelcreator.element.Element; 4 | import com.mrcrayfish.modelcreator.element.ElementManager; 5 | 6 | import static org.lwjgl.opengl.GL11.glTranslatef; 7 | 8 | /** 9 | * Author: MrCrayfish 10 | */ 11 | public abstract class DisplayPropertyRenderer extends StandardRenderer 12 | { 13 | @Override 14 | protected void drawElements(ElementManager manager) 15 | { 16 | glTranslatef(-8, 0, -8); 17 | for(int i = 0; i < manager.getElementCount(); i++) 18 | { 19 | Element cube = manager.getElement(i); 20 | if(cube.isVisible()) 21 | { 22 | cube.draw(); 23 | cube.drawExtras(manager); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/util/Parser.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.util; 2 | 3 | import com.mrcrayfish.modelcreator.Exporter; 4 | 5 | import java.text.ParseException; 6 | 7 | public class Parser 8 | { 9 | public static double parseDouble(String text, double def) 10 | { 11 | try 12 | { 13 | return Exporter.FORMAT.parse(text).doubleValue(); 14 | } 15 | catch(NumberFormatException | ParseException e) 16 | { 17 | e.printStackTrace(); 18 | } 19 | return def; 20 | } 21 | 22 | public static int parseInt(String text, int def) 23 | { 24 | try 25 | { 26 | return Integer.parseInt(text); 27 | } 28 | catch(NumberFormatException e) 29 | { 30 | e.printStackTrace(); 31 | } 32 | return def; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/panels/CuboidTabbedPane.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.panels; 2 | 3 | import com.mrcrayfish.modelcreator.element.ElementManager; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | 8 | public class CuboidTabbedPane extends JTabbedPane 9 | { 10 | private ElementManager manager; 11 | 12 | public CuboidTabbedPane(ElementManager manager) 13 | { 14 | this.manager = manager; 15 | } 16 | 17 | public void updateValues() 18 | { 19 | for(int i = 0; i < getTabCount(); i++) 20 | { 21 | Component component = getComponentAt(i); 22 | if(component != null) 23 | { 24 | if(component instanceof IElementUpdater) 25 | { 26 | IElementUpdater updater = (IElementUpdater) component; 27 | updater.updateValues(manager.getSelectedElement()); 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/util/StreamUtils.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.util; 2 | 3 | import java.io.*; 4 | 5 | public class StreamUtils 6 | { 7 | public static String convertToString(InputStream inputStream) throws IOException 8 | { 9 | if(inputStream != null) 10 | { 11 | Writer writer = new StringWriter(); 12 | 13 | char[] buffer = new char[1024]; 14 | try 15 | { 16 | Reader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 1024); 17 | int n; 18 | while((n = reader.read(buffer)) != -1) 19 | { 20 | writer.write(buffer, 0, n); 21 | } 22 | } 23 | finally 24 | { 25 | inputStream.close(); 26 | } 27 | return writer.toString(); 28 | } 29 | else 30 | { 31 | return ""; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | /bin/ 45 | 46 | .project 47 | .classpath 48 | *.classpath 49 | .classpath 50 | test.json 51 | /bin1/ 52 | /bin1/ 53 | out/ 54 | .idea/ 55 | *.iml 56 | src/META-INF/MANIFEST.MF 57 | .metadata/ 58 | /.gradle/ 59 | /build/ 60 | .settings/ 61 | .project 62 | classes/ 63 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/element/ElementManager.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.element; 2 | 3 | import com.mrcrayfish.modelcreator.display.DisplayProperties; 4 | import com.mrcrayfish.modelcreator.texture.TextureEntry; 5 | 6 | import java.util.List; 7 | 8 | public interface ElementManager 9 | { 10 | Element getSelectedElement(); 11 | 12 | void setSelectedElement(int pos); 13 | 14 | List getAllElements(); 15 | 16 | Element getElement(int index); 17 | 18 | int getElementCount(); 19 | 20 | void clearElements(); 21 | 22 | void updateName(); 23 | 24 | void updateValues(); 25 | 26 | boolean getAmbientOcc(); 27 | 28 | void setAmbientOcc(boolean occ); 29 | 30 | void addElement(Element e); 31 | 32 | void setParticle(TextureEntry entry); 33 | 34 | TextureEntry getParticle(); 35 | 36 | void reset(); 37 | 38 | default ElementManagerState createState() 39 | { 40 | return new ElementManagerState(this); 41 | } 42 | 43 | void restoreState(ElementManagerState state); 44 | 45 | void setDisplayProperties(DisplayProperties properties); 46 | 47 | DisplayProperties getDisplayProperties(); 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/util/AssetsUtil.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.util; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * Author: MrCrayfish 7 | */ 8 | public class AssetsUtil 9 | { 10 | public static String getTextureDirectory(File file) 11 | { 12 | StringBuilder builder = new StringBuilder(); 13 | File parent = file; 14 | while((parent = parent.getParentFile()) != null) 15 | { 16 | if(!parent.getName().equals("textures")) 17 | { 18 | builder.insert(0, parent.getName()).insert(0, "/"); 19 | continue; 20 | } 21 | return builder.length() > 0 ? builder.substring(1, builder.length()) : ""; 22 | } 23 | return "blocks"; 24 | } 25 | 26 | public static String getModId(File file) 27 | { 28 | File previous = null; 29 | File parent = file; 30 | while((parent = parent.getParentFile()) != null) 31 | { 32 | if(parent.getName().equals("assets")) 33 | { 34 | break; 35 | } 36 | previous = parent; 37 | } 38 | return previous != null && Util.hasFolder(previous, "textures") ? previous.getName() : "minecraft"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/util/OperatingSystem.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.util; 2 | 3 | /** 4 | * Author: MrCrayfish 5 | */ 6 | public enum OperatingSystem 7 | { 8 | WINDOWS, 9 | MAC, 10 | LINUX, 11 | SOLARIS, 12 | UNKNOWN; 13 | 14 | private static final OperatingSystem OS; 15 | 16 | static 17 | { 18 | String name = System.getProperty("os.name").toLowerCase(); 19 | if(name.contains("win")) 20 | { 21 | OS = OperatingSystem.WINDOWS; 22 | } 23 | else if(name.contains("mac")) 24 | { 25 | OS = OperatingSystem.MAC; 26 | } 27 | else if(name.contains("solaris")) 28 | { 29 | OS = OperatingSystem.SOLARIS; 30 | } 31 | else if(name.contains("sunos")) 32 | { 33 | OS = OperatingSystem.SOLARIS; 34 | } 35 | else if(name.contains("linux")) 36 | { 37 | OS = OperatingSystem.LINUX; 38 | } 39 | else if(name.contains("unix")) 40 | { 41 | OS = OperatingSystem.LINUX; 42 | } 43 | else 44 | { 45 | OS = OperatingSystem.UNKNOWN; 46 | } 47 | } 48 | 49 | public static OperatingSystem get() 50 | { 51 | return OS; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/sidebar/Sidebar.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.sidebar; 2 | 3 | import com.mrcrayfish.modelcreator.util.FontManager; 4 | import org.newdawn.slick.Color; 5 | 6 | import static org.lwjgl.opengl.GL11.*; 7 | 8 | public abstract class Sidebar 9 | { 10 | private String title; 11 | 12 | public Sidebar(String title) 13 | { 14 | this.title = title; 15 | } 16 | 17 | public void draw(int sidebarWidth, int canvasWidth, int canvasHeight, int frameHeight) 18 | { 19 | glColor3f(0.866F, 0.866F, 0.894F); 20 | glBegin(GL_QUADS); 21 | { 22 | glVertex2i(0, 0); 23 | glVertex2i(sidebarWidth, 0); 24 | glVertex2i(sidebarWidth, canvasHeight); 25 | glVertex2i(0, canvasHeight); 26 | } 27 | glEnd(); 28 | 29 | drawTitle(); 30 | } 31 | 32 | private void drawTitle() 33 | { 34 | glEnable(GL_BLEND); 35 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 36 | FontManager.BEBAS_NEUE_20.drawString(10, 5, title, new Color(0.5F, 0.5F, 0.6F)); 37 | glDisable(GL_BLEND); 38 | } 39 | 40 | public abstract void handleMouseInput(int button, int mouseX, int mouseY, boolean pressed); 41 | 42 | public abstract void handleInput(int canvasHeight); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/element/ElementManagerState.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.element; 2 | 3 | import com.mrcrayfish.modelcreator.texture.TextureEntry; 4 | 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * Author: MrCrayfish 10 | */ 11 | public class ElementManagerState 12 | { 13 | private final List elements; 14 | private final int selectedIndex; 15 | private final boolean ambientOcclusion; 16 | private final TextureEntry particleTexture; 17 | 18 | public ElementManagerState(ElementManager manager) 19 | { 20 | this.elements = manager.getAllElements().stream().map(Element::new).collect(Collectors.toList()); 21 | this.selectedIndex = manager.getAllElements().indexOf(manager.getSelectedElement()); 22 | this.ambientOcclusion = manager.getAmbientOcc(); 23 | this.particleTexture = manager.getParticle(); 24 | } 25 | 26 | public List getElements() 27 | { 28 | return elements; 29 | } 30 | 31 | public int getSelectedIndex() 32 | { 33 | return selectedIndex; 34 | } 35 | 36 | public boolean isAmbientOcclusion() 37 | { 38 | return ambientOcclusion; 39 | } 40 | 41 | public TextureEntry getParticleTexture() 42 | { 43 | return particleTexture; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/util/FontManager.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.util; 2 | 3 | import com.mrcrayfish.modelcreator.ModelCreator; 4 | import org.newdawn.slick.Color; 5 | import org.newdawn.slick.TrueTypeFont; 6 | 7 | import java.awt.*; 8 | import java.io.InputStream; 9 | 10 | public enum FontManager 11 | { 12 | BEBAS_NEUE_20("bebas_neue.otf", 20), 13 | BEBAS_NEUE_50("bebas_neue.otf", 50); 14 | 15 | private TrueTypeFont font; 16 | 17 | FontManager(String name, float size) 18 | { 19 | loadFont(name, size); 20 | } 21 | 22 | private void loadFont(String name, float size) 23 | { 24 | try 25 | { 26 | InputStream is = ModelCreator.class.getClassLoader().getResourceAsStream(name); 27 | Font font = Font.createFont(Font.TRUETYPE_FONT, is); 28 | this.font = new TrueTypeFont(font.deriveFont(size), true); 29 | 30 | } 31 | catch(Exception e) 32 | { 33 | e.printStackTrace(); 34 | } 35 | } 36 | 37 | public void drawString(int x, int y, String text, Color color) 38 | { 39 | font.drawString(x, y, text, color); 40 | } 41 | 42 | public int getWidth(String s) 43 | { 44 | return font.getWidth(s); 45 | } 46 | 47 | public int getHeight() 48 | { 49 | return font.getHeight(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/util/AtlasRenderUtil.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.util; 2 | 3 | import com.mrcrayfish.modelcreator.texture.TextureAtlas; 4 | 5 | import static org.lwjgl.opengl.GL11.*; 6 | 7 | /** 8 | * Author: MrCrayfish 9 | */ 10 | public class AtlasRenderUtil 11 | { 12 | private static TextureAtlas.Entry entry; 13 | 14 | public static void bindTexture(TextureAtlas.Entry entry) 15 | { 16 | AtlasRenderUtil.entry = entry; 17 | } 18 | 19 | public static void drawQuad(int startX, int startY, int endX, int endY) 20 | { 21 | TextureAtlas.bind(); 22 | glBegin(GL_QUADS); 23 | { 24 | if(entry != null) 25 | { 26 | glTexCoord2d(entry.getU(), entry.getV()); 27 | } 28 | glVertex2f(startX, startY); 29 | if(entry != null) 30 | { 31 | glTexCoord2d(entry.getU() + entry.getWidth(), entry.getV()); 32 | } 33 | glVertex2f(endX, startY); 34 | if(entry != null) 35 | { 36 | glTexCoord2d(entry.getU() + entry.getWidth(), entry.getV() + entry.getHeight()); 37 | } 38 | glVertex2f(endX, endY); 39 | if(entry != null) 40 | { 41 | glTexCoord2d(entry.getU(), entry.getV() + entry.getHeight()); 42 | } 43 | glVertex2f(startX, endY); 44 | } 45 | glEnd(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/util/KeyboardUtil.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.util; 2 | 3 | import org.lwjgl.input.Keyboard; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.KeyEvent; 7 | 8 | /** 9 | * Author: MrCrayfish 10 | */ 11 | public class KeyboardUtil 12 | { 13 | public static String convertKeyStokeToString(KeyStroke keyStroke) 14 | { 15 | String shortcutText = ""; 16 | int modifiers = keyStroke.getModifiers(); 17 | if(modifiers > 0) 18 | { 19 | shortcutText = KeyEvent.getKeyModifiersText(modifiers); 20 | shortcutText += "+"; 21 | } 22 | shortcutText += KeyEvent.getKeyText(keyStroke.getKeyCode()); 23 | return shortcutText; 24 | } 25 | 26 | public static boolean isCtrlKeyDown() 27 | { 28 | if(OperatingSystem.get() == OperatingSystem.MAC) 29 | { 30 | return Keyboard.isKeyDown(Keyboard.KEY_LMETA) || Keyboard.isKeyDown(Keyboard.KEY_RMETA); 31 | } 32 | else 33 | { 34 | return Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL); 35 | } 36 | } 37 | 38 | public static boolean isShiftKeyDown() 39 | { 40 | return Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT); 41 | } 42 | 43 | public static boolean isAltKeyDown() 44 | { 45 | return Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/element/ElementCellEntry.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.element; 2 | 3 | import com.mrcrayfish.modelcreator.Icons; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | 8 | /** 9 | * Author: MrCrayfish 10 | */ 11 | public class ElementCellEntry 12 | { 13 | private Element element; 14 | private JPanel panel; 15 | private JLabel visibility; 16 | private JLabel name; 17 | 18 | public ElementCellEntry(Element element) 19 | { 20 | this.element = element; 21 | this.createPanel(); 22 | } 23 | 24 | private void createPanel() 25 | { 26 | panel = new JPanel(); 27 | panel.setLayout(new FlowLayout(FlowLayout.LEFT)); 28 | 29 | visibility = new JLabel(); 30 | visibility.setIcon(element.isVisible() ? Icons.light_on : Icons.light_off); 31 | panel.add(visibility); 32 | 33 | name = new JLabel(element.getName()); 34 | panel.add(name); 35 | } 36 | 37 | public Element getElement() 38 | { 39 | return element; 40 | } 41 | 42 | public JPanel getPanel() 43 | { 44 | return panel; 45 | } 46 | 47 | public JLabel getVisibility() 48 | { 49 | return visibility; 50 | } 51 | 52 | public JLabel getName() 53 | { 54 | return name; 55 | } 56 | 57 | public void toggleVisibility() 58 | { 59 | element.setVisible(!element.isVisible()); 60 | visibility.setIcon(element.isVisible() ? Icons.light_on : Icons.light_off); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/TexturePath.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | import com.mrcrayfish.modelcreator.util.AssetsUtil; 4 | 5 | import java.io.File; 6 | import java.util.regex.Pattern; 7 | 8 | /** 9 | * Author: MrCrayfish 10 | */ 11 | public class TexturePath 12 | { 13 | public static final Pattern PATTERN = Pattern.compile("([a-z_0-9]+:)?([a-z_0-9]+/)*[a-z_0-9]+"); 14 | 15 | private String modId = "minecraft"; 16 | private String directory; 17 | private String name; 18 | 19 | public TexturePath(String s) 20 | { 21 | String[] split = s.split(":"); 22 | if(split.length == 2) 23 | { 24 | this.modId = split[0]; 25 | } 26 | String assetPath = split[split.length - 1]; 27 | this.directory = assetPath.substring(0, Math.max(0, assetPath.lastIndexOf("/"))); 28 | this.name = assetPath.replace(this.directory, "").substring(1); 29 | } 30 | 31 | public TexturePath(File file) 32 | { 33 | this.modId = AssetsUtil.getModId(file); 34 | this.directory = AssetsUtil.getTextureDirectory(file); 35 | this.name = file.getName().substring(0, file.getName().indexOf(".")); 36 | } 37 | 38 | public String getModId() 39 | { 40 | return modId; 41 | } 42 | 43 | public String getDirectory() 44 | { 45 | return directory; 46 | } 47 | 48 | public String getName() 49 | { 50 | return name; 51 | } 52 | 53 | @Override 54 | public String toString() 55 | { 56 | return modId + ":" + directory + "/" + name; 57 | } 58 | 59 | public String toRelativePath() 60 | { 61 | return modId + File.separator + "textures" + File.separator + directory + File.separator + name + ".png"; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/Start.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | import com.jtattoo.plaf.fast.FastLookAndFeel; 4 | import com.mrcrayfish.modelcreator.util.SharedLibraryLoader; 5 | 6 | import javax.swing.*; 7 | import java.util.Properties; 8 | 9 | public class Start 10 | { 11 | public static void main(String[] args) 12 | { 13 | SharedLibraryLoader.load(false); 14 | 15 | Double version = Double.parseDouble(System.getProperty("java.specification.version")); 16 | if(version < 1.8) 17 | { 18 | JOptionPane.showMessageDialog(null, "You need Java 1.8 or higher to run this program."); 19 | return; 20 | } 21 | 22 | System.setProperty("org.lwjgl.util.Debug", "true"); 23 | 24 | try 25 | { 26 | Properties props = new Properties(); 27 | props.put("logoString", ""); 28 | props.put("centerWindowTitle", "on"); 29 | props.put("buttonBackgroundColor", "127 132 145"); 30 | props.put("buttonForegroundColor", "255 255 255"); 31 | props.put("windowTitleBackgroundColor", "97 102 115"); 32 | props.put("windowTitleForegroundColor", "255 255 255"); 33 | props.put("backgroundColor", "221 221 228"); 34 | props.put("menuBackgroundColor", "221 221 228"); 35 | props.put("controlForegroundColor", "120 120 120"); 36 | props.put("windowBorderColor", "97 102 110"); 37 | FastLookAndFeel.setTheme(props); 38 | UIManager.setLookAndFeel("com.jtattoo.plaf.fast.FastLookAndFeel"); 39 | } 40 | catch(Exception e) 41 | { 42 | e.printStackTrace(); 43 | } 44 | 45 | new ModelCreator(Constants.NAME + " v" + Constants.VERSION); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/panels/tabs/ElementPanel.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.panels.tabs; 2 | 3 | import com.mrcrayfish.modelcreator.ModelCreator; 4 | import com.mrcrayfish.modelcreator.element.Element; 5 | import com.mrcrayfish.modelcreator.element.ElementManager; 6 | import com.mrcrayfish.modelcreator.panels.*; 7 | 8 | import javax.swing.*; 9 | import java.awt.*; 10 | 11 | public class ElementPanel extends JPanel implements IElementUpdater 12 | { 13 | private ElementManager manager; 14 | 15 | private SizePanel panelSize; 16 | private PositionPanel panelPosition; 17 | private ElementExtraPanel panelExtras; 18 | private GlobalPanel panelGlobal; 19 | 20 | public ElementPanel(ElementManager manager) 21 | { 22 | this.manager = manager; 23 | setBackground(ModelCreator.BACKGROUND); 24 | setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 25 | initComponents(); 26 | addComponents(); 27 | } 28 | 29 | private void initComponents() 30 | { 31 | panelSize = new SizePanel(manager); 32 | panelPosition = new PositionPanel(manager); 33 | panelExtras = new ElementExtraPanel(manager); 34 | panelGlobal = new GlobalPanel(manager); 35 | } 36 | 37 | private void addComponents() 38 | { 39 | add(Box.createRigidArea(new Dimension(188, 5))); 40 | add(panelSize); 41 | add(Box.createRigidArea(new Dimension(188, 5))); 42 | add(panelPosition); 43 | add(Box.createRigidArea(new Dimension(188, 5))); 44 | add(panelExtras); 45 | add(Box.createRigidArea(new Dimension(188, 70))); 46 | add(new JSeparator(JSeparator.HORIZONTAL)); 47 | add(panelGlobal); 48 | } 49 | 50 | @Override 51 | public void updateValues(Element cube) 52 | { 53 | panelSize.updateValues(cube); 54 | panelPosition.updateValues(cube); 55 | panelExtras.updateValues(cube); 56 | panelGlobal.updateValues(cube); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/Exporter.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | import com.mrcrayfish.modelcreator.element.ElementManager; 4 | 5 | import java.io.BufferedWriter; 6 | import java.io.File; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.text.DecimalFormat; 10 | import java.text.DecimalFormatSymbols; 11 | 12 | public abstract class Exporter 13 | { 14 | /** 15 | * decimalformatter for rounding 16 | */ 17 | public static final DecimalFormat FORMAT = new DecimalFormat("#.###"); 18 | private static final DecimalFormatSymbols SYMBOLS = new DecimalFormatSymbols(); 19 | 20 | static 21 | { 22 | SYMBOLS.setDecimalSeparator('.'); 23 | FORMAT.setDecimalFormatSymbols(SYMBOLS); 24 | } 25 | 26 | // Model Variables 27 | protected ElementManager manager; 28 | 29 | public Exporter(ElementManager manager) 30 | { 31 | this.manager = manager; 32 | } 33 | 34 | public File export(File file) 35 | { 36 | File path = file.getParentFile(); 37 | if(path.exists() && path.isDirectory()) 38 | { 39 | this.writeFile(file); 40 | } 41 | return file; 42 | } 43 | 44 | protected abstract void write(BufferedWriter writer) throws IOException; 45 | 46 | public File writeFile(File file) 47 | { 48 | try(BufferedWriter writer = new BufferedWriter(new FileWriter(file))) 49 | { 50 | if(!file.exists()) 51 | { 52 | file.createNewFile(); 53 | } 54 | this.write(writer); 55 | return file; 56 | } 57 | catch(IOException e) 58 | { 59 | e.printStackTrace(); 60 | } 61 | return null; 62 | } 63 | 64 | protected String space(int size) 65 | { 66 | StringBuilder builder = new StringBuilder(); 67 | for(int i = 0; i < size; i++) 68 | { 69 | //TODO add setting to export with tabs instead 70 | builder.append(" "); 71 | } 72 | return builder.toString(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/panels/ElementExtraPanel.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.panels; 2 | 3 | import com.mrcrayfish.modelcreator.ModelCreator; 4 | import com.mrcrayfish.modelcreator.StateManager; 5 | import com.mrcrayfish.modelcreator.element.Element; 6 | import com.mrcrayfish.modelcreator.element.ElementManager; 7 | import com.mrcrayfish.modelcreator.util.ComponentUtil; 8 | 9 | import javax.swing.*; 10 | import java.awt.*; 11 | 12 | public class ElementExtraPanel extends JPanel implements IElementUpdater 13 | { 14 | private ElementManager manager; 15 | 16 | private JRadioButton btnShade; 17 | 18 | public ElementExtraPanel(ElementManager manager) 19 | { 20 | this.manager = manager; 21 | this.setBackground(ModelCreator.BACKGROUND); 22 | this.setLayout(new GridLayout(1, 2)); 23 | this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Extras")); 24 | this.setMaximumSize(new Dimension(186, 50)); 25 | this.initComponents(); 26 | this.addComponents(); 27 | } 28 | 29 | private void initComponents() 30 | { 31 | btnShade = ComponentUtil.createRadioButton("Shade", "Determines if shadows should be rendered
Default: On"); 32 | btnShade.setBackground(ModelCreator.BACKGROUND); 33 | btnShade.addActionListener(e -> 34 | { 35 | Element selectedElement = manager.getSelectedElement(); 36 | if(selectedElement != null) 37 | { 38 | selectedElement.setShade(btnShade.isSelected()); 39 | StateManager.pushState(manager); 40 | } 41 | }); 42 | } 43 | 44 | private void addComponents() 45 | { 46 | add(btnShade); 47 | } 48 | 49 | @Override 50 | public void updateValues(Element cube) 51 | { 52 | if(cube != null) 53 | { 54 | btnShade.setEnabled(true); 55 | btnShade.setSelected(cube.isShaded()); 56 | } 57 | else 58 | { 59 | btnShade.setEnabled(false); 60 | btnShade.setSelected(false); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/component/JElementList.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.component; 2 | 3 | import com.mrcrayfish.modelcreator.element.ElementCellEntry; 4 | import com.mrcrayfish.modelcreator.util.ComponentUtil; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.awt.event.MouseEvent; 9 | 10 | /** 11 | * Author: MrCrayfish 12 | */ 13 | public class JElementList extends JList 14 | { 15 | private boolean processInput; 16 | 17 | @Override 18 | protected void processMouseEvent(MouseEvent e) 19 | { 20 | if(e.getID() == MouseEvent.MOUSE_FIRST) 21 | { 22 | return; 23 | } 24 | 25 | if(e.getID() == MouseEvent.MOUSE_RELEASED) 26 | { 27 | processInput = true; 28 | return; 29 | } 30 | 31 | if(!processInput) 32 | { 33 | return; 34 | } 35 | 36 | if(e.getButton() == MouseEvent.BUTTON1) 37 | { 38 | int index = this.locationToIndex(e.getPoint()); 39 | if(index != -1) 40 | { 41 | Rectangle rectangle = this.getCellBounds(index, index); 42 | if(rectangle.contains(e.getPoint())) 43 | { 44 | Point relativePoint = new Point((int) e.getPoint().getX(), (int) (e.getPoint().getY() - rectangle.getY())); 45 | ElementCellEntry entry = this.getModel().getElementAt(index); 46 | Rectangle buttonBounds = ComponentUtil.expandRectangle(entry.getVisibility().getBounds(), 4); 47 | if(buttonBounds.contains(relativePoint)) 48 | { 49 | entry.toggleVisibility(); 50 | this.repaint(); 51 | e.consume(); 52 | processInput = false; 53 | return; 54 | } 55 | } 56 | } 57 | } 58 | 59 | super.processMouseEvent(e); 60 | } 61 | 62 | @Override 63 | protected void processMouseMotionEvent(MouseEvent e) 64 | { 65 | if(processInput) 66 | { 67 | super.processMouseMotionEvent(e); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/screenshot/Uploader.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.screenshot; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | import com.google.gson.JsonParser; 6 | import com.mrcrayfish.modelcreator.util.StreamUtils; 7 | 8 | import java.io.*; 9 | import java.net.HttpURLConnection; 10 | import java.net.URL; 11 | 12 | public class Uploader 13 | { 14 | private static final String UPLOAD_URL = "https://api.imgur.com/3/image"; 15 | private static final String CLIENT_ID = "5cd0235db91ac6e"; 16 | 17 | public static String upload(File file) 18 | { 19 | HttpURLConnection conn; 20 | InputStream responseIn; 21 | 22 | try 23 | { 24 | conn = (HttpURLConnection) new URL(UPLOAD_URL).openConnection(); 25 | conn.setDoOutput(true); 26 | conn.setRequestProperty("Authorization", "Client-ID " + CLIENT_ID); 27 | 28 | OutputStream out = conn.getOutputStream(); 29 | upload(new FileInputStream(file), out); 30 | out.flush(); 31 | out.close(); 32 | 33 | if(conn.getResponseCode() == HttpURLConnection.HTTP_OK) 34 | { 35 | responseIn = conn.getInputStream(); 36 | return getImageLink(responseIn); 37 | } 38 | } 39 | catch(Exception e) 40 | { 41 | e.printStackTrace(); 42 | } 43 | return null; 44 | } 45 | 46 | private static void upload(InputStream input, OutputStream output) throws IOException 47 | { 48 | byte[] buffer = new byte[8192]; 49 | int n; 50 | while((n = input.read(buffer)) != -1) 51 | { 52 | output.write(buffer, 0, n); 53 | } 54 | 55 | } 56 | 57 | private static String getImageLink(InputStream input) throws IOException 58 | { 59 | String json = StreamUtils.convertToString(input); 60 | 61 | JsonParser parser = new JsonParser(); 62 | JsonElement read = parser.parse(json); 63 | 64 | if(read.isJsonObject()) 65 | { 66 | JsonObject obj = read.getAsJsonObject(); 67 | 68 | if(obj.has("data") && obj.get("data").isJsonObject()) 69 | { 70 | JsonObject data = obj.getAsJsonObject("data"); 71 | return "http://imgur.com/" + data.get("id").getAsString(); 72 | } 73 | } 74 | return null; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/panels/GlobalPanel.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.panels; 2 | 3 | import com.mrcrayfish.modelcreator.Icons; 4 | import com.mrcrayfish.modelcreator.ModelCreator; 5 | import com.mrcrayfish.modelcreator.StateManager; 6 | import com.mrcrayfish.modelcreator.component.TextureManager; 7 | import com.mrcrayfish.modelcreator.element.Element; 8 | import com.mrcrayfish.modelcreator.element.ElementManager; 9 | import com.mrcrayfish.modelcreator.texture.TextureEntry; 10 | import com.mrcrayfish.modelcreator.util.ComponentUtil; 11 | 12 | import javax.swing.*; 13 | import java.awt.*; 14 | 15 | public class GlobalPanel extends JPanel implements IElementUpdater 16 | { 17 | private ElementManager manager; 18 | 19 | private JRadioButton ambientOcc; 20 | private JButton btnParticle; 21 | 22 | public GlobalPanel(ElementManager manager) 23 | { 24 | this.manager = manager; 25 | this.setBackground(ModelCreator.BACKGROUND); 26 | this.setLayout(new GridLayout(2, 1, 0, 5)); 27 | this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Global Properties")); 28 | this.setMaximumSize(new Dimension(186, 80)); 29 | this.initComponents(); 30 | this.addComponents(); 31 | } 32 | 33 | private void initComponents() 34 | { 35 | ambientOcc = ComponentUtil.createRadioButton("Ambient Occlusion", "Determine the light for each element"); 36 | ambientOcc.setBackground(ModelCreator.BACKGROUND); 37 | ambientOcc.setSelected(true); 38 | ambientOcc.addActionListener(a -> 39 | { 40 | manager.setAmbientOcc(ambientOcc.isSelected()); 41 | StateManager.pushState(manager); 42 | }); 43 | 44 | btnParticle = new JButton("Particle"); 45 | btnParticle.setIcon(Icons.texture); 46 | btnParticle.addActionListener(a -> 47 | { 48 | TextureEntry entry = TextureManager.display(((SidebarPanel) manager).getCreator(), manager, Dialog.ModalityType.APPLICATION_MODAL); 49 | if(entry != null) 50 | { 51 | manager.setParticle(entry); 52 | btnParticle.setText("#" + entry.getKey()); 53 | StateManager.pushState(manager); 54 | } 55 | }); 56 | } 57 | 58 | private void addComponents() 59 | { 60 | add(ambientOcc); 61 | add(btnParticle); 62 | } 63 | 64 | @Override 65 | public void updateValues(Element cube) 66 | { 67 | ambientOcc.setSelected(manager.getAmbientOcc()); 68 | if(manager.getParticle() == null) 69 | { 70 | btnParticle.setText("Particle"); 71 | } 72 | else 73 | { 74 | btnParticle.setText("#" + manager.getParticle().getKey()); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/render/GroundPropertyRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display.render; 2 | 3 | import com.mrcrayfish.modelcreator.Animation; 4 | import com.mrcrayfish.modelcreator.Camera; 5 | import com.mrcrayfish.modelcreator.ModelCreator; 6 | import com.mrcrayfish.modelcreator.display.DisplayProperties; 7 | import com.mrcrayfish.modelcreator.element.Element; 8 | import com.mrcrayfish.modelcreator.element.ElementManager; 9 | 10 | import static org.lwjgl.opengl.GL11.*; 11 | 12 | /** 13 | * Author: MrCrayfish 14 | */ 15 | public class GroundPropertyRenderer extends DisplayPropertyRenderer 16 | { 17 | public GroundPropertyRenderer() 18 | { 19 | this.addElements(); 20 | } 21 | 22 | private void addElements() 23 | { 24 | Element block = new Element(16, 16, 16); 25 | block.setStartX(-8); 26 | block.setStartY(-16); 27 | block.setStartZ(-8); 28 | elements.add(block); 29 | } 30 | 31 | @Override 32 | public void onInit(Camera camera) 33 | { 34 | camera.setX(0); 35 | camera.setY(0); 36 | camera.setZ(-25); 37 | camera.setRX(20); 38 | camera.setRY(0); 39 | camera.setRZ(0); 40 | } 41 | 42 | @Override 43 | public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) 44 | { 45 | DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry("ground"); 46 | if(entry != null) 47 | { 48 | glMatrixMode(GL_MODELVIEW); 49 | glLoadIdentity(); 50 | glEnable(GL_DEPTH_TEST); 51 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 52 | glLoadIdentity(); 53 | camera.useView(); 54 | 55 | for(Element element : elements) 56 | { 57 | element.drawExtras(manager); 58 | element.draw(); 59 | } 60 | 61 | double yOffset = (Animation.getCounter() + Animation.getCounter()) / 60F; 62 | yOffset = Math.sin(yOffset); 63 | glTranslated(0, (yOffset * 1.5) * entry.getScaleY(), 0); 64 | glRotated((Animation.getCounter() + Animation.getPartialTicks()), 0, 1, 0); 65 | 66 | glTranslated(-entry.getTranslationX(), entry.getTranslationY(), -entry.getTranslationZ()); 67 | glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); 68 | 69 | glTranslated(0, 5.5, 0); 70 | 71 | glRotatef(180F, 0, 1, 0); 72 | glRotatef((float) entry.getRotationX(), 1, 0, 0); 73 | glRotatef((float) entry.getRotationY(), 0, 1, 0); 74 | glRotatef((float) entry.getRotationZ(), 0, 0, 1); 75 | glTranslated(0, -8, 0); 76 | 77 | glPushMatrix(); 78 | { 79 | this.drawGrid(camera, false); 80 | this.drawElements(manager); 81 | } 82 | glPopMatrix(); 83 | 84 | glDisable(GL_DEPTH_TEST); 85 | glDisable(GL_CULL_FACE); 86 | glDisable(GL_TEXTURE_2D); 87 | glDisable(GL_LIGHTING); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/Camera.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | import static org.lwjgl.opengl.GL11.*; 4 | import static org.lwjgl.util.glu.GLU.gluPerspective; 5 | 6 | public class Camera 7 | { 8 | private float x; 9 | private float y; 10 | private float z; 11 | private float rx; 12 | private float ry; 13 | private float rz; 14 | 15 | private float fov; 16 | private float aspect; 17 | private float near; 18 | private float far; 19 | 20 | public Camera(float fov, float aspect, float near, float far) 21 | { 22 | x = 0; 23 | y = 0; 24 | z = -20; 25 | rx = 30F; 26 | ry = 0F; 27 | rz = 0; 28 | 29 | this.fov = fov; 30 | this.aspect = aspect; 31 | this.near = near; 32 | this.far = far; 33 | initProjection(); 34 | } 35 | 36 | private void initProjection() 37 | { 38 | glMatrixMode(GL_PROJECTION); 39 | glLoadIdentity(); 40 | gluPerspective(fov, aspect, near, far); 41 | glMatrixMode(GL_MODELVIEW); 42 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 43 | glEnable(GL_DEPTH_TEST); 44 | } 45 | 46 | public void useView() 47 | { 48 | glTranslatef(x, y, z); 49 | glRotatef(rx, 1, 0, 0); 50 | glRotatef(ry, 0, 1, 0); 51 | glRotatef(rz, 0, 0, 1); 52 | } 53 | 54 | public float getX() 55 | { 56 | return x; 57 | } 58 | 59 | public float getY() 60 | { 61 | return y; 62 | } 63 | 64 | public float getZ() 65 | { 66 | return z; 67 | } 68 | 69 | public void setX(float x) 70 | { 71 | this.x = x; 72 | } 73 | 74 | public void setY(float y) 75 | { 76 | this.y = y; 77 | } 78 | 79 | public void setZ(float z) 80 | { 81 | this.z = z; 82 | } 83 | 84 | public float getRX() 85 | { 86 | return rx; 87 | } 88 | 89 | public float getRY() 90 | { 91 | return ry; 92 | } 93 | 94 | public float getRZ() 95 | { 96 | return rz; 97 | } 98 | 99 | public void setRX(float rx) 100 | { 101 | this.rx = rx; 102 | } 103 | 104 | public void setRY(float ry) 105 | { 106 | this.ry = ry; 107 | } 108 | 109 | public void setRZ(float rz) 110 | { 111 | this.rz = rz; 112 | } 113 | 114 | public void move(float amt, float dir) 115 | { 116 | z += amt * Math.sin(Math.toRadians(ry + 90 * dir)); 117 | x += amt * Math.cos(Math.toRadians(ry + 90 * dir)); 118 | } 119 | 120 | public void addX(float amt) 121 | { 122 | x += amt; 123 | } 124 | 125 | public void addY(float amt) 126 | { 127 | y += amt; 128 | } 129 | 130 | public void addZ(float amt) 131 | { 132 | z += amt; 133 | } 134 | 135 | public void rotateX(float amt) 136 | { 137 | rx = ((rx + amt) % 360); 138 | } 139 | 140 | public void rotateY(float amt) 141 | { 142 | ry = ((ry + amt) % 360); 143 | } 144 | } -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/render/GuiPropertyRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display.render; 2 | 3 | import com.mrcrayfish.modelcreator.Camera; 4 | import com.mrcrayfish.modelcreator.ModelCreator; 5 | import com.mrcrayfish.modelcreator.display.DisplayProperties; 6 | import com.mrcrayfish.modelcreator.element.ElementManager; 7 | import com.mrcrayfish.modelcreator.texture.TextureAtlas; 8 | import com.mrcrayfish.modelcreator.util.AtlasRenderUtil; 9 | import org.lwjgl.opengl.GL11; 10 | 11 | import static org.lwjgl.opengl.GL11.*; 12 | 13 | /** 14 | * Author: MrCrayfish 15 | */ 16 | public class GuiPropertyRenderer extends DisplayPropertyRenderer 17 | { 18 | @Override 19 | public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) {} 20 | 21 | @Override 22 | public void onRenderOverlay(ElementManager manager, Camera camera, ModelCreator creator) 23 | { 24 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 25 | 26 | DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry("gui"); 27 | if(entry != null) 28 | { 29 | int canvasOffset = creator.getCanvasOffset(); 30 | int canvasWidth = creator.getCanvasWidth() - creator.getCanvasOffset(); 31 | int canvasHeight = creator.getCanvasHeight(); 32 | 33 | glViewport(canvasOffset, 0, canvasWidth, canvasHeight); 34 | glMatrixMode(GL_PROJECTION); 35 | glLoadIdentity(); 36 | GL11.glOrtho(canvasOffset, canvasWidth, canvasHeight, 0, 500.0D, -500.0D); 37 | glMatrixMode(GL_MODELVIEW); 38 | glLoadIdentity(); 39 | 40 | glPushMatrix(); 41 | { 42 | TextureAtlas.bind(); 43 | glEnable(GL_TEXTURE_2D); 44 | glEnable(GL_BLEND); 45 | glDisable(GL_CULL_FACE); 46 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 47 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 48 | glColor3f(1.0F, 1.0F, 1.0F); 49 | 50 | int scale = 30; 51 | int slotSize = 16 * scale; 52 | int startX = (canvasWidth - slotSize) / 2; 53 | int startY = (canvasHeight - slotSize) / 2; 54 | 55 | glTranslatef(startX, startY, 0); 56 | glScalef(scale, scale, 0); 57 | 58 | AtlasRenderUtil.bindTexture(TextureAtlas.GUI_SLOT); 59 | AtlasRenderUtil.drawQuad(0, 0, 16, 16); 60 | } 61 | glPopMatrix(); 62 | 63 | glPushMatrix(); 64 | { 65 | int scale = 24; 66 | int startX = canvasWidth / 2; 67 | int startY = canvasHeight / 2; 68 | glTranslatef(startX, startY, 0); 69 | glScaled(scale, scale, scale); 70 | glTranslated(entry.getTranslationX(), -entry.getTranslationY(), entry.getTranslationZ()); 71 | glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); 72 | glRotatef(180F, 1, 0, 0); 73 | glRotatef((float) entry.getRotationX(), 1, 0, 0); 74 | glRotatef((float) entry.getRotationY(), 0, 1, 0); 75 | glRotatef((float) entry.getRotationZ(), 0, 0, 1); 76 | glTranslatef(0, -8, 0); 77 | 78 | glEnable(GL_TEXTURE_2D); 79 | glEnable(GL_DEPTH_TEST); 80 | glEnable(GL_CULL_FACE); 81 | 82 | this.drawElements(manager); 83 | 84 | glDisable(GL_DEPTH_TEST); 85 | glDisable(GL_CULL_FACE); 86 | glDisable(GL_TEXTURE_2D); 87 | } 88 | glPopMatrix(); 89 | 90 | 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/render/FixedPropertyRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display.render; 2 | 3 | import com.mrcrayfish.modelcreator.Camera; 4 | import com.mrcrayfish.modelcreator.ModelCreator; 5 | import com.mrcrayfish.modelcreator.display.DisplayProperties; 6 | import com.mrcrayfish.modelcreator.element.Element; 7 | import com.mrcrayfish.modelcreator.element.ElementManager; 8 | 9 | import static org.lwjgl.opengl.GL11.*; 10 | 11 | /** 12 | * Author: MrCrayfish 13 | */ 14 | public class FixedPropertyRenderer extends DisplayPropertyRenderer 15 | { 16 | public FixedPropertyRenderer() 17 | { 18 | this.addElements(); 19 | } 20 | 21 | private void addElements() 22 | { 23 | Element frameOne = new Element(12, 1, 1); 24 | frameOne.setStartX(-6); 25 | frameOne.setStartY(2); 26 | frameOne.setStartZ(-1); 27 | elements.add(frameOne); 28 | 29 | Element frameTwo = new Element(12, 1, 1); 30 | frameTwo.setStartX(-6); 31 | frameTwo.setStartY(13); 32 | frameTwo.setStartZ(-1); 33 | elements.add(frameTwo); 34 | 35 | Element frameThree = new Element(10, 10, 0.5); 36 | frameThree.setStartX(-5); 37 | frameThree.setStartY(3); 38 | frameThree.setStartZ(-1); 39 | elements.add(frameThree); 40 | 41 | Element frameFour = new Element(1, 10, 1); 42 | frameFour.setStartX(-6); 43 | frameFour.setStartY(3); 44 | frameFour.setStartZ(-1); 45 | elements.add(frameFour); 46 | 47 | Element frameFive = new Element(1, 10, 1); 48 | frameFive.setStartX(5); 49 | frameFive.setStartY(3); 50 | frameFive.setStartZ(-1); 51 | elements.add(frameFive); 52 | } 53 | 54 | @Override 55 | public void onInit(Camera camera) 56 | { 57 | camera.setX(0); 58 | camera.setY(-9); 59 | camera.setZ(-30); 60 | camera.setRX(0); 61 | camera.setRY(0); 62 | camera.setRZ(0); 63 | } 64 | 65 | @Override 66 | public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) 67 | { 68 | DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry("fixed"); 69 | if(entry != null) 70 | { 71 | glMatrixMode(GL_MODELVIEW); 72 | glLoadIdentity(); 73 | glEnable(GL_DEPTH_TEST); 74 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 75 | glLoadIdentity(); 76 | camera.useView(); 77 | 78 | glTranslated(0, -5, 0); 79 | glScalef(1.75F, 1.75F, 1.75F); 80 | 81 | glPushMatrix(); 82 | for(Element element : elements) 83 | { 84 | element.drawExtras(manager); 85 | element.draw(); 86 | } 87 | glPopMatrix(); 88 | 89 | glTranslated(0, 8, 0); 90 | glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); 91 | glRotatef(180F, 0, 1, 0); 92 | glScalef(0.5F, 0.5F, 0.5F); 93 | glTranslated(entry.getTranslationX(), entry.getTranslationY(), entry.getTranslationZ()); 94 | glRotatef((float) entry.getRotationX(), 1, 0, 0); 95 | glRotatef((float) entry.getRotationY(), 0, 1, 0); 96 | glRotatef((float) entry.getRotationZ(), 0, 0, 1); 97 | glTranslated(0, -8, 0); 98 | 99 | glPushMatrix(); 100 | { 101 | this.drawGrid(camera, false); 102 | this.drawElements(manager); 103 | } 104 | glPopMatrix(); 105 | 106 | glDisable(GL_DEPTH_TEST); 107 | glDisable(GL_CULL_FACE); 108 | glDisable(GL_TEXTURE_2D); 109 | glDisable(GL_LIGHTING); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/texture/TextureAtlas.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.texture; 2 | 3 | import org.lwjgl.BufferUtils; 4 | import org.lwjgl.opengl.GL11; 5 | import org.lwjgl.opengl.GL12; 6 | import org.newdawn.slick.opengl.Texture; 7 | import org.newdawn.slick.util.BufferedImageUtil; 8 | 9 | import javax.imageio.ImageIO; 10 | import java.awt.image.BufferedImage; 11 | import java.net.URL; 12 | import java.nio.ByteBuffer; 13 | 14 | /** 15 | * Author: MrCrayfish 16 | */ 17 | public class TextureAtlas 18 | { 19 | private static final int ATLAS_WIDTH = 1024; 20 | private static final int ATLAS_HEIGHT = 1024; 21 | private static int atlasTextureId; 22 | 23 | public static final Entry GUI_SLOT; 24 | public static final Entry FIRST_PERSON_PREVIEW; 25 | 26 | static 27 | { 28 | GUI_SLOT = new Entry(0, 0, 20, 20); 29 | FIRST_PERSON_PREVIEW = new Entry(0, 20, 512, 288); 30 | } 31 | 32 | public static void load() 33 | { 34 | try 35 | { 36 | URL url = TextureAtlas.class.getClassLoader().getResource("atlas.png"); 37 | if(url != null) 38 | { 39 | BufferedImage bufferedImage = ImageIO.read(url); 40 | atlasTextureId = loadTexture(bufferedImage); 41 | } 42 | } 43 | catch(Exception e) 44 | { 45 | e.printStackTrace(); 46 | } 47 | } 48 | 49 | public static void bind() 50 | { 51 | GL11.glBindTexture(GL11.GL_TEXTURE_2D, atlasTextureId); 52 | } 53 | 54 | public static class Entry 55 | { 56 | int u, v; 57 | int width, height; 58 | 59 | private Entry(int u, int v, int width, int height) 60 | { 61 | this.u = u; 62 | this.v = v; 63 | this.width = width; 64 | this.height = height; 65 | } 66 | 67 | public double getU() 68 | { 69 | return u / (double) ATLAS_WIDTH; 70 | } 71 | 72 | public double getV() 73 | { 74 | return v / (double) ATLAS_HEIGHT; 75 | } 76 | 77 | public double getWidth() 78 | { 79 | return width / (double) ATLAS_WIDTH; 80 | } 81 | 82 | public double getHeight() 83 | { 84 | return height / (double) ATLAS_HEIGHT; 85 | } 86 | } 87 | 88 | private static int loadTexture(BufferedImage image) 89 | { 90 | int[] pixels = new int[image.getWidth() * image.getHeight()]; 91 | image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth()); 92 | ByteBuffer buffer = BufferUtils.createByteBuffer(pixels.length * 4); 93 | for(int y = 0; y < image.getHeight(); y++) 94 | { 95 | for(int x = 0; x < image.getWidth(); x++) 96 | { 97 | int pixel = pixels[y * image.getWidth() + x]; 98 | buffer.put((byte) ((pixel >> 16) & 0xFF)); 99 | buffer.put((byte) ((pixel >> 8) & 0xFF)); 100 | buffer.put((byte) (pixel & 0xFF)); 101 | buffer.put((byte) ((pixel >> 24) & 0xFF)); 102 | } 103 | } 104 | buffer.flip(); 105 | int textureId = GL11.glGenTextures(); 106 | GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); 107 | GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); 108 | GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); 109 | GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); 110 | GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); 111 | GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); 112 | return textureId; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/StateManager.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | import com.mrcrayfish.modelcreator.element.ElementManager; 4 | import com.mrcrayfish.modelcreator.element.ElementManagerState; 5 | 6 | import javax.swing.*; 7 | import java.awt.event.ActionListener; 8 | import java.util.Stack; 9 | 10 | /** 11 | * Author: MrCrayfish 12 | */ 13 | public class StateManager 14 | { 15 | /* Undo/Redo Stack */ 16 | private static Stack states = new Stack<>(); 17 | private static int tailIndex = -1; 18 | private static int lastId = -1; 19 | private static Timer timer; 20 | 21 | public static void pushState(ElementManager manager) 22 | { 23 | pushState(manager.createState()); 24 | } 25 | 26 | private static void pushState(ElementManagerState state) 27 | { 28 | if(timer != null && timer.isRunning()) 29 | { 30 | for(ActionListener listener : timer.getActionListeners()) 31 | { 32 | listener.actionPerformed(null); 33 | } 34 | timer.stop(); 35 | timer = null; 36 | } 37 | pushManagerState(state); 38 | } 39 | 40 | private static void pushManagerState(ElementManagerState state) 41 | { 42 | while(tailIndex < states.size() - 1) 43 | { 44 | states.pop(); 45 | } 46 | 47 | if(states.size() >= 50) //Make configurable 48 | { 49 | while(states.size() > 50) 50 | { 51 | states.remove(0); 52 | } 53 | } 54 | states.push(state); 55 | tailIndex = states.size() - 1; 56 | } 57 | 58 | public static void restorePreviousState(ElementManager manager) 59 | { 60 | if(canRestorePreviousState()) 61 | { 62 | ElementManagerState state = states.get(tailIndex - 1); 63 | manager.restoreState(state); 64 | tailIndex--; 65 | } 66 | } 67 | 68 | public static void restoreNextState(ElementManager manager) 69 | { 70 | if(canRestoreNextState()) 71 | { 72 | ElementManagerState state = states.get(tailIndex + 1); 73 | manager.restoreState(state); 74 | tailIndex++; 75 | } 76 | } 77 | 78 | public static boolean canRestorePreviousState() 79 | { 80 | return tailIndex > 0; 81 | } 82 | 83 | public static boolean canRestoreNextState() 84 | { 85 | return tailIndex < states.size() - 1; 86 | } 87 | 88 | public static void clear() 89 | { 90 | if(timer != null && timer.isRunning()) 91 | { 92 | timer.stop(); 93 | timer = null; 94 | } 95 | states.clear(); 96 | tailIndex = -1; 97 | } 98 | 99 | public static Stack getStates() 100 | { 101 | return states; 102 | } 103 | 104 | public static int getTailIndex() 105 | { 106 | return tailIndex; 107 | } 108 | 109 | public static void pushStateDelayed(ElementManager manager, int id) 110 | { 111 | if(lastId != id) 112 | { 113 | if(timer != null && timer.isRunning()) 114 | { 115 | for(ActionListener listener : timer.getActionListeners()) 116 | { 117 | listener.actionPerformed(null); 118 | } 119 | timer.stop(); 120 | } 121 | } 122 | else 123 | { 124 | if(timer != null && timer.isRunning()) 125 | { 126 | timer.stop(); 127 | } 128 | } 129 | 130 | ElementManagerState state = manager.createState(); 131 | ActionListener listener = e -> pushManagerState(state); 132 | timer = new Timer(400, listener); 133 | timer.setRepeats(false); 134 | timer.start(); 135 | lastId = id; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/screenshot/Screenshot.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.screenshot; 2 | 3 | import com.mrcrayfish.modelcreator.util.Util; 4 | import org.lwjgl.BufferUtils; 5 | import org.lwjgl.opengl.GL11; 6 | 7 | import javax.imageio.ImageIO; 8 | import javax.swing.*; 9 | import java.awt.image.BufferedImage; 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.net.URLEncoder; 13 | import java.nio.ByteBuffer; 14 | 15 | public class Screenshot 16 | { 17 | public static void getScreenshot(int width, int height, ScreenshotCallback callback) 18 | { 19 | try 20 | { 21 | getScreenshot(width, height, callback, File.createTempFile("screenshot", ".png")); 22 | } 23 | catch(IOException e) 24 | { 25 | e.printStackTrace(); 26 | } 27 | } 28 | 29 | public static void getScreenshot(int width, int height, ScreenshotCallback callback, File file) 30 | { 31 | GL11.glReadBuffer(GL11.GL_FRONT); 32 | int bpp = 4; 33 | ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp); 34 | GL11.glReadPixels(0, 0, width, height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); 35 | 36 | try 37 | { 38 | String format = "PNG"; 39 | BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 40 | 41 | for(int x = 0; x < width; x++) 42 | { 43 | for(int y = 0; y < height; y++) 44 | { 45 | int i = (x + (width * y)) * bpp; 46 | int r = buffer.get(i) & 0xFF; 47 | int g = buffer.get(i + 1) & 0xFF; 48 | int b = buffer.get(i + 2) & 0xFF; 49 | image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); 50 | } 51 | } 52 | ImageIO.write(image, format, file); 53 | 54 | if(callback != null) 55 | { 56 | callback.callback(file); 57 | } 58 | } 59 | catch(IOException e) 60 | { 61 | e.printStackTrace(); 62 | } 63 | } 64 | 65 | private static boolean isUrl(String url) 66 | { 67 | if(url == null | (url != null && url.equals("null"))) 68 | { 69 | JOptionPane message = new JOptionPane(); 70 | message.setMessage("Failed to upload screenshot. Check your internet connection then try again."); 71 | JDialog dialog = message.createDialog(null, "Error"); 72 | dialog.setLocationRelativeTo(null); 73 | dialog.setModal(false); 74 | dialog.setVisible(true); 75 | return false; 76 | } 77 | return true; 78 | } 79 | 80 | public static void shareToFacebook(String link) 81 | { 82 | try 83 | { 84 | if(isUrl(link)) 85 | { 86 | String url = "https://www.facebook.com/sharer/sharer.php?"; 87 | url += "u=" + URLEncoder.encode(link, "UTF-8"); 88 | Util.openUrl(url); 89 | } 90 | } 91 | catch(Exception e) 92 | { 93 | e.printStackTrace(); 94 | } 95 | } 96 | 97 | public static void shareToTwitter(String link) 98 | { 99 | try 100 | { 101 | if(isUrl(link)) 102 | { 103 | String url = "https://twitter.com/intent/tweet?"; 104 | url += "text=" + URLEncoder.encode("Check out this awesome model I created with @MrCraayfish's Model Creator", "UTF-8"); 105 | url += "&url=" + URLEncoder.encode(link, "UTF-8"); 106 | Util.openUrl(url); 107 | } 108 | } 109 | catch(Exception e) 110 | { 111 | e.printStackTrace(); 112 | } 113 | } 114 | 115 | public static void shareToReddit(String link) 116 | { 117 | try 118 | { 119 | if(isUrl(link)) 120 | { 121 | String url = "http://www.reddit.com/r/Minecraft/submit?"; 122 | url += "title=" + URLEncoder.encode("[Model] (Created using MrCrayfish's Model Creator)", "UTF-8"); 123 | url += "&url=" + URLEncoder.encode(link, "UTF-8"); 124 | Util.openUrl(url); 125 | } 126 | } 127 | catch(Exception e) 128 | { 129 | e.printStackTrace(); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/render/FirstPersonPropertyRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display.render; 2 | 3 | import com.mrcrayfish.modelcreator.Camera; 4 | import com.mrcrayfish.modelcreator.ModelCreator; 5 | import com.mrcrayfish.modelcreator.display.DisplayProperties; 6 | import com.mrcrayfish.modelcreator.element.ElementManager; 7 | import com.mrcrayfish.modelcreator.texture.TextureAtlas; 8 | import com.mrcrayfish.modelcreator.util.AtlasRenderUtil; 9 | import org.lwjgl.opengl.GL11; 10 | import org.lwjgl.util.glu.GLU; 11 | import org.newdawn.slick.opengl.TextureImpl; 12 | 13 | import static org.lwjgl.opengl.GL11.*; 14 | 15 | /** 16 | * Author: MrCrayfish 17 | */ 18 | public class FirstPersonPropertyRenderer extends DisplayPropertyRenderer 19 | { 20 | private boolean leftHanded; 21 | 22 | public FirstPersonPropertyRenderer(boolean leftHanded) 23 | { 24 | this.leftHanded = leftHanded; 25 | } 26 | 27 | @Override 28 | public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) {} 29 | 30 | @Override 31 | public void onRenderOverlay(ElementManager manager, Camera camera, ModelCreator creator) 32 | { 33 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 34 | 35 | DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry(!leftHanded ? "firstperson_righthand" : "firstperson_lefthand"); 36 | if(entry != null) 37 | { 38 | int canvasOffset = creator.getCanvasOffset(); 39 | int canvasWidth = creator.getCanvasWidth() - creator.getCanvasOffset(); 40 | int canvasHeight = creator.getCanvasHeight(); 41 | 42 | glViewport(canvasOffset, 0, canvasWidth, canvasHeight); 43 | glMatrixMode(GL_PROJECTION); 44 | glLoadIdentity(); 45 | GL11.glOrtho(canvasOffset, canvasWidth, canvasHeight, 0, 500.0D, -500.0D); 46 | glMatrixMode(GL_MODELVIEW); 47 | glLoadIdentity(); 48 | 49 | glPushMatrix(); 50 | 51 | TextureAtlas.bind(); 52 | glEnable(GL_TEXTURE_2D); 53 | glEnable(GL_BLEND); 54 | glDisable(GL_CULL_FACE); 55 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 56 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 57 | glColor3f(1.0F, 1.0F, 1.0F); 58 | 59 | double startX = (canvasWidth - 960) / 2; 60 | double startY = (canvasHeight - 540) / 2; 61 | 62 | glTranslated((int) startX, (int) startY, 0); 63 | AtlasRenderUtil.bindTexture(TextureAtlas.FIRST_PERSON_PREVIEW); 64 | AtlasRenderUtil.drawQuad(0, 0, 960, 540); 65 | 66 | glEnable(GL_SCISSOR_TEST); 67 | glScissor((int) startX, (int) startY, 960, 540); 68 | 69 | glPopMatrix(); 70 | 71 | glPushMatrix(); 72 | { 73 | glViewport((int) startX, (int) startY, 960, 540); 74 | glMatrixMode(GL_PROJECTION); 75 | glLoadIdentity(); 76 | GLU.gluPerspective(-70F, (float) 960 / (float) 540, 0.3F, 1000F); 77 | glMatrixMode(GL_MODELVIEW); 78 | glLoadIdentity(); 79 | glEnable(GL_DEPTH_TEST); 80 | 81 | if(leftHanded) 82 | { 83 | glScaled(-1, 1, 1); 84 | } 85 | 86 | glTranslated(-9, 8.35, -11.5); 87 | glTranslated(-entry.getTranslationX(), -entry.getTranslationY(), entry.getTranslationZ()); 88 | glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); 89 | glRotatef(180F, 1, 0, 0); 90 | glRotatef((float) entry.getRotationX(), 1, 0, 0); 91 | glRotatef((float) entry.getRotationY(), 0, 1, 0); 92 | glRotatef((float) entry.getRotationZ(), 0, 0, 1); 93 | glTranslated(0, -8, 0); 94 | glRotated(180F, 0, 1, 0); 95 | 96 | glEnable(GL_TEXTURE_2D); 97 | glEnable(GL_DEPTH_TEST); 98 | glEnable(GL_CULL_FACE); 99 | 100 | if(leftHanded) 101 | { 102 | glScaled(-1, 1, 1); 103 | glRotatef(180F, 0, 1, 0); 104 | } 105 | this.drawElements(manager); 106 | 107 | glDisable(GL_DEPTH_TEST); 108 | glDisable(GL_CULL_FACE); 109 | glDisable(GL_TEXTURE_2D); 110 | glDisable(GL_SCISSOR_TEST); 111 | } 112 | glPopMatrix(); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/render/HeadPropertyRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display.render; 2 | 3 | import com.mrcrayfish.modelcreator.Camera; 4 | import com.mrcrayfish.modelcreator.ModelCreator; 5 | import com.mrcrayfish.modelcreator.display.DisplayProperties; 6 | import com.mrcrayfish.modelcreator.element.Element; 7 | import com.mrcrayfish.modelcreator.element.ElementManager; 8 | 9 | import static org.lwjgl.opengl.GL11.*; 10 | 11 | /** 12 | * Author: MrCrayfish 13 | */ 14 | public class HeadPropertyRenderer extends DisplayPropertyRenderer 15 | { 16 | public HeadPropertyRenderer() 17 | { 18 | this.addElements(); 19 | } 20 | 21 | private void addElements() 22 | { 23 | Element rightArm = new Element(4, 12, 4); 24 | rightArm.setStartX(-8); 25 | rightArm.setStartY(-12); 26 | rightArm.setStartZ(-2); 27 | rightArm.setOriginX(-6); 28 | rightArm.setOriginY(-2); 29 | rightArm.setOriginZ(0); 30 | rightArm.setRotation(15F); //TODO maybe add option to change 31 | elements.add(rightArm); 32 | 33 | Element leftArm = new Element(4, 12, 4); 34 | leftArm.setStartX(4); 35 | leftArm.setStartY(-12); 36 | leftArm.setStartZ(-2); 37 | leftArm.setOriginX(6); 38 | leftArm.setOriginY(-2); 39 | leftArm.setOriginZ(0); 40 | leftArm.setRotation(-15F); //TODO maybe add option to change 41 | elements.add(leftArm); 42 | 43 | Element body = new Element(8, 12, 4); 44 | body.setStartX(-4); 45 | body.setStartY(-12); 46 | body.setStartZ(-2); 47 | body.setOriginX(0); 48 | body.setOriginY(0); 49 | body.setOriginZ(0); 50 | elements.add(body); 51 | 52 | Element head = new Element(8, 8, 8); 53 | head.setStartX(-4); 54 | head.setStartY(0); 55 | head.setStartZ(-4); 56 | head.setOriginX(0); 57 | head.setOriginY(0); 58 | head.setOriginZ(0); 59 | elements.add(head); 60 | 61 | Element rightLeg = new Element(4, 12, 4); 62 | rightLeg.setStartX(-4); 63 | rightLeg.setStartY(-24); 64 | rightLeg.setStartZ(-2); 65 | rightLeg.setOriginX(4); 66 | rightLeg.setOriginY(-12); 67 | rightLeg.setOriginZ(0); 68 | rightLeg.setRotation(-15F); 69 | elements.add(rightLeg); 70 | 71 | Element leftLeg = new Element(4, 12, 4); 72 | leftLeg.setStartX(0); 73 | leftLeg.setStartY(-24); 74 | leftLeg.setStartZ(-2); 75 | leftLeg.setOriginX(8); 76 | leftLeg.setOriginX(2); 77 | leftLeg.setOriginY(-12); 78 | leftLeg.setOriginZ(0); 79 | leftLeg.setRotation(15F); 80 | elements.add(leftLeg); 81 | } 82 | 83 | @Override 84 | public void onInit(Camera camera) 85 | { 86 | camera.setX(0); 87 | camera.setY(-5); 88 | camera.setZ(-45); 89 | camera.setRX(10); 90 | camera.setRY(45); 91 | camera.setRZ(0); 92 | } 93 | 94 | @Override 95 | public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) 96 | { 97 | DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry("head"); 98 | if(entry != null) 99 | { 100 | glMatrixMode(GL_MODELVIEW); 101 | glLoadIdentity(); 102 | glEnable(GL_DEPTH_TEST); 103 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 104 | glLoadIdentity(); 105 | camera.useView(); 106 | 107 | glScaled(2.0, 2.0, 2.0); 108 | 109 | for(Element element : elements) 110 | { 111 | element.drawExtras(manager); 112 | element.draw(); 113 | } 114 | 115 | glTranslated(0, 4, 0); 116 | glTranslated(-entry.getTranslationX(), entry.getTranslationY(), -entry.getTranslationZ()); 117 | glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); 118 | glRotatef(180F, 0, 1, 0); 119 | glRotatef((float) entry.getRotationX(), 1, 0, 0); 120 | glRotatef((float) entry.getRotationY(), 0, 1, 0); 121 | glRotatef((float) entry.getRotationZ(), 0, 0, 1); 122 | glTranslated(0, -4, 0); 123 | glScalef(0.625F, 0.625F, 0.625F); 124 | 125 | glPushMatrix(); 126 | { 127 | this.drawGrid(camera, false); 128 | this.drawElements(manager); 129 | } 130 | glPopMatrix(); 131 | 132 | glDisable(GL_DEPTH_TEST); 133 | glDisable(GL_CULL_FACE); 134 | glDisable(GL_TEXTURE_2D); 135 | glDisable(GL_LIGHTING); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/Actions.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | import com.mrcrayfish.modelcreator.element.Element; 4 | import com.mrcrayfish.modelcreator.element.ElementManager; 5 | import com.mrcrayfish.modelcreator.element.Face; 6 | 7 | /** 8 | * Author: MrCrayfish 9 | */ 10 | public class Actions 11 | { 12 | public static int optimiseModel(ElementManager manager) 13 | { 14 | int count = 0; 15 | for(Element element : manager.getAllElements()) 16 | { 17 | for(Face face : element.getAllFaces()) 18 | { 19 | if(face.isEnabled() && !face.isVisible(manager)) 20 | { 21 | count++; 22 | face.setEnabled(false); 23 | } 24 | } 25 | } 26 | if(count > 0) 27 | { 28 | StateManager.pushState(manager); 29 | } 30 | return count; 31 | } 32 | 33 | public static void rotateModel(ElementManager manager, boolean clockwise) 34 | { 35 | manager.getAllElements().forEach(element -> rotateElement(element, clockwise)); 36 | manager.updateValues(); 37 | StateManager.pushState(manager); 38 | } 39 | 40 | private static void rotateElement(Element element, boolean clockwise) 41 | { 42 | /* Calculates and sets the new starting x and y position of the element */ 43 | double newX; 44 | double newZ; 45 | if(clockwise) 46 | { 47 | newX = element.getStartX() - 8 > 0 ? 16 - (element.getDepth() + element.getStartZ()) : 16 - element.getDepth() - element.getStartZ(); 48 | newZ = element.getStartX(); 49 | } 50 | else 51 | { 52 | newX = element.getStartZ(); 53 | newZ = element.getStartZ() - 8 > 0 ? 16 - (element.getWidth() + element.getStartX()) : 16 - element.getWidth() - element.getStartX(); 54 | } 55 | element.setStartX(newX); 56 | element.setStartZ(newZ); 57 | 58 | /* Swaps the width and depth of the element */ 59 | double width = element.getWidth(); 60 | element.setWidth(element.getDepth()); 61 | element.setDepth(width); 62 | 63 | /* Shifts the UVs of horizontal faces to the next target face */ 64 | Face[] faces = element.getAllFaces(); 65 | Face tempFace = new Face(faces[clockwise ? 3 : 0]); 66 | if(clockwise) 67 | { 68 | for(int i = 3; i >= 1; i--) 69 | { 70 | faces[i].copyProperties(faces[i - 1]); 71 | } 72 | } 73 | else 74 | { 75 | for(int i = 0; i < 3; i++) 76 | { 77 | faces[i].copyProperties(faces[i + 1]); 78 | } 79 | } 80 | faces[clockwise ? 0 : 3].copyProperties(tempFace); 81 | 82 | /* Rotates the textures on the top so they match the original when rotated */ 83 | faces[Face.UP].setRotation(getNextFaceRotation(element, Face.UP, clockwise)); 84 | faces[Face.DOWN].setRotation(getNextFaceRotation(element, Face.DOWN, clockwise)); 85 | 86 | /* Rotates the rotation axis. This only applies to horizontal axis */ 87 | if(element.getRotationAxis() == 0) 88 | { 89 | element.setRotationAxis(2); 90 | if(!clockwise) 91 | { 92 | element.setRotation(-element.getRotation()); 93 | } 94 | } 95 | else if(element.getRotationAxis() == 2) 96 | { 97 | element.setRotationAxis(0); 98 | if(clockwise) 99 | { 100 | element.setRotation(-element.getRotation()); 101 | } 102 | } 103 | 104 | /* Rotates the origin starting x and y */ 105 | double newOriginX; 106 | double newOriginZ; 107 | if(clockwise) 108 | { 109 | newOriginX = element.getOriginX() - 8 > 0 ? 16 - element.getOriginZ() : 16 - element.getOriginZ(); 110 | newOriginZ = element.getOriginX(); 111 | } 112 | else 113 | { 114 | newOriginX = element.getOriginZ(); 115 | newOriginZ = element.getOriginZ() - 8 > 0 ? 16 - element.getOriginX() : 16 - element.getOriginX(); 116 | } 117 | element.setOriginX(newOriginX); 118 | element.setOriginZ(newOriginZ); 119 | } 120 | 121 | private static int getNextFaceRotation(Element element, int side, boolean clockwise) 122 | { 123 | Face[] faces = element.getAllFaces(); 124 | if(clockwise) 125 | { 126 | return (faces[side].getRotation() + 1) % 4; 127 | } 128 | else if(faces[side].getRotation() - 1 >= 0) 129 | { 130 | return faces[side].getRotation() - 1; 131 | } 132 | return 3; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/panels/TexturePanel.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.panels; 2 | 3 | import com.mrcrayfish.modelcreator.Icons; 4 | import com.mrcrayfish.modelcreator.ModelCreator; 5 | import com.mrcrayfish.modelcreator.StateManager; 6 | import com.mrcrayfish.modelcreator.component.TextureManager; 7 | import com.mrcrayfish.modelcreator.element.Element; 8 | import com.mrcrayfish.modelcreator.element.ElementManager; 9 | import com.mrcrayfish.modelcreator.element.Face; 10 | import com.mrcrayfish.modelcreator.texture.Clipboard; 11 | import com.mrcrayfish.modelcreator.texture.TextureEntry; 12 | 13 | import javax.swing.*; 14 | import java.awt.*; 15 | import java.awt.event.InputEvent; 16 | 17 | public class TexturePanel extends JPanel 18 | { 19 | private ElementManager manager; 20 | 21 | private JButton btnSelect; 22 | private JButton btnClear; 23 | private JButton btnCopy; 24 | private JButton btnPaste; 25 | 26 | public TexturePanel(ElementManager manager) 27 | { 28 | this.manager = manager; 29 | this.setBackground(ModelCreator.BACKGROUND); 30 | this.setLayout(new GridLayout(2, 2, 4, 4)); 31 | this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Texture")); 32 | this.setMaximumSize(new Dimension(186, 80)); 33 | this.initComponents(); 34 | this.addComponents(); 35 | } 36 | 37 | private void initComponents() 38 | { 39 | btnSelect = new JButton("Select..."); 40 | btnSelect.setIcon(Icons.texture); 41 | btnSelect.addActionListener(e -> 42 | { 43 | Element selectedElement = manager.getSelectedElement(); 44 | if(selectedElement != null) 45 | { 46 | TextureEntry entry = TextureManager.display(((SidebarPanel) manager).getCreator(), manager, Dialog.ModalityType.APPLICATION_MODAL); 47 | if(entry != null) 48 | { 49 | selectedElement.getSelectedFace().setTexture(entry); 50 | StateManager.pushState(manager); 51 | } 52 | } 53 | }); 54 | btnSelect.setToolTipText("Opens the Texture Manager"); 55 | 56 | btnClear = new JButton("Clear"); 57 | btnClear.setIcon(Icons.clear_texture); 58 | btnClear.addActionListener(e -> 59 | { 60 | Element selectedElement = manager.getSelectedElement(); 61 | if(selectedElement != null) 62 | { 63 | if((e.getModifiers() & InputEvent.SHIFT_MASK) == 1) 64 | { 65 | selectedElement.setAllTextures(null); 66 | } 67 | else 68 | { 69 | selectedElement.getSelectedFace().setTexture(null); 70 | } 71 | StateManager.pushState(manager); 72 | } 73 | }); 74 | btnClear.setToolTipText("Clears the texture from this face.
Hold shift to clear all faces"); 75 | 76 | btnCopy = new JButton("Copy"); 77 | btnCopy.setIcon(Icons.copy_small); 78 | btnCopy.addActionListener(e -> 79 | { 80 | Element selectedElement = manager.getSelectedElement(); 81 | if(selectedElement != null) 82 | { 83 | Face face = selectedElement.getSelectedFace(); 84 | Clipboard.copyTexture(face); 85 | } 86 | }); 87 | btnCopy.setToolTipText("Copies the texture on this face to clipboard"); 88 | 89 | btnPaste = new JButton("Paste"); 90 | btnPaste.setIcon(Icons.clipboard_texture); 91 | btnPaste.addActionListener(e -> 92 | { 93 | Element selectedElement = manager.getSelectedElement(); 94 | if(selectedElement != null) 95 | { 96 | TextureEntry entry = Clipboard.getTexture(); 97 | if(entry != null) 98 | { 99 | if((e.getModifiers() & InputEvent.SHIFT_MASK) == 1) 100 | { 101 | selectedElement.setAllTextures(entry); 102 | } 103 | else 104 | { 105 | Face face = selectedElement.getSelectedFace(); 106 | face.setTexture(entry); 107 | } 108 | StateManager.pushState(manager); 109 | } 110 | } 111 | }); 112 | btnPaste.setToolTipText("Pastes the clipboard texture to this face.
Hold shift to paste to all faces"); 113 | } 114 | 115 | private void addComponents() 116 | { 117 | this.add(btnSelect); 118 | this.add(btnClear); 119 | this.add(btnCopy); 120 | this.add(btnPaste); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/dialog/WelcomeDialog.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.dialog; 2 | 3 | import com.mrcrayfish.modelcreator.Constants; 4 | import com.mrcrayfish.modelcreator.Icons; 5 | 6 | import javax.swing.*; 7 | import javax.swing.border.EmptyBorder; 8 | import java.awt.*; 9 | import java.net.URL; 10 | 11 | public class WelcomeDialog 12 | { 13 | public static void show(JFrame parent) 14 | { 15 | JPanel dialogContent = getDialogContent(parent); 16 | JDialog welcomeDialog = getWelcomeDialog(parent, dialogContent); 17 | welcomeDialog.requestFocus(); 18 | welcomeDialog.setAlwaysOnTop(true); 19 | showDialog(welcomeDialog); 20 | } 21 | 22 | private static JPanel getDialogContent(JFrame parent) 23 | { 24 | JPanel container = new JPanel(new BorderLayout(20, 10)); 25 | container.setBorder(new EmptyBorder(10, 10, 10, 10)); 26 | 27 | ImageIcon crayfish = new ImageIcon(parent.getClass().getClassLoader().getResource("sticker.png")); 28 | container.add(new JLabel(crayfish), BorderLayout.EAST); 29 | 30 | JPanel leftPanel = getLeftPanel(); 31 | container.add(leftPanel, BorderLayout.CENTER); 32 | 33 | JPanel btnGrid = getButtonGrid(); 34 | container.add(btnGrid, BorderLayout.SOUTH); 35 | return container; 36 | } 37 | 38 | private static JPanel getLeftPanel() 39 | { 40 | JPanel leftPanel = new JPanel(new BorderLayout()); 41 | 42 | JLabel title = new JLabel("
Model Creator by MrCrayfish
"); 43 | leftPanel.add(title, BorderLayout.NORTH); 44 | 45 | JScrollPane message = getScrollableMessage(); 46 | leftPanel.add(message, BorderLayout.CENTER); 47 | return leftPanel; 48 | } 49 | 50 | private static JScrollPane getScrollableMessage() 51 | { 52 | 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!" + ""; 53 | JTextArea textArea = new JTextArea(message); 54 | textArea.setEditable(false); 55 | textArea.setCursor(null); 56 | textArea.setFocusable(false); 57 | textArea.setBorder(null); 58 | textArea.setOpaque(false); 59 | textArea.setLineWrap(true); 60 | textArea.setWrapStyleWord(true); 61 | 62 | JScrollPane scrollPane = new JScrollPane(textArea); 63 | scrollPane.setBorder(null); 64 | return scrollPane; 65 | } 66 | 67 | private static JPanel getButtonGrid() 68 | { 69 | JPanel btnGrid = new JPanel(new GridLayout(1, 4, 5, 0)); 70 | JButton btnDonate = new JButton("Donate"); 71 | btnDonate.setIcon(Icons.patreon); 72 | btnDonate.addActionListener(a -> openUrl(Constants.URL_DONATE)); 73 | btnGrid.add(btnDonate); 74 | 75 | JButton btnTwitter = new JButton("Twitter"); 76 | btnTwitter.setIcon(Icons.twitter); 77 | btnTwitter.addActionListener(arg0 -> openUrl(Constants.URL_TWITTER)); 78 | btnGrid.add(btnTwitter); 79 | 80 | JButton btnFacebook = new JButton("Facebook"); 81 | btnFacebook.setIcon(Icons.facebook); 82 | btnFacebook.addActionListener(a -> openUrl(Constants.URL_FACEBOOK)); 83 | btnGrid.add(btnFacebook); 84 | 85 | JButton btnClose = new JButton("Close"); 86 | btnClose.addActionListener(a -> SwingUtilities.getWindowAncestor(btnClose).dispose()); 87 | btnGrid.add(btnClose); 88 | return btnGrid; 89 | } 90 | 91 | private static void openUrl(String url) 92 | { 93 | Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; 94 | if(desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) 95 | { 96 | try 97 | { 98 | desktop.browse(new URL(url).toURI()); 99 | } 100 | catch(Exception e) 101 | { 102 | e.printStackTrace(); 103 | } 104 | } 105 | } 106 | 107 | private static JDialog getWelcomeDialog(JFrame parent, JPanel dialogContent) 108 | { 109 | JDialog dialog = new JDialog(parent, "Welcome", Dialog.ModalityType.APPLICATION_MODAL); 110 | dialog.setResizable(false); 111 | dialog.setPreferredSize(new Dimension(500, 290)); 112 | dialog.add(dialogContent); 113 | dialog.pack(); 114 | return dialog; 115 | } 116 | 117 | private static void showDialog(JDialog dialog) 118 | { 119 | dialog.setLocationRelativeTo(null); 120 | dialog.setVisible(true); 121 | dialog.requestFocusInWindow(); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/Icons.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | import javax.swing.*; 4 | 5 | public class Icons 6 | { 7 | public static Icon bin; 8 | public static Icon new_; 9 | public static Icon import_; 10 | public static Icon export; 11 | public static Icon texture; 12 | public static Icon clear_texture; 13 | public static Icon copy; 14 | public static Icon copy_small; 15 | public static Icon clipboard; 16 | public static Icon clipboard_texture; 17 | public static Icon transparent; 18 | public static Icon coin; 19 | public static Icon load; 20 | public static Icon disk; 21 | public static Icon exit; 22 | public static Icon settings; 23 | public static Icon cube; 24 | public static Icon light_off; 25 | public static Icon light_on; 26 | public static Icon arrow_up; 27 | public static Icon arrow_down; 28 | public static Icon facebook; 29 | public static Icon twitter; 30 | public static Icon reddit; 31 | public static Icon imgur; 32 | public static Icon patreon; 33 | public static Icon planet_minecraft; 34 | public static Icon minecraft_forum; 35 | public static Icon github; 36 | public static Icon model_cauldron; 37 | public static Icon model_chair; 38 | public static Icon extract; 39 | public static Icon mojang; 40 | public static Icon java; 41 | public static Icon undo; 42 | public static Icon redo; 43 | public static Icon optimize; 44 | public static Icon rotate; 45 | public static Icon rotate_clockwise; 46 | public static Icon rotate_counter_clockwise; 47 | public static Icon refresh; 48 | public static Icon gallery; 49 | public static Icon bin2; 50 | public static Icon edit; 51 | public static Icon edit_image; 52 | 53 | public static void init(Class clazz) 54 | { 55 | ClassLoader loader = clazz.getClassLoader(); 56 | cube = new ImageIcon(loader.getResource("icons/cube.png")); 57 | bin = new ImageIcon(loader.getResource("icons/bin.png")); 58 | new_ = new ImageIcon(loader.getResource("icons/new.png")); 59 | import_ = new ImageIcon(loader.getResource("icons/import.png")); 60 | export = new ImageIcon(loader.getResource("icons/export.png")); 61 | texture = new ImageIcon(loader.getResource("icons/texture.png")); 62 | clear_texture = new ImageIcon(loader.getResource("icons/clear_texture.png")); 63 | copy = new ImageIcon(loader.getResource("icons/copy.png")); 64 | copy_small = new ImageIcon(loader.getResource("icons/copy_small.png")); 65 | clipboard = new ImageIcon(loader.getResource("icons/clipboard.png")); 66 | clipboard_texture = new ImageIcon(loader.getResource("icons/paste_texture.png")); 67 | transparent = new ImageIcon(loader.getResource("icons/transparent.png")); 68 | coin = new ImageIcon(loader.getResource("icons/coin.png")); 69 | load = new ImageIcon(loader.getResource("icons/load.png")); 70 | disk = new ImageIcon(loader.getResource("icons/disk.png")); 71 | exit = new ImageIcon(loader.getResource("icons/exit.png")); 72 | settings = new ImageIcon(loader.getResource("icons/settings.png")); 73 | extract = new ImageIcon(loader.getResource("icons/extract.png")); 74 | light_off = new ImageIcon(loader.getResource("icons/box_off.png")); 75 | light_on = new ImageIcon(loader.getResource("icons/box_on.png")); 76 | arrow_up = new ImageIcon(loader.getResource("icons/arrow_up.png")); 77 | arrow_down = new ImageIcon(loader.getResource("icons/arrow_down.png")); 78 | facebook = new ImageIcon(loader.getResource("icons/facebook.png")); 79 | twitter = new ImageIcon(loader.getResource("icons/twitter.png")); 80 | reddit = new ImageIcon(loader.getResource("icons/reddit.png")); 81 | imgur = new ImageIcon(loader.getResource("icons/imgur.png")); 82 | patreon = new ImageIcon(loader.getResource("icons/patreon.png")); 83 | planet_minecraft = new ImageIcon(loader.getResource("icons/planet_minecraft.png")); 84 | minecraft_forum = new ImageIcon(loader.getResource("icons/minecraft_forum.png")); 85 | github = new ImageIcon(loader.getResource("icons/github.png")); 86 | model_cauldron = new ImageIcon(loader.getResource("icons/model_cauldron.png")); 87 | model_chair = new ImageIcon(loader.getResource("icons/model_chair.png")); 88 | mojang = new ImageIcon(loader.getResource("icons/mojang.png")); 89 | java = new ImageIcon(loader.getResource("icons/java.png")); 90 | undo = new ImageIcon(loader.getResource("icons/undo.png")); 91 | redo = new ImageIcon(loader.getResource("icons/redo.png")); 92 | optimize = new ImageIcon(loader.getResource("icons/optimize.png")); 93 | rotate = new ImageIcon(loader.getResource("icons/rotate.png")); 94 | rotate_clockwise = new ImageIcon(loader.getResource("icons/rotate_clockwise.png")); 95 | rotate_counter_clockwise = new ImageIcon(loader.getResource("icons/rotate_anticlockwise.png")); 96 | refresh = new ImageIcon(loader.getResource("icons/refresh.png")); 97 | gallery = new ImageIcon(loader.getResource("icons/gallery.png")); 98 | bin2 = new ImageIcon(loader.getResource("icons/bin2.png")); 99 | edit = new ImageIcon(loader.getResource("icons/edit.png")); 100 | edit_image = new ImageIcon(loader.getResource("icons/edit_image.png")); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/render/ThirdPersonPropertyRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display.render; 2 | 3 | import com.mrcrayfish.modelcreator.Camera; 4 | import com.mrcrayfish.modelcreator.ModelCreator; 5 | import com.mrcrayfish.modelcreator.display.DisplayProperties; 6 | import com.mrcrayfish.modelcreator.element.Element; 7 | import com.mrcrayfish.modelcreator.element.ElementManager; 8 | 9 | import static org.lwjgl.opengl.GL11.*; 10 | 11 | /** 12 | * Author: MrCrayfish 13 | */ 14 | public class ThirdPersonPropertyRenderer extends DisplayPropertyRenderer 15 | { 16 | private boolean leftHanded; 17 | 18 | public ThirdPersonPropertyRenderer(boolean leftHanded) 19 | { 20 | this.leftHanded = leftHanded; 21 | this.addElements(); 22 | } 23 | 24 | private void addElements() 25 | { 26 | Element rightArm = new Element(4, 12, 4); 27 | rightArm.setStartX(-2); 28 | rightArm.setStartY(-12); 29 | rightArm.setStartZ(-12); 30 | rightArm.setOriginX(0); 31 | rightArm.setOriginY(-2); 32 | rightArm.setOriginZ(-10); 33 | rightArm.setRotation(-90F); //TODO maybe add option to change 34 | elements.add(rightArm); 35 | 36 | Element leftArm = new Element(4, 12, 4); 37 | leftArm.setStartX(10); 38 | leftArm.setStartY(-12); 39 | leftArm.setStartZ(-12); 40 | leftArm.setOriginX(12); 41 | leftArm.setOriginY(-2); 42 | leftArm.setOriginZ(-10); 43 | leftArm.setRotation(-15F); //TODO maybe add option to change 44 | elements.add(leftArm); 45 | 46 | Element body = new Element(8, 12, 4); 47 | body.setStartX(2); 48 | body.setStartY(-12); 49 | body.setStartZ(-12); 50 | body.setOriginX(0); 51 | body.setOriginY(0); 52 | body.setOriginZ(0); 53 | elements.add(body); 54 | 55 | Element head = new Element(8, 8, 8); 56 | head.setStartX(2); 57 | head.setStartY(0); 58 | head.setStartZ(-14); 59 | head.setOriginX(6); 60 | head.setOriginY(0); 61 | head.setOriginZ(-10); 62 | elements.add(head); 63 | 64 | Element rightLeg = new Element(4, 12, 4); 65 | rightLeg.setStartX(2); 66 | rightLeg.setStartY(-24); 67 | rightLeg.setStartZ(-12); 68 | rightLeg.setOriginX(4); 69 | rightLeg.setOriginY(-12); 70 | rightLeg.setOriginZ(-10); 71 | rightLeg.setRotation(-15F); 72 | elements.add(rightLeg); 73 | 74 | Element leftLeg = new Element(4, 12, 4); 75 | leftLeg.setStartX(6); 76 | leftLeg.setStartY(-24); 77 | leftLeg.setStartZ(-12); 78 | leftLeg.setOriginX(8); 79 | leftLeg.setOriginY(-12); 80 | leftLeg.setOriginZ(-10); 81 | leftLeg.setRotation(15F); 82 | elements.add(leftLeg); 83 | } 84 | 85 | @Override 86 | public void onInit(Camera camera) 87 | { 88 | camera.setX(leftHanded ? -13 : 13); 89 | camera.setY(-5); 90 | camera.setZ(-45); 91 | camera.setRX(10); 92 | camera.setRY(leftHanded ? -90 : 90); 93 | camera.setRZ(0); 94 | } 95 | 96 | @Override 97 | public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) 98 | { 99 | DisplayProperties.Entry entry = creator.getElementManager().getDisplayProperties().getEntry(!leftHanded ? "thirdperson_righthand" : "thirdperson_lefthand"); 100 | if(entry != null) 101 | { 102 | glMatrixMode(GL_MODELVIEW); 103 | glLoadIdentity(); 104 | glEnable(GL_DEPTH_TEST); 105 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 106 | glLoadIdentity(); 107 | camera.useView(); 108 | 109 | glPushMatrix(); 110 | glPushAttrib(0); 111 | { 112 | if(leftHanded) 113 | { 114 | glScaled(-1, 1, 1); 115 | glEnable(GL_CULL_FACE); 116 | glCullFace(GL_FRONT); 117 | } 118 | 119 | glScaled(2.5, 2.5, 2.5); 120 | 121 | for(Element element : elements) 122 | { 123 | element.drawExtras(manager); 124 | element.draw(); 125 | } 126 | 127 | if(leftHanded) 128 | { 129 | glCullFace(GL_BACK); 130 | glDisable(GL_CULL_FACE); 131 | } 132 | 133 | glTranslated(-entry.getTranslationX(), entry.getTranslationY(), -entry.getTranslationZ()); 134 | glScaled(entry.getScaleX(), entry.getScaleY(), entry.getScaleZ()); 135 | glRotatef(180F, 0, 1, 0); 136 | glRotatef((float) entry.getRotationX(), 1, 0, 0); 137 | glRotatef((float) entry.getRotationY(), 0, 1, 0); 138 | glRotatef((float) entry.getRotationZ(), 0, 0, 1); 139 | glTranslatef(0, -8, 0); 140 | 141 | if(leftHanded) 142 | { 143 | glScaled(-1, 1, 1); 144 | glRotatef(180F, 0, 1, 0); 145 | } 146 | 147 | glPushMatrix(); 148 | { 149 | this.drawGrid(camera, false); 150 | this.drawElements(manager); 151 | } 152 | glPopMatrix(); 153 | 154 | glDisable(GL_DEPTH_TEST); 155 | glDisable(GL_CULL_FACE); 156 | glDisable(GL_TEXTURE_2D); 157 | glDisable(GL_LIGHTING); 158 | } 159 | glPopAttrib(); 160 | glPopMatrix(); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/Settings.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | import java.util.prefs.Preferences; 4 | 5 | public class Settings 6 | { 7 | private static final String IMAGE_IMPORT_DIR = "image_import_dir"; 8 | private static final String SCREENSHOT_DIR = "screenshot_dir"; 9 | private static final String MODEL_DIR = "model_dir"; 10 | private static final String JSON_DIR = "json_dir"; 11 | private static final String EXPORT_JSON_DIR = "export_json_dir"; 12 | private static final String UNDO_LIMIT = "undo_limit"; 13 | private static final String RENDER_CARDINAL_POINTS = "cardinal_points"; 14 | private static final String ASSESTS_DIR = "assets_dir"; 15 | private static final String FACE_COLORS = "face_colors"; 16 | private static final String IMAGE_EDITOR = "image_editor"; 17 | private static final String IMAGE_EDITOR_ARGS = "image_editor_args"; 18 | 19 | public static final int[] DEFAULT_FACE_COLORS = {16711680, 65280, 255, 16776960, 16711935, 65535}; 20 | 21 | public static String getImageImportDir() 22 | { 23 | Preferences prefs = getPreferences(); 24 | return prefs.get(IMAGE_IMPORT_DIR, null); 25 | } 26 | 27 | public static void setImageImportDir(String dir) 28 | { 29 | Preferences prefs = getPreferences(); 30 | prefs.put(IMAGE_IMPORT_DIR, dir); 31 | } 32 | 33 | public static String getScreenshotDir() 34 | { 35 | Preferences prefs = getPreferences(); 36 | return prefs.get(SCREENSHOT_DIR, null); 37 | } 38 | 39 | public static void setScreenshotDir(String dir) 40 | { 41 | Preferences prefs = getPreferences(); 42 | prefs.put(SCREENSHOT_DIR, dir); 43 | } 44 | 45 | public static String getModelDir() 46 | { 47 | Preferences prefs = getPreferences(); 48 | return prefs.get(MODEL_DIR, null); 49 | } 50 | 51 | public static void setModelDir(String dir) 52 | { 53 | Preferences prefs = getPreferences(); 54 | prefs.put(MODEL_DIR, dir); 55 | } 56 | 57 | public static String getJSONDir() 58 | { 59 | Preferences prefs = getPreferences(); 60 | return prefs.get(JSON_DIR, null); 61 | } 62 | 63 | public static void setJSONDir(String dir) 64 | { 65 | Preferences prefs = getPreferences(); 66 | prefs.put(JSON_DIR, dir); 67 | } 68 | 69 | public static String getExportJSONDir() 70 | { 71 | Preferences prefs = getPreferences(); 72 | return prefs.get(EXPORT_JSON_DIR, null); 73 | } 74 | 75 | public static void setExportJSONDir(String dir) 76 | { 77 | Preferences prefs = getPreferences(); 78 | prefs.put(EXPORT_JSON_DIR, dir); 79 | } 80 | 81 | public static String getAssetsDir() 82 | { 83 | Preferences prefs = getPreferences(); 84 | return prefs.get(ASSESTS_DIR, null); 85 | } 86 | 87 | public static void setAssetsDir(String dir) 88 | { 89 | Preferences prefs = getPreferences(); 90 | prefs.put(ASSESTS_DIR, dir); 91 | } 92 | 93 | public static int getUndoLimit() 94 | { 95 | Preferences prefs = getPreferences(); 96 | String s = prefs.get(UNDO_LIMIT, null); 97 | try 98 | { 99 | return Math.max(1, Integer.parseInt(s)); 100 | } 101 | catch(NumberFormatException e) 102 | { 103 | return 50; 104 | } 105 | } 106 | 107 | public static void setUndoLimit(int limit) 108 | { 109 | Preferences prefs = getPreferences(); 110 | prefs.put(UNDO_LIMIT, Integer.toString(Math.max(1, limit))); 111 | } 112 | 113 | public static boolean getCardinalPoints() 114 | { 115 | Preferences prefs = getPreferences(); 116 | String s = prefs.get(RENDER_CARDINAL_POINTS, "true"); 117 | return Boolean.parseBoolean(s); 118 | } 119 | 120 | public static void setCardinalPoints(boolean renderCardinalPoints) 121 | { 122 | Preferences prefs = getPreferences(); 123 | prefs.put(RENDER_CARDINAL_POINTS, Boolean.toString(renderCardinalPoints)); 124 | } 125 | 126 | public static int[] getFaceColors() 127 | { 128 | Preferences prefs = getPreferences(); 129 | String s = prefs.get(FACE_COLORS, ""); 130 | String[] values = s.split(","); 131 | if(values.length == 6) 132 | { 133 | int[] colors = new int[6]; 134 | for(int i = 0; i < values.length; i++) 135 | { 136 | int color = Integer.parseInt(values[i]); 137 | colors[i] = color; 138 | } 139 | return colors; 140 | } 141 | return DEFAULT_FACE_COLORS; 142 | } 143 | 144 | public static void setFaceColors(int[] colors) 145 | { 146 | StringBuilder builder = new StringBuilder(); 147 | for(int value : colors) 148 | { 149 | builder.append(value); 150 | builder.append(","); 151 | } 152 | builder.setLength(builder.length() - 1); 153 | Preferences prefs = getPreferences(); 154 | prefs.put(FACE_COLORS, builder.toString()); 155 | } 156 | 157 | public static String getImageEditor() 158 | { 159 | Preferences prefs = getPreferences(); 160 | return prefs.get(IMAGE_EDITOR, null); 161 | } 162 | 163 | public static void setImageEditor(String file) 164 | { 165 | Preferences prefs = getPreferences(); 166 | prefs.put(IMAGE_EDITOR, file); 167 | } 168 | 169 | public static String getImageEditorArgs() 170 | { 171 | Preferences prefs = getPreferences(); 172 | return prefs.get(IMAGE_EDITOR_ARGS, "\"%s\""); 173 | } 174 | 175 | public static void setImageEditorArgs(String args) 176 | { 177 | Preferences prefs = getPreferences(); 178 | prefs.put(IMAGE_EDITOR_ARGS, args); 179 | } 180 | 181 | private static Preferences getPreferences() 182 | { 183 | return Preferences.userNodeForPackage(Settings.class); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/panels/tabs/FacePanel.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.panels.tabs; 2 | 3 | import com.mrcrayfish.modelcreator.ModelCreator; 4 | import com.mrcrayfish.modelcreator.StateManager; 5 | import com.mrcrayfish.modelcreator.element.Element; 6 | import com.mrcrayfish.modelcreator.element.ElementManager; 7 | import com.mrcrayfish.modelcreator.element.Face; 8 | import com.mrcrayfish.modelcreator.panels.FaceExtrasPanel; 9 | import com.mrcrayfish.modelcreator.panels.IElementUpdater; 10 | import com.mrcrayfish.modelcreator.panels.TexturePanel; 11 | import com.mrcrayfish.modelcreator.panels.UVPanel; 12 | 13 | import javax.swing.*; 14 | import java.awt.*; 15 | import java.awt.event.MouseAdapter; 16 | import java.awt.event.MouseEvent; 17 | import java.util.Hashtable; 18 | 19 | public class FacePanel extends JPanel implements IElementUpdater 20 | { 21 | private ElementManager manager; 22 | 23 | private JPanel menuPanel; 24 | private JComboBox menuList; 25 | private UVPanel panelUV; 26 | private JPanel sliderPanel; 27 | private JSlider rotation; 28 | private TexturePanel panelTexture; 29 | private FaceExtrasPanel panelProperties; 30 | 31 | private final int ROTATION_MIN = 0; 32 | private final int ROTATION_MAX = 3; 33 | private final int ROTATION_INIT = 0; 34 | 35 | private DefaultComboBoxModel model; 36 | 37 | public FacePanel(ElementManager manager) 38 | { 39 | this.manager = manager; 40 | setBackground(ModelCreator.BACKGROUND); 41 | setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 42 | initMenu(); 43 | initComponents(); 44 | addComponents(); 45 | } 46 | 47 | private void initMenu() 48 | { 49 | model = new DefaultComboBoxModel<>(); 50 | model.addElement("
North"); 51 | model.addElement("
East"); 52 | model.addElement("
South"); 53 | model.addElement("
West"); 54 | model.addElement("
Up"); 55 | model.addElement("
Down"); 56 | } 57 | 58 | private void initComponents() 59 | { 60 | menuPanel = new JPanel(new GridLayout(1, 1)); 61 | menuPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Side")); 62 | menuPanel.setMaximumSize(new Dimension(186, 56)); 63 | menuPanel.setBackground(ModelCreator.BACKGROUND); 64 | 65 | menuList = new JComboBox<>(); 66 | menuList.setModel(model); 67 | menuList.setToolTipText("The face to edit."); 68 | menuList.addActionListener(e -> 69 | { 70 | Element selectedElement = manager.getSelectedElement(); 71 | if(selectedElement != null) 72 | { 73 | selectedElement.setSelectedFace(menuList.getSelectedIndex()); 74 | updateValues(selectedElement); 75 | } 76 | }); 77 | menuPanel.add(menuList); 78 | 79 | panelTexture = new TexturePanel(manager); 80 | panelUV = new UVPanel(manager); 81 | panelProperties = new FaceExtrasPanel(manager); 82 | 83 | Hashtable labelTable = new Hashtable<>(); 84 | labelTable.put(0, new JLabel("0\u00b0")); 85 | labelTable.put(1, new JLabel("90\u00b0")); 86 | labelTable.put(2, new JLabel("180\u00b0")); 87 | labelTable.put(3, new JLabel("270\u00b0")); 88 | 89 | sliderPanel = new JPanel(new GridLayout(1, 1)); 90 | sliderPanel.setBackground(ModelCreator.BACKGROUND); 91 | sliderPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Rotation")); 92 | rotation = new JSlider(JSlider.HORIZONTAL, ROTATION_MIN, ROTATION_MAX, ROTATION_INIT); 93 | rotation.setBackground(ModelCreator.BACKGROUND); 94 | rotation.setMajorTickSpacing(4); 95 | rotation.setPaintTicks(true); 96 | rotation.setPaintLabels(true); 97 | rotation.setLabelTable(labelTable); 98 | rotation.addChangeListener(e -> 99 | { 100 | Element selectedElement = manager.getSelectedElement(); 101 | if(selectedElement != null) 102 | { 103 | selectedElement.getSelectedFace().setRotation(rotation.getValue()); 104 | } 105 | }); 106 | rotation.addMouseListener(new MouseAdapter() 107 | { 108 | @Override 109 | public void mouseReleased(MouseEvent e) 110 | { 111 | StateManager.pushState(manager); 112 | } 113 | }); 114 | rotation.setToolTipText("The rotation of the texture
Default: 0\u00b0"); 115 | sliderPanel.setMaximumSize(new Dimension(190, 80)); 116 | sliderPanel.add(rotation); 117 | } 118 | 119 | private void addComponents() 120 | { 121 | add(Box.createRigidArea(new Dimension(192, 5))); 122 | add(menuPanel); 123 | add(panelTexture); 124 | add(panelUV); 125 | add(sliderPanel); 126 | add(panelProperties); 127 | } 128 | 129 | @Override 130 | public void updateValues(Element cube) 131 | { 132 | if(cube != null) 133 | { 134 | menuList.setSelectedItem(model.getElementAt(cube.getSelectedFaceIndex())); 135 | menuList.repaint(); 136 | rotation.setEnabled(true); 137 | rotation.setValue(cube.getSelectedFace().getRotation()); 138 | } 139 | else 140 | { 141 | rotation.setEnabled(false); 142 | rotation.setValue(0); 143 | } 144 | panelUV.updateValues(cube); 145 | panelProperties.updateValues(cube); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/component/DisplayPropertiesDialog.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.component; 2 | 3 | import com.mrcrayfish.modelcreator.ModelCreator; 4 | import com.mrcrayfish.modelcreator.display.CanvasRenderer; 5 | import com.mrcrayfish.modelcreator.display.DisplayProperties; 6 | import com.mrcrayfish.modelcreator.element.ElementManager; 7 | import com.mrcrayfish.modelcreator.panels.DisplayEntryPanel; 8 | import com.mrcrayfish.modelcreator.util.ComponentUtil; 9 | 10 | import javax.swing.*; 11 | import java.awt.*; 12 | 13 | /** 14 | * Author: MrCrayfish 15 | */ 16 | public class DisplayPropertiesDialog extends JDialog 17 | { 18 | private ModelCreator creator; 19 | 20 | private JTabbedPane tabbedPane; 21 | 22 | public DisplayPropertiesDialog(ModelCreator creator) 23 | { 24 | super(creator, "Display Properties", Dialog.ModalityType.MODELESS); 25 | this.creator = creator; 26 | this.init(); 27 | this.pack(); 28 | this.setResizable(false); 29 | } 30 | 31 | 32 | private void init() 33 | { 34 | SpringLayout layout = new SpringLayout(); 35 | JPanel panel = new JPanel(layout); 36 | panel.setPreferredSize(new Dimension(400, 490)); 37 | this.add(panel); 38 | 39 | JLabel labelProperties = new JLabel("Presets"); 40 | panel.add(labelProperties); 41 | 42 | JComboBox comboBoxProperties = new JComboBox<>(); 43 | comboBoxProperties.addItem(DisplayProperties.MODEL_CREATOR_BLOCK); 44 | comboBoxProperties.addItem(DisplayProperties.DEFAULT_BLOCK); 45 | comboBoxProperties.addItem(DisplayProperties.DEFAULT_ITEM); 46 | comboBoxProperties.setPreferredSize(new Dimension(0, 24)); 47 | panel.add(comboBoxProperties); 48 | 49 | DisplayProperties properties = creator.getElementManager().getDisplayProperties(); 50 | 51 | tabbedPane = new JTabbedPane(); 52 | tabbedPane.addTab("GUI", new DisplayEntryPanel(properties.getEntry("gui"))); 53 | tabbedPane.addTab("Ground", new DisplayEntryPanel(properties.getEntry("ground"))); 54 | tabbedPane.addTab("Fixed", new DisplayEntryPanel(properties.getEntry("fixed"))); 55 | tabbedPane.addTab("Head", new DisplayEntryPanel(properties.getEntry("head"))); 56 | tabbedPane.addTab("First Person", new DisplayEntryPanel(properties.getEntry("firstperson_righthand"))); 57 | tabbedPane.addTab("Third Person", new DisplayEntryPanel(properties.getEntry("thirdperson_righthand"))); 58 | tabbedPane.addTab("First Person (Left)", new DisplayEntryPanel(properties.getEntry("firstperson_lefthand"))); 59 | tabbedPane.addTab("Third Person (Left)", new DisplayEntryPanel(properties.getEntry("thirdperson_lefthand"))); 60 | tabbedPane.addChangeListener(e -> 61 | { 62 | Component c = tabbedPane.getComponentAt(tabbedPane.getSelectedIndex()); 63 | if(c instanceof DisplayEntryPanel) 64 | { 65 | DisplayEntryPanel entryPanel = (DisplayEntryPanel) c; 66 | CanvasRenderer render = DisplayProperties.RENDER_MAP.get(entryPanel.getEntry().getId()); 67 | if(render != null) 68 | { 69 | ModelCreator.setCanvasRenderer(render); 70 | } 71 | else 72 | { 73 | ModelCreator.restoreStandardRenderer(); 74 | } 75 | } 76 | }); 77 | panel.add(tabbedPane); 78 | 79 | JButton btnApplyProperties = new JButton("Apply"); 80 | btnApplyProperties.setPreferredSize(new Dimension(80, 24)); 81 | btnApplyProperties.addActionListener(e -> 82 | { 83 | creator.getElementManager().setDisplayProperties((DisplayProperties) comboBoxProperties.getSelectedItem()); 84 | this.updateValues(creator.getElementManager().getDisplayProperties()); 85 | }); 86 | panel.add(btnApplyProperties); 87 | 88 | JCheckBox checkBoxShowGrid = ComponentUtil.createCheckBox("Show Grid", "Determines whether the grid should render", Menu.shouldRenderGrid); 89 | checkBoxShowGrid.addActionListener(e -> Menu.shouldRenderGrid = checkBoxShowGrid.isSelected()); 90 | panel.add(checkBoxShowGrid); 91 | 92 | layout.putConstraint(SpringLayout.WEST, labelProperties, 10, SpringLayout.WEST, panel); 93 | layout.putConstraint(SpringLayout.NORTH, labelProperties, 2, SpringLayout.NORTH, comboBoxProperties); 94 | layout.putConstraint(SpringLayout.EAST, comboBoxProperties, -10, SpringLayout.WEST, btnApplyProperties); 95 | layout.putConstraint(SpringLayout.NORTH, comboBoxProperties, 10, SpringLayout.NORTH, panel); 96 | layout.putConstraint(SpringLayout.WEST, comboBoxProperties, 10, SpringLayout.EAST, labelProperties); 97 | layout.putConstraint(SpringLayout.NORTH, btnApplyProperties, 10, SpringLayout.NORTH, panel); 98 | layout.putConstraint(SpringLayout.EAST, btnApplyProperties, -10, SpringLayout.EAST, panel); 99 | layout.putConstraint(SpringLayout.WEST, checkBoxShowGrid, 10, SpringLayout.WEST, panel); 100 | layout.putConstraint(SpringLayout.NORTH, checkBoxShowGrid, 5, SpringLayout.SOUTH, comboBoxProperties); 101 | layout.putConstraint(SpringLayout.EAST, tabbedPane, -10, SpringLayout.EAST, panel); 102 | layout.putConstraint(SpringLayout.NORTH, tabbedPane, 5, SpringLayout.SOUTH, checkBoxShowGrid); 103 | layout.putConstraint(SpringLayout.WEST, tabbedPane, 10, SpringLayout.WEST, panel); 104 | } 105 | 106 | public void updateValues(DisplayProperties displayProperties) 107 | { 108 | Component[] components = tabbedPane.getComponents(); 109 | for(Component c : components) 110 | { 111 | if(c instanceof DisplayEntryPanel) 112 | { 113 | DisplayEntryPanel entryPanel = (DisplayEntryPanel) c; 114 | DisplayProperties.Entry oldEntry = entryPanel.getEntry(); 115 | DisplayProperties.Entry newEntry = displayProperties.getEntry(oldEntry.getId()); 116 | if(newEntry != null) 117 | { 118 | entryPanel.updateValues(newEntry); 119 | } 120 | } 121 | } 122 | } 123 | 124 | public static void update(ModelCreator creator) 125 | { 126 | if(Menu.displayPropertiesDialog != null) 127 | { 128 | Menu.displayPropertiesDialog.updateValues(creator.getElementManager().getDisplayProperties()); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/render/StandardRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display.render; 2 | 3 | import com.mrcrayfish.modelcreator.Camera; 4 | import com.mrcrayfish.modelcreator.ModelCreator; 5 | import com.mrcrayfish.modelcreator.Settings; 6 | import com.mrcrayfish.modelcreator.component.Menu; 7 | import com.mrcrayfish.modelcreator.display.CanvasRenderer; 8 | import com.mrcrayfish.modelcreator.element.Element; 9 | import com.mrcrayfish.modelcreator.element.ElementManager; 10 | import com.mrcrayfish.modelcreator.element.Face; 11 | import com.mrcrayfish.modelcreator.util.FontManager; 12 | import org.lwjgl.opengl.GL11; 13 | import org.newdawn.slick.Color; 14 | import org.newdawn.slick.opengl.TextureImpl; 15 | 16 | import static org.lwjgl.opengl.GL11.*; 17 | 18 | /** 19 | * Author: MrCrayfish 20 | */ 21 | public class StandardRenderer extends CanvasRenderer 22 | { 23 | @Override 24 | public void onInit(Camera camera) 25 | { 26 | camera.setX(0); 27 | camera.setY(-5); 28 | camera.setZ(-30); 29 | camera.setRX(20); 30 | camera.setRY(0); 31 | camera.setRZ(0); 32 | } 33 | 34 | @Override 35 | public void onRenderPerspective(ModelCreator creator, ElementManager manager, Camera camera) 36 | { 37 | glMatrixMode(GL_MODELVIEW); 38 | glLoadIdentity(); 39 | glEnable(GL_DEPTH_TEST); 40 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 41 | camera.useView(); 42 | 43 | this.drawGrid(camera, Settings.getCardinalPoints()); //TODO make this an option 44 | this.drawElements(manager); 45 | 46 | glDisable(GL_DEPTH_TEST); 47 | glDisable(GL_CULL_FACE); 48 | glDisable(GL_TEXTURE_2D); 49 | glDisable(GL_LIGHTING); 50 | } 51 | 52 | protected void drawElements(ElementManager manager) 53 | { 54 | glTranslatef(-8, 0, -8); 55 | for(int i = 0; i < manager.getElementCount(); i++) 56 | { 57 | Element cube = manager.getElement(i); 58 | if(cube.isVisible()) 59 | { 60 | glLoadName(i + 1); 61 | cube.draw(); 62 | glLoadName(0); 63 | cube.drawExtras(manager); 64 | } 65 | } 66 | 67 | Element selectedElement = manager.getSelectedElement(); 68 | if(selectedElement != null && selectedElement.isVisible()) 69 | { 70 | selectedElement.drawOutline(); 71 | } 72 | } 73 | 74 | protected void drawGrid(Camera camera, boolean renderCardinalPoints) 75 | { 76 | if(Menu.displayPropertiesDialog != null && !Menu.shouldRenderGrid) 77 | { 78 | return; 79 | } 80 | 81 | glPushMatrix(); 82 | { 83 | glColor3f(0.55F, 0.55F, 0.65F); 84 | glTranslatef(-8, 0, -8); 85 | 86 | // Bold outside lines 87 | glLineWidth(1.5F); 88 | glBegin(GL_LINES); 89 | { 90 | glVertex3i(0, 0, 0); 91 | glVertex3i(0, 0, 16); 92 | glVertex3i(16, 0, 0); 93 | glVertex3i(16, 0, 16); 94 | glVertex3i(0, 0, 16); 95 | glVertex3i(16, 0, 16); 96 | glVertex3i(0, 0, 0); 97 | glVertex3i(16, 0, 0); 98 | } 99 | glEnd(); 100 | 101 | // Thin inside lines 102 | glLineWidth(1F); 103 | glBegin(GL_LINES); 104 | { 105 | for(int i = 1; i <= 16; i++) 106 | { 107 | glVertex3i(i, 0, 0); 108 | glVertex3i(i, 0, 16); 109 | } 110 | 111 | for(int i = 1; i <= 16; i++) 112 | { 113 | glVertex3i(0, 0, i); 114 | glVertex3i(16, 0, i); 115 | } 116 | } 117 | glEnd(); 118 | } 119 | glPopMatrix(); 120 | 121 | glPushMatrix(); 122 | { 123 | TextureImpl.bindNone(); 124 | 125 | glTranslatef(-8, 0, -8); 126 | glEnable(GL_TEXTURE_2D); 127 | glEnable(GL_BLEND); 128 | glShadeModel(GL_SMOOTH); 129 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 130 | 131 | glPushMatrix(); 132 | glTranslated(0, 0, 16); 133 | glScaled(0.015, 0.015, 0.015); 134 | glRotated(90, 1, 0, 0); 135 | FontManager.BEBAS_NEUE_50.drawString(0, 0, "MrCrayfish's Model Creator", Color.lightGray); 136 | glPopMatrix(); 137 | 138 | if(renderCardinalPoints) 139 | { 140 | Color color = new Color(0.5F, 0.5F, 0.55F).brighter(0.40F); 141 | 142 | glPushMatrix(); 143 | glTranslated(8, 0, 17); 144 | glScaled(0.025, 0.025, 0.025); 145 | glRotated(-camera.getRY(), 0, 1, 0); 146 | glTranslated(-(FontManager.BEBAS_NEUE_50.getWidth("S") / 2), 0, -(FontManager.BEBAS_NEUE_50.getHeight() / 2)); 147 | glRotated(90, 1, 0, 0); 148 | FontManager.BEBAS_NEUE_50.drawString(0, 0, "S", color); 149 | glPopMatrix(); 150 | 151 | glPushMatrix(); 152 | glTranslated(8, 0, -1); 153 | glScaled(0.025, 0.025, 0.025); 154 | glRotated(-camera.getRY(), 0, 1, 0); 155 | glTranslated(-(FontManager.BEBAS_NEUE_50.getWidth("N") / 2), 0, -(FontManager.BEBAS_NEUE_50.getHeight() / 2)); 156 | glRotated(90, 1, 0, 0); 157 | FontManager.BEBAS_NEUE_50.drawString(0, 0, "N", color); 158 | glPopMatrix(); 159 | 160 | glPushMatrix(); 161 | glTranslated(-1, 0, 8); 162 | glScaled(0.025, 0.025, 0.025); 163 | glRotated(-camera.getRY(), 0, 1, 0); 164 | glTranslated(-(FontManager.BEBAS_NEUE_50.getWidth("W") / 2), 0, -(FontManager.BEBAS_NEUE_50.getHeight() / 2)); 165 | glRotated(90, 1, 0, 0); 166 | FontManager.BEBAS_NEUE_50.drawString(0, 0, "W", color); 167 | glPopMatrix(); 168 | 169 | glPushMatrix(); 170 | glTranslated(17, 0, 8); 171 | glScaled(0.025, 0.025, 0.025); 172 | glRotated(-camera.getRY(), 0, 1, 0); 173 | glTranslated(-(FontManager.BEBAS_NEUE_50.getWidth("E") / 2), 0, -(FontManager.BEBAS_NEUE_50.getHeight() / 2)); 174 | glRotated(90, 1, 0, 0); 175 | FontManager.BEBAS_NEUE_50.drawString(0, 0, "E", color); 176 | glPopMatrix(); 177 | } 178 | 179 | glDisable(GL_TEXTURE_2D); 180 | glDisable(GL_BLEND); 181 | } 182 | glPopMatrix(); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/panels/tabs/RotationPanel.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.panels.tabs; 2 | 3 | import com.mrcrayfish.modelcreator.ModelCreator; 4 | import com.mrcrayfish.modelcreator.StateManager; 5 | import com.mrcrayfish.modelcreator.element.Element; 6 | import com.mrcrayfish.modelcreator.element.ElementManager; 7 | import com.mrcrayfish.modelcreator.panels.IElementUpdater; 8 | import com.mrcrayfish.modelcreator.panels.OriginPanel; 9 | import com.mrcrayfish.modelcreator.util.ComponentUtil; 10 | 11 | import javax.swing.*; 12 | import java.awt.*; 13 | import java.awt.event.ItemEvent; 14 | import java.awt.event.MouseAdapter; 15 | import java.awt.event.MouseEvent; 16 | import java.util.Hashtable; 17 | 18 | public class RotationPanel extends JPanel implements IElementUpdater 19 | { 20 | private ElementManager manager; 21 | 22 | private OriginPanel panelOrigin; 23 | private JPanel axisPanel; 24 | private JComboBox axisList; 25 | private JPanel sliderPanel; 26 | private JSlider rotation; 27 | private JPanel extraPanel; 28 | private JRadioButton btnRescale; 29 | 30 | private DefaultComboBoxModel model; 31 | 32 | private final int ROTATION_MIN = -2; 33 | private final int ROTATION_MAX = 2; 34 | private final int ROTATION_INIT = 0; 35 | 36 | public RotationPanel(ElementManager manager) 37 | { 38 | this.manager = manager; 39 | this.setBackground(ModelCreator.BACKGROUND); 40 | this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 41 | this.initMenu(); 42 | this.initComponents(); 43 | this.addComponents(); 44 | } 45 | 46 | private void initMenu() 47 | { 48 | model = new DefaultComboBoxModel<>(); 49 | model.addElement("
X"); 50 | model.addElement("
Y"); 51 | model.addElement("
Z"); 52 | } 53 | 54 | private void initComponents() 55 | { 56 | panelOrigin = new OriginPanel(manager); 57 | panelOrigin.setBackground(ModelCreator.BACKGROUND); 58 | 59 | axisPanel = new JPanel(new GridLayout(1, 1)); 60 | axisPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Axis")); 61 | axisPanel.setBackground(ModelCreator.BACKGROUND); 62 | 63 | axisList = new JComboBox<>(); 64 | axisList.setModel(model); 65 | axisList.setToolTipText("The axis the element will rotate around"); 66 | axisList.addItemListener(e -> 67 | { 68 | if(e.getStateChange() == ItemEvent.SELECTED) 69 | { 70 | Element selectedElement = manager.getSelectedElement(); 71 | if(selectedElement != null && selectedElement.getRotationAxis() != axisList.getSelectedIndex()) 72 | { 73 | selectedElement.setRotationAxis(axisList.getSelectedIndex()); 74 | StateManager.pushState(manager); 75 | } 76 | } 77 | }); 78 | axisList.setMaximumSize(new Dimension(186, 55)); 79 | axisPanel.setMaximumSize(new Dimension(186, 55)); 80 | axisPanel.add(axisList); 81 | 82 | Hashtable labelTable = new Hashtable<>(); 83 | labelTable.put(-2, new JLabel("-45\u00b0")); 84 | labelTable.put(-1, new JLabel("-22.5\u00b0")); 85 | labelTable.put(0, new JLabel("0\u00b0")); 86 | labelTable.put(1, new JLabel("22.5\u00b0")); 87 | labelTable.put(2, new JLabel("45\u00b0")); 88 | 89 | sliderPanel = new JPanel(new GridLayout(1, 1)); 90 | sliderPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Rotation")); 91 | sliderPanel.setBackground(ModelCreator.BACKGROUND); 92 | 93 | rotation = new JSlider(JSlider.HORIZONTAL, ROTATION_MIN, ROTATION_MAX, ROTATION_INIT); 94 | rotation.setBackground(ModelCreator.BACKGROUND); 95 | rotation.setMajorTickSpacing(1); 96 | rotation.setPaintTicks(true); 97 | rotation.setPaintLabels(true); 98 | rotation.setLabelTable(labelTable); 99 | rotation.addChangeListener(e -> 100 | { 101 | Element selectedElement = manager.getSelectedElement(); 102 | if(selectedElement != null) 103 | { 104 | selectedElement.setRotation(rotation.getValue() * 22.5D); 105 | } 106 | }); 107 | rotation.addMouseListener(new MouseAdapter() 108 | { 109 | @Override 110 | public void mouseReleased(MouseEvent e) 111 | { 112 | StateManager.pushState(manager); 113 | } 114 | }); 115 | rotation.setToolTipText("The rotation of the element
Default: 0"); 116 | sliderPanel.setMaximumSize(new Dimension(190, 80)); 117 | sliderPanel.add(rotation); 118 | 119 | extraPanel = new JPanel(new GridLayout(1, 2)); 120 | extraPanel.setBackground(ModelCreator.BACKGROUND); 121 | extraPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Extras")); 122 | 123 | btnRescale = ComponentUtil.createRadioButton("Rescale", "Should scale faces across whole block
Default: Off"); 124 | btnRescale.setBackground(ModelCreator.BACKGROUND); 125 | btnRescale.addActionListener(e -> 126 | { 127 | Element selectedElement = manager.getSelectedElement(); 128 | if(selectedElement != null) 129 | { 130 | selectedElement.setRescale(btnRescale.isSelected()); 131 | StateManager.pushState(manager); 132 | } 133 | }); 134 | extraPanel.setMaximumSize(new Dimension(186, 50)); 135 | extraPanel.add(btnRescale); 136 | } 137 | 138 | private void addComponents() 139 | { 140 | add(Box.createRigidArea(new Dimension(188, 5))); 141 | add(panelOrigin); 142 | add(axisPanel); 143 | add(sliderPanel); 144 | add(extraPanel); 145 | } 146 | 147 | @Override 148 | public void updateValues(Element cube) 149 | { 150 | panelOrigin.updateValues(cube); 151 | if(cube != null) 152 | { 153 | axisList.setSelectedIndex(cube.getRotationAxis()); 154 | rotation.setEnabled(true); 155 | rotation.setValue((int) (cube.getRotation() / 22.5)); 156 | btnRescale.setEnabled(true); 157 | btnRescale.setSelected(cube.shouldRescale()); 158 | } 159 | else 160 | { 161 | rotation.setValue(0); 162 | rotation.setEnabled(false); 163 | btnRescale.setSelected(false); 164 | btnRescale.setEnabled(false); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/util/ComponentUtil.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.util; 2 | 3 | import com.mrcrayfish.modelcreator.Icons; 4 | import com.mrcrayfish.modelcreator.Processor; 5 | 6 | import javax.swing.*; 7 | import javax.swing.filechooser.FileFilter; 8 | import java.awt.*; 9 | import java.io.File; 10 | 11 | public class ComponentUtil 12 | { 13 | public static JRadioButton createRadioButton(String label, String toolTip) 14 | { 15 | JRadioButton radioButton = new JRadioButton(label); 16 | radioButton.setToolTipText(toolTip); 17 | radioButton.setIcon(Icons.light_off); 18 | radioButton.setRolloverIcon(Icons.light_off); 19 | radioButton.setSelectedIcon(Icons.light_on); 20 | radioButton.setRolloverSelectedIcon(Icons.light_on); 21 | return radioButton; 22 | } 23 | 24 | public static JCheckBox createCheckBox(String text, String tooltip, boolean selected) 25 | { 26 | JCheckBox checkBox = new JCheckBox(text); 27 | checkBox.setToolTipText(tooltip); 28 | checkBox.setSelected(selected); 29 | checkBox.setIcon(Icons.light_off); 30 | checkBox.setRolloverIcon(Icons.light_off); 31 | checkBox.setSelectedIcon(Icons.light_on); 32 | checkBox.setRolloverSelectedIcon(Icons.light_on); 33 | return checkBox; 34 | } 35 | 36 | public static JPanel createDirectorySelector(String label, Component parent, String defaultDir, Processor processor) 37 | { 38 | SpringLayout layout = new SpringLayout(); 39 | JPanel panel = new JPanel(layout); 40 | panel.setPreferredSize(new Dimension(100, 24)); 41 | 42 | JTextField textFieldDestination = new JTextField(); 43 | textFieldDestination.setPreferredSize(new Dimension(100, 24)); 44 | textFieldDestination.setText(defaultDir); 45 | textFieldDestination.setEditable(false); 46 | textFieldDestination.setFocusable(false); 47 | textFieldDestination.setCaretPosition(0); 48 | panel.add(textFieldDestination); 49 | 50 | JButton btnBrowserDir = new JButton("Browse"); 51 | btnBrowserDir.setPreferredSize(new Dimension(80, 24)); 52 | btnBrowserDir.setIcon(Icons.load); 53 | btnBrowserDir.addActionListener(e -> 54 | { 55 | JFileChooser chooser = new JFileChooser(); 56 | chooser.setDialogTitle("Select a Folder"); 57 | chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 58 | chooser.setApproveButtonText("Select"); 59 | chooser.setCurrentDirectory(new File(defaultDir)); 60 | int returnVal = chooser.showOpenDialog(parent); 61 | if(returnVal == JFileChooser.APPROVE_OPTION) 62 | { 63 | File file = chooser.getSelectedFile(); 64 | if(file != null) 65 | { 66 | if(processor != null) 67 | { 68 | if(processor.run(file)) 69 | { 70 | return; 71 | } 72 | } 73 | textFieldDestination.setText(file.getAbsolutePath()); 74 | } 75 | } 76 | }); 77 | panel.add(btnBrowserDir); 78 | 79 | JLabel labelExportDir = new JLabel(label); 80 | panel.add(labelExportDir); 81 | 82 | layout.putConstraint(SpringLayout.NORTH, textFieldDestination, 0, SpringLayout.NORTH, panel); 83 | layout.putConstraint(SpringLayout.WEST, textFieldDestination, 10, SpringLayout.EAST, labelExportDir); 84 | layout.putConstraint(SpringLayout.EAST, textFieldDestination, -10, SpringLayout.WEST, btnBrowserDir); 85 | layout.putConstraint(SpringLayout.NORTH, labelExportDir, 3, SpringLayout.NORTH, textFieldDestination); 86 | layout.putConstraint(SpringLayout.WEST, labelExportDir, 0, SpringLayout.WEST, panel); 87 | layout.putConstraint(SpringLayout.NORTH, btnBrowserDir, 0, SpringLayout.NORTH, textFieldDestination); 88 | layout.putConstraint(SpringLayout.EAST, btnBrowserDir, 0, SpringLayout.EAST, panel); 89 | 90 | return panel; 91 | } 92 | 93 | public static JPanel createFileSelector(String label, Component parent, String defaultDir, FileFilter filter, Processor processor) 94 | { 95 | SpringLayout layout = new SpringLayout(); 96 | JPanel panel = new JPanel(layout); 97 | panel.setPreferredSize(new Dimension(100, 24)); 98 | 99 | JTextField textFieldDestination = new JTextField(); 100 | textFieldDestination.setPreferredSize(new Dimension(100, 24)); 101 | textFieldDestination.setText(defaultDir); 102 | textFieldDestination.setEditable(false); 103 | textFieldDestination.setFocusable(false); 104 | textFieldDestination.setCaretPosition(0); 105 | panel.add(textFieldDestination); 106 | 107 | JButton btnBrowserDir = new JButton("Browse"); 108 | btnBrowserDir.setPreferredSize(new Dimension(80, 24)); 109 | btnBrowserDir.setIcon(Icons.load); 110 | btnBrowserDir.addActionListener(e -> 111 | { 112 | JFileChooser chooser = new JFileChooser(); 113 | chooser.setDialogTitle("Select a File"); 114 | chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); 115 | chooser.setApproveButtonText("Select"); 116 | chooser.setCurrentDirectory(new File(defaultDir)); 117 | if(filter != null) 118 | { 119 | chooser.setFileFilter(filter); 120 | } 121 | int returnVal = chooser.showOpenDialog(parent); 122 | if(returnVal == JFileChooser.APPROVE_OPTION) 123 | { 124 | File file = chooser.getSelectedFile(); 125 | if(file != null) 126 | { 127 | if(processor != null) 128 | { 129 | if(processor.run(file)) 130 | { 131 | return; 132 | } 133 | } 134 | textFieldDestination.setText(file.getAbsolutePath()); 135 | } 136 | } 137 | }); 138 | panel.add(btnBrowserDir); 139 | 140 | JLabel labelExportDir = new JLabel(label); 141 | panel.add(labelExportDir); 142 | 143 | layout.putConstraint(SpringLayout.NORTH, textFieldDestination, 0, SpringLayout.NORTH, panel); 144 | layout.putConstraint(SpringLayout.WEST, textFieldDestination, 10, SpringLayout.EAST, labelExportDir); 145 | layout.putConstraint(SpringLayout.EAST, textFieldDestination, -10, SpringLayout.WEST, btnBrowserDir); 146 | layout.putConstraint(SpringLayout.NORTH, labelExportDir, 3, SpringLayout.NORTH, textFieldDestination); 147 | layout.putConstraint(SpringLayout.WEST, labelExportDir, 0, SpringLayout.WEST, panel); 148 | layout.putConstraint(SpringLayout.NORTH, btnBrowserDir, 0, SpringLayout.NORTH, textFieldDestination); 149 | layout.putConstraint(SpringLayout.EAST, btnBrowserDir, 0, SpringLayout.EAST, panel); 150 | 151 | return panel; 152 | } 153 | 154 | public static Rectangle expandRectangle(Rectangle r, int amount) 155 | { 156 | return new Rectangle(r.x - amount, r.y - amount, r.width + amount * 2, r.height + amount * 2); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/panels/FaceExtrasPanel.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.panels; 2 | 3 | import com.mrcrayfish.modelcreator.ModelCreator; 4 | import com.mrcrayfish.modelcreator.Settings; 5 | import com.mrcrayfish.modelcreator.StateManager; 6 | import com.mrcrayfish.modelcreator.element.Element; 7 | import com.mrcrayfish.modelcreator.element.ElementManager; 8 | import com.mrcrayfish.modelcreator.util.ComponentUtil; 9 | 10 | import javax.swing.*; 11 | import java.awt.*; 12 | 13 | public class FaceExtrasPanel extends JPanel implements IElementUpdater 14 | { 15 | private ElementManager manager; 16 | 17 | private JPanel horizontalBox; 18 | private JRadioButton boxCullFace; 19 | private JRadioButton boxFill; 20 | private JRadioButton boxEnabled; 21 | private JRadioButton boxAutoUV; 22 | private JCheckBox checkBoxTintIndex; 23 | private JSpinner tintIndexSpinner; 24 | 25 | 26 | public FaceExtrasPanel(ElementManager manager) 27 | { 28 | this.manager = manager; 29 | this.setBackground(ModelCreator.BACKGROUND); 30 | this.setLayout(new BorderLayout(0, 5)); 31 | this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(ModelCreator.BACKGROUND, 5), "Extras")); 32 | this.setMaximumSize(new Dimension(186, 120)); 33 | this.initComponents(); 34 | this.addComponents(); 35 | } 36 | 37 | private void initComponents() 38 | { 39 | horizontalBox = new JPanel(new GridLayout(3, 2)); 40 | boxCullFace = ComponentUtil.createRadioButton("Cullface", "Should render face is another block is adjacent
Default: Off"); 41 | boxCullFace.setBackground(ModelCreator.BACKGROUND); 42 | boxCullFace.addActionListener(e -> 43 | { 44 | Element selectedElement = manager.getSelectedElement(); 45 | if(selectedElement != null) 46 | { 47 | selectedElement.getSelectedFace().setCullface(boxCullFace.isSelected()); 48 | StateManager.pushState(manager); 49 | } 50 | }); 51 | boxFill = ComponentUtil.createRadioButton("Fill", "Makes the texture fill the face
Default: Off"); 52 | boxFill.setBackground(ModelCreator.BACKGROUND); 53 | boxFill.addActionListener(e -> 54 | { 55 | Element selectedElement = manager.getSelectedElement(); 56 | if(selectedElement != null) 57 | { 58 | selectedElement.getSelectedFace().fitTexture(boxFill.isSelected()); 59 | StateManager.pushState(manager); 60 | } 61 | }); 62 | boxEnabled = ComponentUtil.createRadioButton("Enable", "Determines if face should be rendered
Default: On"); 63 | boxEnabled.setBackground(ModelCreator.BACKGROUND); 64 | boxEnabled.addActionListener(e -> 65 | { 66 | Element selectedElement = manager.getSelectedElement(); 67 | if(selectedElement != null) 68 | { 69 | selectedElement.getSelectedFace().setEnabled(boxEnabled.isSelected()); 70 | StateManager.pushState(manager); 71 | } 72 | }); 73 | boxAutoUV = ComponentUtil.createRadioButton("Auto UV", "Determines if UV end coordinates should be set based on element size
Default: On"); 74 | boxAutoUV.setBackground(ModelCreator.BACKGROUND); 75 | boxAutoUV.addActionListener(e -> 76 | { 77 | Element selectedElement = manager.getSelectedElement(); 78 | if(selectedElement != null) 79 | { 80 | selectedElement.getSelectedFace().setAutoUVEnabled(boxAutoUV.isSelected()); 81 | selectedElement.getSelectedFace().updateEndUV(); 82 | manager.updateValues(); 83 | StateManager.pushState(manager); 84 | } 85 | }); 86 | horizontalBox.add(boxCullFace); 87 | horizontalBox.add(boxFill); 88 | horizontalBox.add(boxEnabled); 89 | horizontalBox.add(boxAutoUV); 90 | 91 | checkBoxTintIndex = ComponentUtil.createCheckBox("Tint Index", "The tint index to apply to this face. Used in gam", false); 92 | checkBoxTintIndex.setBackground(ModelCreator.BACKGROUND); 93 | checkBoxTintIndex.setEnabled(false); 94 | horizontalBox.add(checkBoxTintIndex); 95 | 96 | SpinnerNumberModel numberModel = new SpinnerNumberModel(); 97 | numberModel.setMinimum(0); 98 | tintIndexSpinner = new JSpinner(numberModel); 99 | tintIndexSpinner.setBackground(ModelCreator.BACKGROUND); 100 | tintIndexSpinner.setEnabled(false); 101 | tintIndexSpinner.setPreferredSize(new Dimension(75, 24)); 102 | tintIndexSpinner.setValue(0); 103 | tintIndexSpinner.addChangeListener(e -> 104 | { 105 | Element selectedElement = manager.getSelectedElement(); 106 | if(selectedElement != null) 107 | { 108 | selectedElement.getSelectedFace().setTintIndex((int) tintIndexSpinner.getValue()); 109 | StateManager.pushState(manager); 110 | } 111 | }); 112 | horizontalBox.add(tintIndexSpinner); 113 | 114 | checkBoxTintIndex.addActionListener(e -> 115 | { 116 | Element selectedElement = manager.getSelectedElement(); 117 | if(selectedElement != null) 118 | { 119 | boolean selected = checkBoxTintIndex.isSelected(); 120 | selectedElement.getSelectedFace().setTintIndexEnabled(selected); 121 | tintIndexSpinner.setEnabled(selected); 122 | StateManager.pushState(manager); 123 | } 124 | }); 125 | } 126 | 127 | private void addComponents() 128 | { 129 | add(horizontalBox, BorderLayout.NORTH); 130 | } 131 | 132 | @Override 133 | public void updateValues(Element cube) 134 | { 135 | if(cube != null) 136 | { 137 | boxCullFace.setEnabled(true); 138 | boxCullFace.setSelected(cube.getSelectedFace().isCullfaced()); 139 | boxFill.setEnabled(true); 140 | boxFill.setSelected(cube.getSelectedFace().shouldFitTexture()); 141 | boxEnabled.setEnabled(true); 142 | boxEnabled.setSelected(cube.getSelectedFace().isEnabled()); 143 | boxAutoUV.setEnabled(true); 144 | boxAutoUV.setSelected(cube.getSelectedFace().isAutoUVEnabled()); 145 | checkBoxTintIndex.setEnabled(true); 146 | checkBoxTintIndex.setSelected(cube.getSelectedFace().isTintIndexEnabled()); 147 | if(cube.getSelectedFace().isTintIndexEnabled()) 148 | { 149 | tintIndexSpinner.setEnabled(true); 150 | tintIndexSpinner.setValue(cube.getSelectedFace().getTintIndex()); 151 | } 152 | else 153 | { 154 | tintIndexSpinner.setEnabled(false); 155 | } 156 | } 157 | else 158 | { 159 | boxCullFace.setEnabled(false); 160 | boxCullFace.setSelected(false); 161 | boxFill.setEnabled(false); 162 | boxFill.setSelected(false); 163 | boxEnabled.setEnabled(false); 164 | boxEnabled.setSelected(false); 165 | boxAutoUV.setEnabled(false); 166 | boxAutoUV.setSelected(false); 167 | checkBoxTintIndex.setEnabled(false); 168 | checkBoxTintIndex.setSelected(false); 169 | tintIndexSpinner.setEnabled(false); 170 | tintIndexSpinner.setValue(0); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/texture/TextureEntry.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.texture; 2 | 3 | import com.mrcrayfish.modelcreator.TexturePath; 4 | import com.mrcrayfish.modelcreator.component.TextureManager; 5 | import org.lwjgl.BufferUtils; 6 | import org.lwjgl.opengl.GL11; 7 | import org.lwjgl.opengl.GL12; 8 | 9 | import javax.imageio.ImageIO; 10 | import javax.swing.*; 11 | import java.awt.*; 12 | import java.awt.image.BufferedImage; 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.nio.ByteBuffer; 16 | import java.util.ArrayList; 17 | import java.util.Collections; 18 | import java.util.List; 19 | import java.util.regex.Pattern; 20 | 21 | public class TextureEntry 22 | { 23 | public static final Pattern KEY_PATTERN = Pattern.compile("[a-z_0-9]+"); 24 | 25 | private String key; 26 | private TexturePath path; 27 | 28 | private BufferedImage source; 29 | private ImageIcon icon; 30 | private List textures; 31 | 32 | private File textureFile; 33 | private File metaFile; 34 | 35 | private TextureAnimation anim; 36 | 37 | public TextureEntry(File texture) throws IOException 38 | { 39 | this.path = new TexturePath(texture); 40 | this.key = path.getName(); 41 | this.textureFile = texture; 42 | this.source = ImageIO.read(texture); 43 | this.anim = TextureAnimation.getAnimationForTexture(texture, this.source.getWidth(), this.source.getHeight()); 44 | this.icon = createIcon(this.source); 45 | File metaFile = new File(texture.getAbsolutePath() + ".mcmeta"); 46 | if(metaFile.exists()) 47 | { 48 | this.metaFile = metaFile; 49 | } 50 | } 51 | 52 | public TextureEntry(String key, File texture) throws IOException 53 | { 54 | this.key = key; 55 | this.path = new TexturePath(texture); 56 | this.textureFile = texture; 57 | this.source = ImageIO.read(texture); 58 | this.anim = TextureAnimation.getAnimationForTexture(texture, this.source.getWidth(), this.source.getHeight()); 59 | this.icon = createIcon(this.source); 60 | File metaFile = new File(texture.getAbsolutePath() + ".mcmeta"); 61 | if(metaFile.exists()) 62 | { 63 | this.metaFile = metaFile; 64 | } 65 | } 66 | 67 | public TextureEntry(String key, TexturePath path, File texture) throws IOException 68 | { 69 | this.key = key; 70 | this.path = path; 71 | this.textureFile = texture; 72 | this.source = ImageIO.read(texture); 73 | this.anim = TextureAnimation.getAnimationForTexture(texture, this.source.getWidth(), this.source.getHeight()); 74 | this.icon = createIcon(this.source); 75 | File metaFile = new File(texture.getAbsolutePath() + ".mcmeta"); 76 | if(metaFile.exists()) 77 | { 78 | this.metaFile = metaFile; 79 | } 80 | } 81 | 82 | public void setTexturePath(TexturePath path) 83 | { 84 | this.path = path; 85 | } 86 | 87 | public TexturePath getTexturePath() 88 | { 89 | return path; 90 | } 91 | 92 | public String getKey() 93 | { 94 | return key; 95 | } 96 | 97 | public void setKey(String key) 98 | { 99 | this.key = key; 100 | } 101 | 102 | public String getModId() 103 | { 104 | return path.getModId(); 105 | } 106 | 107 | public String getDirectory() 108 | { 109 | return path.getDirectory(); 110 | } 111 | 112 | public String getName() 113 | { 114 | return path.getName(); 115 | } 116 | 117 | public void bindTexture() 118 | { 119 | if(textures != null) 120 | { 121 | GL11.glBindTexture(GL11.GL_TEXTURE_2D, textures.get(this.isAnimated() ? anim.getCurrentAnimationFrame() : 0)); 122 | } 123 | } 124 | 125 | public void bindNextTexture() 126 | { 127 | if(textures != null) 128 | { 129 | GL11.glBindTexture(GL11.GL_TEXTURE_2D, textures.get(this.isAnimated() ? anim.getNextAnimationFrame() : 0)); 130 | } 131 | } 132 | 133 | public BufferedImage getSource() 134 | { 135 | return source; 136 | } 137 | 138 | public ImageIcon getIcon() 139 | { 140 | return icon; 141 | } 142 | 143 | public TextureAnimation getAnimation() 144 | { 145 | return anim; 146 | } 147 | 148 | public boolean isAnimated() 149 | { 150 | return anim != null; 151 | } 152 | 153 | public int getPasses() 154 | { 155 | if(anim != null) 156 | { 157 | return anim.getPasses(); 158 | } 159 | return 1; 160 | } 161 | 162 | public File getTextureFile() 163 | { 164 | return textureFile; 165 | } 166 | 167 | public void setTextureFile(File texture) 168 | { 169 | try 170 | { 171 | this.textureFile = texture; 172 | this.source = ImageIO.read(texture); 173 | this.icon = createIcon(this.source); 174 | this.anim = TextureAnimation.getAnimationForTexture(texture, source.getWidth(), source.getHeight()); 175 | TextureManager.loadTexture(this); 176 | } 177 | catch(IOException e) 178 | { 179 | e.printStackTrace(); 180 | } 181 | } 182 | 183 | public void deleteTexture() 184 | { 185 | if(textures != null) 186 | { 187 | for(int i : textures) 188 | { 189 | GL11.glDeleteTextures(i); 190 | } 191 | textures = null; 192 | } 193 | } 194 | 195 | private static ImageIcon createIcon(BufferedImage source) 196 | { 197 | source = source.getSubimage(0, 0, source.getWidth(), source.getWidth()); 198 | Image scaledImage = source.getScaledInstance(64, 64, java.awt.Image.SCALE_FAST); 199 | return new ImageIcon(scaledImage); 200 | } 201 | 202 | public void loadTexture() 203 | { 204 | if(textures == null) 205 | { 206 | if(anim == null) 207 | { 208 | this.textures = Collections.singletonList(loadTexture(source)); 209 | } 210 | else 211 | { 212 | List textures = new ArrayList<>(); 213 | int width = anim.getWidth(); 214 | int height = anim.getHeight(); 215 | int x = 0; 216 | while(x + width <= source.getWidth()) 217 | { 218 | int y = 0; 219 | while(y + height <= source.getHeight()) 220 | { 221 | BufferedImage subImage = source.getSubimage(x, y, width, height); 222 | textures.add(loadTexture(subImage)); 223 | y += height; 224 | } 225 | x += width; 226 | } 227 | this.textures = textures; 228 | } 229 | } 230 | } 231 | 232 | private int loadTexture(BufferedImage image) 233 | { 234 | int[] pixels = new int[image.getWidth() * image.getHeight()]; 235 | image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth()); 236 | ByteBuffer buffer = BufferUtils.createByteBuffer(pixels.length * 4); 237 | for(int y = 0; y < image.getHeight(); y++) 238 | { 239 | for(int x = 0; x < image.getWidth(); x++) 240 | { 241 | int pixel = pixels[y * image.getWidth() + x]; 242 | buffer.put((byte) ((pixel >> 16) & 0xFF)); 243 | buffer.put((byte) ((pixel >> 8) & 0xFF)); 244 | buffer.put((byte) (pixel & 0xFF)); 245 | buffer.put((byte) ((pixel >> 24) & 0xFF)); 246 | } 247 | } 248 | buffer.flip(); 249 | int textureId = GL11.glGenTextures(); 250 | GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); 251 | GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); 252 | GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); 253 | GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); 254 | GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); 255 | GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); 256 | return textureId; 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/ProjectManager.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator; 2 | 3 | import com.mrcrayfish.modelcreator.component.TextureManager; 4 | import com.mrcrayfish.modelcreator.element.Element; 5 | import com.mrcrayfish.modelcreator.element.ElementManager; 6 | import com.mrcrayfish.modelcreator.element.Face; 7 | import com.mrcrayfish.modelcreator.texture.TextureEntry; 8 | 9 | import javax.imageio.ImageIO; 10 | import java.awt.image.BufferedImage; 11 | import java.io.File; 12 | import java.io.FileInputStream; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | import java.nio.file.Files; 16 | import java.nio.file.Path; 17 | import java.util.Comparator; 18 | import java.util.HashSet; 19 | import java.util.Set; 20 | import java.util.regex.Matcher; 21 | import java.util.regex.Pattern; 22 | import java.util.zip.ZipEntry; 23 | import java.util.zip.ZipInputStream; 24 | import java.util.zip.ZipOutputStream; 25 | 26 | public class ProjectManager 27 | { 28 | private static final Pattern TEXTURE_FIX = Pattern.compile("\\d+$"); //Matches numbers at the end of line 29 | 30 | public static void loadProject(ElementManager manager, String modelFile) 31 | { 32 | TextureManager.clear(); 33 | manager.clearElements(); 34 | manager.setParticle(null); 35 | 36 | File projectFolder = extractFiles(modelFile); 37 | if(projectFolder != null) 38 | { 39 | Project project = new Project(projectFolder); 40 | Importer importer = new Importer(manager, project.getModel().getPath()); 41 | importer.importFromJSON(); 42 | } 43 | deleteFolder(projectFolder); 44 | } 45 | 46 | private static void deleteFolder(File file) 47 | { 48 | Runtime.getRuntime().addShutdownHook(new Thread(() -> 49 | { 50 | try 51 | { 52 | Files.walk(file.toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); 53 | } 54 | catch(IOException e) 55 | { 56 | e.printStackTrace(); 57 | } 58 | })); 59 | } 60 | 61 | private static File extractFiles(String modelFile) 62 | { 63 | try 64 | { 65 | Path path = Files.createTempDirectory("ModelCreator"); 66 | File folder = path.toFile(); 67 | 68 | ZipInputStream zis = new ZipInputStream(new FileInputStream(modelFile)); 69 | ZipEntry ze; 70 | while((ze = zis.getNextEntry()) != null) 71 | { 72 | String fileName = ze.getName(); 73 | 74 | /* Fixes old project texture files extracting with numbers on the file name */ 75 | Matcher matcher = TEXTURE_FIX.matcher(ze.getName()); 76 | if(matcher.find()) 77 | { 78 | String numbers = matcher.group(0); 79 | fileName = fileName.replace(numbers, ""); 80 | } 81 | 82 | File file = new File(folder, fileName); 83 | file.getParentFile().mkdirs(); 84 | file.createNewFile(); 85 | 86 | byte[] buffer = new byte[1024]; 87 | FileOutputStream fos = new FileOutputStream(file); 88 | 89 | int len; 90 | while((len = zis.read(buffer)) > 0) 91 | { 92 | fos.write(buffer, 0, len); 93 | } 94 | 95 | fos.flush(); 96 | fos.close(); 97 | zis.closeEntry(); 98 | } 99 | zis.close(); 100 | 101 | return folder; 102 | } 103 | catch(IOException e) 104 | { 105 | e.printStackTrace(); 106 | } 107 | return null; 108 | } 109 | 110 | public static void saveProject(ElementManager manager, String name) 111 | { 112 | try 113 | { 114 | FileOutputStream fos = new FileOutputStream(name); 115 | ZipOutputStream zos = new ZipOutputStream(fos); 116 | 117 | File file = getSaveFile(manager); 118 | addToZipFile(file, zos, "model.json"); 119 | file.delete(); 120 | 121 | for(TextureEntry entry : getAllTextures(manager)) 122 | { 123 | File temp = File.createTempFile(entry.getName(), ""); 124 | BufferedImage image = entry.getSource(); 125 | ImageIO.write(image, "PNG", temp); 126 | addToZipFile(temp, zos, "assets/" + entry.getModId() + "/textures/" + entry.getDirectory() + "/", entry.getName() + ".png"); 127 | temp.delete(); 128 | } 129 | 130 | //TODO make output animation properties 131 | /*for(String metaLocation : getMetaLocations(manager)) 132 | { 133 | if(metaLocation != null) 134 | { 135 | File texture = new File(metaLocation); 136 | if(texture.exists()) 137 | { 138 | addToZipFile(texture, zos, "textures/", texture.getName()); 139 | } 140 | } 141 | }*/ 142 | 143 | zos.close(); 144 | fos.close(); 145 | } 146 | catch(IOException e) 147 | { 148 | e.printStackTrace(); 149 | } 150 | } 151 | 152 | private static Set getAllTextures(ElementManager manager) 153 | { 154 | Set textureEntries = new HashSet<>(); 155 | for(Element element : manager.getAllElements()) 156 | { 157 | for(Face face : element.getAllFaces()) 158 | { 159 | if(face.getTexture() != null) 160 | { 161 | textureEntries.add(face.getTexture()); 162 | } 163 | } 164 | } 165 | return textureEntries; 166 | } 167 | 168 | private static File getSaveFile(ElementManager manager) throws IOException 169 | { 170 | ExporterModel exporter = new ExporterModel(manager); 171 | exporter.setOptimize(false); 172 | exporter.setIncludeNonTexturedFaces(true); 173 | return exporter.writeFile(File.createTempFile("model.json", "")); 174 | } 175 | 176 | private static void addToZipFile(File file, ZipOutputStream zos, String name) throws IOException 177 | { 178 | addToZipFile(file, zos, "", name); 179 | } 180 | 181 | private static void addToZipFile(File file, ZipOutputStream zos, String folder, String name) throws IOException 182 | { 183 | FileInputStream fis = new FileInputStream(file); 184 | ZipEntry zipEntry = new ZipEntry(folder + name); 185 | zos.putNextEntry(zipEntry); 186 | 187 | byte[] bytes = new byte[1024]; 188 | int length; 189 | while((length = fis.read(bytes)) >= 0) 190 | { 191 | zos.write(bytes, 0, length); 192 | } 193 | 194 | zos.closeEntry(); 195 | fis.close(); 196 | } 197 | 198 | private static class Project 199 | { 200 | public File model; 201 | public File textures; 202 | 203 | public Project(File folder) 204 | { 205 | File[] files = folder.listFiles(); 206 | if(files != null) 207 | { 208 | for(File file : files) 209 | { 210 | String name = file.getName(); 211 | if(file.isFile() && name.equals("model.json")) 212 | { 213 | this.model = file; 214 | } 215 | else if(file.isDirectory() && name.equals("textures")) 216 | { 217 | this.textures = file; 218 | } 219 | } 220 | } 221 | } 222 | 223 | public File getModel() 224 | { 225 | return model; 226 | } 227 | 228 | public File getTextures() 229 | { 230 | return textures; 231 | } 232 | } 233 | 234 | private static class ProjectTexture 235 | { 236 | private File texture; 237 | private File meta; 238 | 239 | public ProjectTexture(File texture, File meta) 240 | { 241 | this.texture = texture; 242 | this.meta = meta; 243 | } 244 | 245 | public File getTexture() 246 | { 247 | return texture; 248 | } 249 | 250 | public File getMeta() 251 | { 252 | return meta; 253 | } 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/texture/TextureAnimation.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.texture; 2 | 3 | import com.google.gson.JsonArray; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | import com.google.gson.JsonParser; 7 | 8 | import java.awt.image.BufferedImage; 9 | import java.io.File; 10 | import java.io.FileNotFoundException; 11 | import java.io.FileReader; 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | public class TextureAnimation 18 | { 19 | private int width = 16, height = 16; 20 | 21 | private List frames = new ArrayList<>(); 22 | private Map customTimes = new HashMap<>(); 23 | private int frametime = 1; 24 | private boolean interpolate = false; 25 | 26 | public void setSize(int width, int height) 27 | { 28 | this.width = width; 29 | this.height = height; 30 | } 31 | 32 | public int getWidth() 33 | { 34 | return width; 35 | } 36 | 37 | public int getHeight() 38 | { 39 | return height; 40 | } 41 | 42 | public void setFrameTime(int frametime) 43 | { 44 | this.frametime = frametime; 45 | } 46 | 47 | public void setFrames(List frameList) 48 | { 49 | frames = new ArrayList<>(); 50 | frames.addAll(frameList); 51 | } 52 | 53 | public void setCustomTimes(Map times) 54 | { 55 | customTimes = new HashMap<>(); 56 | customTimes.putAll(times); 57 | } 58 | 59 | public void setInterpolate(boolean interpolate) 60 | { 61 | this.interpolate = interpolate; 62 | } 63 | 64 | public boolean isInterpolated() 65 | { 66 | return interpolate; 67 | } 68 | 69 | public int getFrameCount() 70 | { 71 | return frames.size(); 72 | } 73 | 74 | public long getMaxTime() 75 | { 76 | long maxTime = 0; 77 | for(int i = 0; i < frames.size(); i++) 78 | { 79 | maxTime += getFrameTime(i); 80 | } 81 | return maxTime; 82 | } 83 | 84 | public int getCurrentAnimationFrame() 85 | { 86 | long maxTime = this.getMaxTime(); 87 | if(maxTime > 0) 88 | { 89 | long animTime = System.currentTimeMillis() % maxTime; 90 | for(int i = 0; i < frames.size(); i++) 91 | { 92 | if(animTime < getFrameTime(i)) 93 | { 94 | return frames.get(i); 95 | } 96 | animTime -= getFrameTime(i); 97 | } 98 | } 99 | return 0; 100 | } 101 | 102 | public int getNextAnimationFrame() 103 | { 104 | if(frames.size() < 1) 105 | { 106 | return 0; 107 | } 108 | 109 | long maxTime = 0; 110 | for(int i = 0; i < frames.size(); i++) 111 | { 112 | maxTime += getFrameTime(i); 113 | } 114 | 115 | long animTime = System.currentTimeMillis() % maxTime; 116 | 117 | for(int i = 0; i < frames.size(); i++) 118 | { 119 | if(animTime <= getFrameTime(i)) 120 | { 121 | if(i < frames.size() - 1) 122 | { 123 | return frames.get(i + 1); 124 | } 125 | else 126 | { 127 | return frames.get(0); 128 | } 129 | } 130 | animTime -= getFrameTime(i); 131 | } 132 | 133 | return 0; 134 | } 135 | 136 | public long getFrameTime(int frame) 137 | { 138 | if(customTimes != null && customTimes.containsKey(frame)) 139 | { 140 | return customTimes.get(frame) * 50L; 141 | } 142 | return frametime * 50L; 143 | } 144 | 145 | public double getFrameInterpolation() 146 | { 147 | long maxTime = 0; 148 | for(int i = 0; i < frames.size(); i++) 149 | { 150 | maxTime += getFrameTime(i); 151 | } 152 | 153 | long animTime = System.currentTimeMillis() % maxTime; 154 | 155 | for(int i = 0; i < frames.size(); i++) 156 | { 157 | if(animTime <= getFrameTime(i)) 158 | { 159 | return animTime / (double) getFrameTime(i); 160 | } 161 | animTime -= getFrameTime(i); 162 | } 163 | 164 | return 0; 165 | } 166 | 167 | public int getPasses() 168 | { 169 | if(isInterpolated() && getFrameCount() > 1) 170 | { 171 | return 2; 172 | } 173 | return 1; 174 | } 175 | 176 | public static TextureAnimation getAnimationForTexture(File file, int width, int height) 177 | { 178 | try 179 | { 180 | file = new File(file.getAbsolutePath() + ".mcmeta"); 181 | if(file.exists()) 182 | { 183 | TextureAnimation anim = null; 184 | JsonObject animationObj = null; 185 | JsonParser parser = new JsonParser(); 186 | JsonElement read = parser.parse(new FileReader(file)); 187 | 188 | if(read.isJsonObject()) 189 | { 190 | JsonObject mcMeta = read.getAsJsonObject(); 191 | if(mcMeta.has("animation") && mcMeta.get("animation").isJsonObject()) 192 | { 193 | animationObj = mcMeta.get("animation").getAsJsonObject(); 194 | anim = new TextureAnimation(); 195 | } 196 | } 197 | 198 | if(anim != null && animationObj != null) 199 | { 200 | int frametime = 1; 201 | if(animationObj.has("frametime") && animationObj.get("frametime").isJsonPrimitive()) 202 | { 203 | frametime = animationObj.get("frametime").getAsInt(); 204 | } 205 | anim.setFrameTime(frametime); 206 | 207 | if(animationObj.has("interpolate") && animationObj.get("interpolate").isJsonPrimitive()) 208 | { 209 | boolean interpolate = animationObj.get("interpolate").getAsBoolean(); 210 | anim.setInterpolate(interpolate); 211 | } 212 | 213 | if(animationObj.has("frames") && animationObj.get("frames").isJsonArray()) 214 | { 215 | JsonArray frames = animationObj.get("frames").getAsJsonArray(); 216 | if(frames.size() > 0) 217 | { 218 | List frameList = new ArrayList<>(); 219 | Map customTimes = new HashMap<>(); 220 | 221 | for(int i = 0; i < frames.size(); i++) 222 | { 223 | JsonElement frame = frames.get(i); 224 | 225 | int index = 0; 226 | int time = frametime; 227 | if(frame.isJsonPrimitive()) 228 | { 229 | index = frame.getAsInt(); 230 | } 231 | else if(frame.isJsonObject()) 232 | { 233 | JsonObject frameObj = frame.getAsJsonObject(); 234 | 235 | if(frameObj.has("index") && frameObj.get("index").isJsonPrimitive()) 236 | { 237 | index = frameObj.get("index").getAsInt(); 238 | } 239 | if(frameObj.has("time") && frameObj.get("time").isJsonPrimitive()) 240 | { 241 | time = frameObj.get("time").getAsInt(); 242 | } 243 | } 244 | 245 | frameList.add(index); 246 | if(time != frametime) 247 | { 248 | customTimes.put(frameList.size() - 1, time); 249 | } 250 | } 251 | 252 | anim.setFrames(frameList); 253 | anim.setCustomTimes(customTimes); 254 | } 255 | } 256 | else 257 | { 258 | int columns = width / 16; 259 | List frameList = new ArrayList<>(); 260 | for(int i = 0; i < (height / 16) * columns; i++) 261 | { 262 | frameList.add(i); 263 | } 264 | anim.setFrames(frameList); 265 | } 266 | return anim; 267 | } 268 | } 269 | } 270 | catch(FileNotFoundException e) 271 | { 272 | e.printStackTrace(); 273 | } 274 | return null; 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/display/DisplayProperties.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.display; 2 | 3 | import com.mrcrayfish.modelcreator.display.render.*; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * Author: MrCrayfish 10 | */ 11 | public class DisplayProperties 12 | { 13 | public static final Map RENDER_MAP = new HashMap<>(); 14 | public static final DisplayProperties MODEL_CREATOR_BLOCK; 15 | public static final DisplayProperties DEFAULT_BLOCK; 16 | public static final DisplayProperties DEFAULT_ITEM; 17 | 18 | static 19 | { 20 | MODEL_CREATOR_BLOCK = new DisplayProperties("Model Creator Block", true); 21 | MODEL_CREATOR_BLOCK.add("gui", 30, 45, 0, 0, 0, 0, 0.625, 0.625, 0.625, true); 22 | MODEL_CREATOR_BLOCK.add("ground", 0, 0, 0, 0, 3, 0, 0.25, 0.25, 0.25, true); 23 | MODEL_CREATOR_BLOCK.add("fixed", 0, 180, 0, 0, 0, 0, 1, 1, 1, true); 24 | MODEL_CREATOR_BLOCK.add("head", 0, 180, 0, 0, 0, 0, 1, 1, 1, true); 25 | MODEL_CREATOR_BLOCK.add("firstperson_righthand", 0, 315, 0, 0, 2.5, 0, 0.4, 0.4, 0.4, true); 26 | MODEL_CREATOR_BLOCK.add("firstperson_lefthand", 0, 0, 45, 0, 2.5, 0, 0.4, 0.4, 0.4, false); 27 | MODEL_CREATOR_BLOCK.add("thirdperson_righthand", 75, 315, 0, 0, 2.5, 0, 0.375, 0.375, 0.375, true); 28 | MODEL_CREATOR_BLOCK.add("thirdperson_lefthand", 75, 45, 0, 0, 2.5, 0, 0.375, 0.375, 0.375, false); 29 | 30 | DEFAULT_BLOCK = new DisplayProperties("Default Block", true); 31 | DEFAULT_BLOCK.add("gui", 30, 225, 0, 0, 0, 0, 0.625, 0.625, 0.625, true); 32 | DEFAULT_BLOCK.add("ground", 0, 0, 0, 0, 3, 0, 0.25, 0.25, 0.25, true); 33 | DEFAULT_BLOCK.add("fixed", 0, 0, 0, 0, 0, 0, 0.5, 0.5, 0.5, true); 34 | DEFAULT_BLOCK.add("head", 0, 0, 0, 0, 0, 0, 1, 1, 1, false); 35 | DEFAULT_BLOCK.add("firstperson_righthand", 0, 45, 0, 0, 2.5, 0, 0.4, 0.4, 0.4, true); 36 | DEFAULT_BLOCK.add("firstperson_lefthand", 0, 0, 225, 0, 2.5, 0, 0.4, 0.4, 0.4, true); 37 | DEFAULT_BLOCK.add("thirdperson_righthand", 75, 45, 0, 0, 2.5, 0, 0.375, 0.375, 0.375, true); 38 | DEFAULT_BLOCK.add("thirdperson_lefthand", 75, 225, 0, 0, 2.5, 0, 0.375, 0.375, 0.375, true); 39 | 40 | DEFAULT_ITEM = new DisplayProperties("Default Item", true); 41 | DEFAULT_ITEM.add("gui", 0, 0, 0, 0, 0, 0, 1, 1, 1, true); 42 | DEFAULT_ITEM.add("ground", 0, 0, 0, 0, 2, 0, 0.5, 0.5, 0.5, true); 43 | DEFAULT_ITEM.add("fixed", 0, 180, 0, 0, 0, 0, 1, 1, 1, true); 44 | DEFAULT_ITEM.add("head", 0, 180, 0, 0, 13, 7, 1, 1, 1, true); 45 | DEFAULT_ITEM.add("firstperson_righthand", 0, -90, 25, 1.13, 3.2, 1.13, 0.68, 0.68, 0.68, true); 46 | DEFAULT_ITEM.add("firstperson_lefthand", 0, -90, 25, 1.13, 3.2, 1.13, 0.68, 0.68, 0.68, true); 47 | DEFAULT_ITEM.add("thirdperson_righthand", 0, 0, 0, 0, 3, 1, 0.55, 0.55, 0.55, true); 48 | DEFAULT_ITEM.add("thirdperson_lefthand", 0, 0, 0, 0, 3, 1, 0.55, 0.55, 0.55, true); 49 | 50 | RENDER_MAP.put("head", new HeadPropertyRenderer()); 51 | RENDER_MAP.put("gui", new GuiPropertyRenderer()); 52 | RENDER_MAP.put("ground", new GroundPropertyRenderer()); 53 | RENDER_MAP.put("fixed", new FixedPropertyRenderer()); 54 | RENDER_MAP.put("firstperson_righthand", new FirstPersonPropertyRenderer(false)); 55 | RENDER_MAP.put("thirdperson_righthand", new ThirdPersonPropertyRenderer(false)); 56 | RENDER_MAP.put("firstperson_lefthand", new FirstPersonPropertyRenderer(true)); 57 | RENDER_MAP.put("thirdperson_lefthand", new ThirdPersonPropertyRenderer(true)); 58 | } 59 | 60 | private Map entries = new HashMap<>(); 61 | private String name; 62 | private boolean isDefault = false; 63 | 64 | private DisplayProperties(String name, boolean isDefault) 65 | { 66 | this.name = name; 67 | this.isDefault = isDefault; 68 | } 69 | 70 | public DisplayProperties(DisplayProperties properties) 71 | { 72 | this.name = properties.name; 73 | properties.entries.forEach((id, entry) -> entries.put(id, new Entry(entry))); 74 | } 75 | 76 | public DisplayProperties(String name, DisplayProperties properties) 77 | { 78 | this.name = name; 79 | properties.entries.forEach((id, entry) -> entries.put(id, new Entry(entry))); 80 | } 81 | 82 | 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) 83 | { 84 | Entry entry = new Entry(id, rotationX, rotationY, rotationZ, translationX, translationY, translationZ, scaleX, scaleY, scaleZ); 85 | entry.setEnabled(enabled); 86 | entries.put(id, entry); 87 | } 88 | 89 | public String getName() 90 | { 91 | return name; 92 | } 93 | 94 | public boolean isDefault() 95 | { 96 | return isDefault; 97 | } 98 | 99 | public Entry getEntry(String id) 100 | { 101 | return entries.get(id); 102 | } 103 | 104 | public Map getEntries() 105 | { 106 | return entries; 107 | } 108 | 109 | @Override 110 | public String toString() 111 | { 112 | return name; 113 | } 114 | 115 | public static class Entry 116 | { 117 | private boolean enabled = true; 118 | private String id; 119 | private double rotationX, rotationY, rotationZ; 120 | private double translationX, translationY, translationZ; 121 | private double scaleX, scaleY, scaleZ; 122 | 123 | public Entry(String id, double rotationX, double rotationY, double rotationZ, double translationX, double translationY, double translationZ, double scaleX, double scaleY, double scaleZ) 124 | { 125 | this.id = id; 126 | this.rotationX = rotationX; 127 | this.rotationY = rotationY; 128 | this.rotationZ = rotationZ; 129 | this.translationX = translationX; 130 | this.translationY = translationY; 131 | this.translationZ = translationZ; 132 | this.scaleX = scaleX; 133 | this.scaleY = scaleY; 134 | this.scaleZ = scaleZ; 135 | } 136 | 137 | public Entry(Entry entry) 138 | { 139 | this.enabled = entry.enabled; 140 | this.id = entry.id; 141 | this.rotationX = entry.rotationX; 142 | this.rotationY = entry.rotationY; 143 | this.rotationZ = entry.rotationZ; 144 | this.translationX = entry.translationX; 145 | this.translationY = entry.translationY; 146 | this.translationZ = entry.translationZ; 147 | this.scaleX = entry.scaleX; 148 | this.scaleY = entry.scaleY; 149 | this.scaleZ = entry.scaleZ; 150 | } 151 | 152 | public void setEnabled(boolean enabled) 153 | { 154 | this.enabled = enabled; 155 | } 156 | 157 | public boolean isEnabled() 158 | { 159 | return enabled; 160 | } 161 | 162 | public String getId() 163 | { 164 | return id; 165 | } 166 | 167 | public double getRotationX() 168 | { 169 | return rotationX; 170 | } 171 | 172 | public void setRotationX(double rotationX) 173 | { 174 | this.rotationX = rotationX; 175 | } 176 | 177 | public double getRotationY() 178 | { 179 | return rotationY; 180 | } 181 | 182 | public void setRotationY(double rotationY) 183 | { 184 | this.rotationY = rotationY; 185 | } 186 | 187 | public double getRotationZ() 188 | { 189 | return rotationZ; 190 | } 191 | 192 | public void setRotationZ(double rotationZ) 193 | { 194 | this.rotationZ = rotationZ; 195 | } 196 | 197 | public double getTranslationX() 198 | { 199 | return translationX; 200 | } 201 | 202 | public void setTranslationX(double translationX) 203 | { 204 | this.translationX = translationX; 205 | } 206 | 207 | public double getTranslationY() 208 | { 209 | return translationY; 210 | } 211 | 212 | public void setTranslationY(double translationY) 213 | { 214 | this.translationY = translationY; 215 | } 216 | 217 | public double getTranslationZ() 218 | { 219 | return translationZ; 220 | } 221 | 222 | public void setTranslationZ(double translationZ) 223 | { 224 | this.translationZ = translationZ; 225 | } 226 | 227 | public double getScaleX() 228 | { 229 | return scaleX; 230 | } 231 | 232 | public void setScaleX(double scaleX) 233 | { 234 | this.scaleX = scaleX; 235 | } 236 | 237 | public double getScaleY() 238 | { 239 | return scaleY; 240 | } 241 | 242 | public void setScaleY(double scaleY) 243 | { 244 | this.scaleY = scaleY; 245 | } 246 | 247 | public double getScaleZ() 248 | { 249 | return scaleZ; 250 | } 251 | 252 | public void setScaleZ(double scaleZ) 253 | { 254 | this.scaleZ = scaleZ; 255 | } 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /src/main/java/com/mrcrayfish/modelcreator/util/SharedLibraryLoader.java: -------------------------------------------------------------------------------- 1 | package com.mrcrayfish.modelcreator.util; 2 | 3 | /******************************************************************************* 4 | * Copyright 2011 See AUTHORS file. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | ******************************************************************************/ 18 | 19 | import java.io.*; 20 | import java.lang.reflect.Method; 21 | import java.util.UUID; 22 | import java.util.zip.CRC32; 23 | import java.util.zip.ZipEntry; 24 | import java.util.zip.ZipFile; 25 | 26 | /** 27 | * Loads shared libraries from JAR files. Call {@link SharedLibraryLoader#load() 28 | * to load the required LWJGL 3 native shared libraries. 29 | * 30 | * @author mzechner 31 | * @author Nathan Sweet 32 | */ 33 | public class SharedLibraryLoader 34 | { 35 | 36 | public static final boolean isWindows = System.getProperty("os.name").contains("Windows"); 37 | public static final boolean isLinux = System.getProperty("os.name").contains("Linux"); 38 | public static final boolean isMac = System.getProperty("os.name").contains("Mac"); 39 | public static final boolean is64Bit = System.getProperty("os.arch").equals("amd64") 40 | || System.getProperty("os.arch").equals("x86_64"); 41 | 42 | private static final boolean usingJws; 43 | 44 | static 45 | { 46 | if (!isWindows && !isLinux && !isMac) 47 | { 48 | throw new UnsupportedOperationException("Unknown platform: " + System.getProperty("os.name")); 49 | } 50 | 51 | // Don't extract natives if using JWS. 52 | boolean failed = false; 53 | try 54 | { 55 | Method method = Class.forName("javax.jnlp.ServiceManager").getDeclaredMethod("lookup", 56 | new Class[] { String.class }); 57 | method.invoke(null, "javax.jnlp.PersistenceService"); 58 | } 59 | catch (Throwable ex) 60 | { 61 | failed = true; 62 | } 63 | usingJws = !failed; 64 | } 65 | 66 | /** 67 | * Extracts the LWJGL native libraries from the classpath and sets the 68 | * "org.lwjgl.librarypath" system property. 69 | */ 70 | public static synchronized void load(boolean disableOpenAL) 71 | { 72 | if (usingJws) 73 | return; 74 | 75 | SharedLibraryLoader loader = new SharedLibraryLoader(); 76 | File nativesDir = null; 77 | try 78 | { 79 | if (SharedLibraryLoader.isWindows) 80 | { 81 | 82 | nativesDir = loader.extractFile(SharedLibraryLoader.is64Bit ? "lwjgl64.dll" : "lwjgl.dll", null) 83 | .getParentFile(); 84 | 85 | if (!disableOpenAL) 86 | loader.extractFile(SharedLibraryLoader.is64Bit ? "OpenAL64.dll" : "OpenAL32.dll", 87 | nativesDir.getName()); 88 | 89 | } 90 | else if (SharedLibraryLoader.isMac) 91 | { 92 | 93 | nativesDir = loader.extractFile("liblwjgl.dylib", null).getParentFile(); 94 | 95 | if (!disableOpenAL) 96 | loader.extractFile("openal.dylib", nativesDir.getName()); 97 | 98 | } 99 | else if (SharedLibraryLoader.isLinux) 100 | { 101 | 102 | nativesDir = loader.extractFile(SharedLibraryLoader.is64Bit ? "liblwjgl64.so" : "liblwjgl.so", null) 103 | .getParentFile(); 104 | 105 | if (!disableOpenAL) 106 | loader.extractFile(SharedLibraryLoader.is64Bit ? "libopenal64.so" : "libopenal.so", 107 | nativesDir.getName()); 108 | 109 | } 110 | else 111 | { 112 | throw new UnsupportedOperationException("Unknown platform: " + System.getProperty("os.name")); 113 | } 114 | } 115 | catch (Throwable ex) 116 | { 117 | throw new Error("Unable to extract LWJGL natives.", ex); 118 | } 119 | 120 | System.setProperty("org.lwjgl.librarypath", nativesDir.getAbsolutePath()); 121 | } 122 | 123 | private String nativesJar; 124 | 125 | private SharedLibraryLoader() 126 | { 127 | } 128 | 129 | /** Returns a CRC of the remaining bytes in the stream. */ 130 | private String crc(InputStream input) 131 | { 132 | if (input == null) 133 | throw new IllegalArgumentException("input cannot be null."); 134 | CRC32 crc = new CRC32(); 135 | byte[] buffer = new byte[4096]; 136 | try 137 | { 138 | while (true) 139 | { 140 | int length = input.read(buffer); 141 | if (length == -1) 142 | break; 143 | crc.update(buffer, 0, length); 144 | } 145 | } catch (Exception ex) 146 | { 147 | if (input != null) 148 | { 149 | try 150 | { 151 | input.close(); 152 | } 153 | catch (IOException e) 154 | { 155 | } 156 | } 157 | } 158 | return Long.toString(crc.getValue(), 16); 159 | } 160 | 161 | private InputStream readFile(String path) 162 | { 163 | if (nativesJar == null) 164 | { 165 | InputStream input = SharedLibraryLoader.class.getResourceAsStream("/" + path); 166 | if (input == null) 167 | throw new RuntimeException("Unable to read file for extraction: " + path); 168 | return input; 169 | } 170 | 171 | // Read from JAR. 172 | ZipFile file = null; 173 | try 174 | { 175 | file = new ZipFile(nativesJar); 176 | ZipEntry entry = file.getEntry(path); 177 | if (entry == null) 178 | throw new RuntimeException("Couldn't find '" + path + "' in JAR: " + nativesJar); 179 | return file.getInputStream(entry); 180 | } 181 | catch (IOException ex) 182 | { 183 | throw new RuntimeException("Error reading '" + path + "' in JAR: " + nativesJar, ex); 184 | } 185 | finally 186 | { 187 | if (file != null) 188 | { 189 | try 190 | { 191 | file.close(); 192 | } 193 | catch (IOException e) 194 | { 195 | } 196 | } 197 | } 198 | } 199 | 200 | /** 201 | * Extracts the specified file into the temp directory if it does not already 202 | * exist or the CRC does not match. If file extraction fails and the file exists 203 | * at java.library.path, that file is returned. 204 | * 205 | * @param sourcePath The file to extract from the classpath or JAR. 206 | * @param dirName The name of the subdirectory where the file will be 207 | * extracted. If null, the file's CRC will be used. 208 | * @return The extracted file. 209 | */ 210 | private File extractFile(String sourcePath, String dirName) throws IOException 211 | { 212 | try 213 | { 214 | String sourceCrc = crc(readFile(sourcePath)); 215 | if (dirName == null) 216 | dirName = sourceCrc; 217 | 218 | File extractedFile = getExtractedFile(dirName, new File(sourcePath).getName()); 219 | return extractFile(sourcePath, sourceCrc, extractedFile); 220 | } 221 | catch (RuntimeException ex) 222 | { 223 | // Fallback to file at java.library.path location, eg for applets. 224 | File file = new File(System.getProperty("java.library.path"), sourcePath); 225 | if (file.exists()) 226 | return file; 227 | throw ex; 228 | } 229 | } 230 | 231 | /** 232 | * Returns a path to a file that can be written. Tries multiple locations and 233 | * verifies writing succeeds. 234 | */ 235 | private File getExtractedFile(String dirName, String fileName) 236 | { 237 | // Temp directory with username in path. 238 | File idealFile = new File( 239 | System.getProperty("java.io.tmpdir") + "/lwjgl" + System.getProperty("user.name") + "/" + dirName, 240 | fileName); 241 | if (canWrite(idealFile)) 242 | return idealFile; 243 | 244 | // System provided temp directory. 245 | try 246 | { 247 | File file = File.createTempFile(dirName, null); 248 | if (file.delete()) 249 | { 250 | file = new File(file, fileName); 251 | if (canWrite(file)) 252 | return file; 253 | } 254 | } 255 | catch (IOException ignored) 256 | { 257 | } 258 | 259 | // User home. 260 | File file = new File(System.getProperty("user.home") + "/.lwjgl/" + dirName, fileName); 261 | if (canWrite(file)) 262 | return file; 263 | 264 | // Relative directory. 265 | file = new File(".temp/" + dirName, fileName); 266 | if (canWrite(file)) 267 | return file; 268 | 269 | return idealFile; // Will likely fail, but we did our best. 270 | } 271 | 272 | /** 273 | * Returns true if the parent directories of the file can be created and the 274 | * file can be written. 275 | */ 276 | private boolean canWrite(File file) 277 | { 278 | File parent = file.getParentFile(); 279 | File testFile; 280 | if (file.exists()) 281 | { 282 | if (!file.canWrite() || !canExecute(file)) 283 | return false; 284 | // Don't overwrite existing file just to check if we can write to directory. 285 | testFile = new File(parent, UUID.randomUUID().toString()); 286 | } 287 | else 288 | { 289 | parent.mkdirs(); 290 | if (!parent.isDirectory()) 291 | return false; 292 | testFile = file; 293 | } 294 | try 295 | { 296 | new FileOutputStream(testFile).close(); 297 | if (!canExecute(testFile)) 298 | return false; 299 | return true; 300 | } 301 | catch (Throwable ex) 302 | { 303 | return false; 304 | } 305 | finally 306 | { 307 | testFile.delete(); 308 | } 309 | } 310 | 311 | private boolean canExecute(File file) 312 | { 313 | try 314 | { 315 | if (file.canExecute()) 316 | return true; 317 | 318 | file.setExecutable(true, false); 319 | return file.canExecute(); 320 | } 321 | catch (Exception ignored) 322 | { 323 | } 324 | 325 | return false; 326 | } 327 | 328 | private File extractFile(String sourcePath, String sourceCrc, File extractedFile) throws IOException 329 | { 330 | String extractedCrc = null; 331 | if (extractedFile.exists()) 332 | { 333 | try 334 | { 335 | extractedCrc = crc(new FileInputStream(extractedFile)); 336 | } 337 | catch (FileNotFoundException ignored) 338 | { 339 | } 340 | } 341 | 342 | // If file doesn't exist or the CRC doesn't match, extract it to the temp dir. 343 | if (extractedCrc == null || !extractedCrc.equals(sourceCrc)) 344 | { 345 | try 346 | { 347 | InputStream input = readFile(sourcePath); 348 | extractedFile.getParentFile().mkdirs(); 349 | FileOutputStream output = new FileOutputStream(extractedFile); 350 | byte[] buffer = new byte[4096]; 351 | while (true) 352 | { 353 | int length = input.read(buffer); 354 | if (length == -1) 355 | break; 356 | output.write(buffer, 0, length); 357 | } 358 | input.close(); 359 | output.close(); 360 | } 361 | catch (IOException ex) 362 | { 363 | throw new RuntimeException( 364 | "Error extracting file: " + sourcePath + "\nTo: " + extractedFile.getAbsolutePath(), ex); 365 | } 366 | } 367 | 368 | return extractedFile; 369 | } 370 | 371 | } 372 | --------------------------------------------------------------------------------