Ver Fonte

Changes

____tbvns____ há 6 meses atrás
pai
commit
0461a2ba4d

+ 37 - 0
GD4J/src/main/java/xyz/tbvns/Objects/Object.java

@@ -0,0 +1,37 @@
+package xyz.tbvns.Objects;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import xyz.tbvns.Decoder;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+@Slf4j
+@Data
+public class Object {
+    private HashMap<String, String> properties = new HashMap<>();
+
+    public static List<Object> fromLevel(Level level) throws IOException {
+        String data = Decoder.decodeLevel(level.getEncodedLevelString());
+        String[] usableData = data.split(";");
+        List<Object> objects = new ArrayList<>();
+
+        for (int i = 1; i < usableData.length; i++) { //<- 1 here to prevent the first thingy that is not an object
+            String object = usableData[i];
+            String[] usableObject = object.split(",");
+            if (usableObject.length % 2 != 0) {
+                log.error("Detected a broken object:\n{}", object);
+                continue;
+            }
+            Object obj = new Object();
+            for (int j = 0; j < usableObject.length; j+=2) {
+                obj.properties.put(usableObject[j], usableObject[j+1]);
+            }
+            objects.add(obj);
+        }
+        return objects;
+    }
+}

+ 5 - 0
PowerGDEditor/pom.xml

@@ -65,6 +65,11 @@
             <artifactId>imgui-java-natives-macos</artifactId>
             <version>1.86.11</version>
         </dependency>
+        <dependency>
+            <groupId>xyz.tbvns</groupId>
+            <artifactId>GD4J</artifactId>
+            <version>1.0-ALPHA</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 45 - 0
PowerGDEditor/src/main/java/xyz/tbvns/GeometryDash/LevelUtils.java

@@ -0,0 +1,45 @@
+package xyz.tbvns.GeometryDash;
+
+import com.badlogic.gdx.graphics.Color;
+import com.badlogic.gdx.graphics.g3d.Material;
+import com.badlogic.gdx.graphics.g3d.Model;
+import com.badlogic.gdx.graphics.g3d.ModelCache;
+import com.badlogic.gdx.graphics.g3d.ModelInstance;
+import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
+import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
+import xyz.tbvns.Objects.Level;
+import xyz.tbvns.Objects.Object;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class LevelUtils {
+    private static List<Model> models = new ArrayList<>();
+    private static ModelCache modelCache = new ModelCache();
+
+    public static ModelCache generateModelCache(Level level) throws IOException {
+        modelCache.dispose();
+        for (Model model : models) {
+            model.dispose();
+        }
+        models.clear();
+        modelCache = new ModelCache();
+        modelCache.begin();
+        for (Object object : Object.fromLevel(level)) {
+            Model model =new ModelBuilder().createRect(
+                    0f, 0f, 0f,
+                    1f, 0f, 0f,
+                    1f, 1f, 0f,
+                    0, 1, 0f,
+                    0, 0, 0,
+                    new Material(ColorAttribute.createDiffuse(new Color(0, 0, new Random().nextFloat(0, 1), 0))), 1
+            );
+            models.add(model);
+            modelCache.add(new ModelInstance(model, Float.parseFloat(object.getProperties().get("2")) / 30, Float.parseFloat(object.getProperties().get("3")) / 30, 0));
+        }
+        modelCache.end();
+        return modelCache;
+    }
+}

+ 23 - 0
PowerGDEditor/src/main/java/xyz/tbvns/Inputs/Shortcut.java

@@ -0,0 +1,23 @@
+package xyz.tbvns.Inputs;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.Input;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class Shortcut {
+    public static void check() {
+        if (Gdx.input.isButtonJustPressed(Input.Keys.S)) {
+            System.out.println("yay");
+        }
+        if (Gdx.input.isButtonJustPressed(Input.Keys.SHIFT_LEFT) && Gdx.input.isKeyJustPressed(Input.Keys.S)) {
+            System.out.println("yay");
+        }
+        if (Gdx.input.isButtonJustPressed(Input.Keys.O)) {
+            System.out.println("yay");
+        }
+        if (Gdx.input.isButtonJustPressed(Input.Keys.L)) {
+            Runtime.getRuntime().exit(1);
+        }
+    }
+}

+ 22 - 0
PowerGDEditor/src/main/java/xyz/tbvns/LWJGL3/CustomViewport.java

@@ -0,0 +1,22 @@
+package xyz.tbvns.LWJGL3;
+
+import com.badlogic.gdx.graphics.Camera;
+import com.badlogic.gdx.utils.viewport.ScreenViewport;
+
+public class CustomViewport extends ScreenViewport {
+    public CustomViewport (Camera camera) {
+        setCamera(camera);
+    }
+
+    @Override
+    public void update(int screenWidth, int screenHeight, boolean centerCamera) {
+        setScreenBounds(200, 200, screenWidth, screenHeight - 200);
+        setWorldSize(screenWidth - 200, screenHeight - 300);
+        apply(centerCamera);
+    }
+
+    @Override
+    public void apply(boolean centerCamera) {
+        super.apply(centerCamera);
+    }
+}

+ 4 - 2
PowerGDEditor/src/main/java/xyz/tbvns/LWJGL3/Lwjgl3Launcher.java

@@ -17,7 +17,7 @@ public class Lwjgl3Launcher {
 
     private static Lwjgl3ApplicationConfiguration getDefaultConfiguration() {
         Lwjgl3ApplicationConfiguration configuration = new Lwjgl3ApplicationConfiguration();
-        configuration.setTitle("MiningGame");
+        configuration.setTitle("PowerGD - 3D Editor for GeometryDash");
         //// Vsync limits the frames per second to what your hardware can display, and helps eliminate
         //// screen tearing. This setting doesn't always work on Linux, so the line after is a safeguard.
         configuration.useVsync(true);
@@ -27,10 +27,12 @@ public class Lwjgl3Launcher {
         //// If you remove the above line and set Vsync to false, you can get unlimited FPS, which can be
         //// useful for testing performance, but can also be very stressful to some hardware.
         //// You may also need to configure GPU drivers to fully disable Vsync; this can cause screen tearing.
-        configuration.setWindowedMode(640, 480);
+        configuration.setWindowedMode(1000, 600);
         //// You can change these files; they are in lwjgl3/src/main/resources/ .
         //TODO: vvvv Re add that vvvv
         //configuration.setWindowIcon("libgdx128.png", "libgdx64.png", "libgdx32.png", "libgdx16.png");
+        //Antialiasing
+        configuration.setBackBufferConfig(8, 8, 8, 8, 16, 0, 8);
         return configuration;
     }
 }

+ 13 - 0
PowerGDEditor/src/main/java/xyz/tbvns/LevelInfo.java

@@ -0,0 +1,13 @@
+package xyz.tbvns;
+
+import lombok.Getter;
+import lombok.Setter;
+import xyz.tbvns.Objects.Level;
+
+
+public class LevelInfo {
+    @Getter @Setter
+    private static Level level;
+    @Getter @Setter
+    private static String levelString;
+}

+ 82 - 17
PowerGDEditor/src/main/java/xyz/tbvns/Main.java

@@ -2,47 +2,112 @@ package xyz.tbvns;
 
 import com.badlogic.gdx.ApplicationAdapter;
 import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.InputProcessor;
-import com.badlogic.gdx.backends.headless.HeadlessFiles;
-import com.badlogic.gdx.backends.headless.HeadlessNativesLoader;
-import com.badlogic.gdx.backends.headless.mock.graphics.MockGraphics;
-import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Graphics;
+import com.badlogic.gdx.Input;
+import com.badlogic.gdx.graphics.Camera;
 import com.badlogic.gdx.graphics.GL20;
+import com.badlogic.gdx.graphics.PerspectiveCamera;
 import com.badlogic.gdx.graphics.Texture;
-import com.badlogic.gdx.graphics.g2d.SpriteBatch;
-import com.badlogic.gdx.utils.ScreenUtils;
-import imgui.ImGui;
-import imgui.ImGuiIO;
-import imgui.gl3.ImGuiImplGl3;
-import imgui.glfw.ImGuiImplGlfw;
+import com.badlogic.gdx.graphics.g3d.*;
+import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
+import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
+import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
+import com.badlogic.gdx.math.Vector3;
+import com.badlogic.gdx.utils.viewport.Viewport;
+import xyz.tbvns.Inputs.Shortcut;
+import xyz.tbvns.LWJGL3.CustomViewport;
 import xyz.tbvns.ui.Ui;
 
+import static org.lwjgl.opengl.GL11.GL_CULL_FACE;
+
 /** {@link com.badlogic.gdx.ApplicationListener} implementation shared by all platforms. */
 public class Main extends ApplicationAdapter {
-    private SpriteBatch batch;
+    private ModelBatch batch;
+    private Camera camera;
     private Texture image;
+    private Model worldGrid;
+    private Model levelGrid;
+    private ModelInstance worldGridInstance;
+    private ModelInstance levelGridInstance;
+    private CameraInputController cameraInputController;
+    private Viewport viewport;
+    public static ModelCache modelCache;
 
     @Override
     public void create() {
         Ui.initImGui();
-        batch = new SpriteBatch();
+        batch = new ModelBatch();
+        camera = new PerspectiveCamera(80, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
+        camera.far = Integer.MAX_VALUE;
+        camera.near = 0.000000000001f;
+        viewport = new CustomViewport(camera);
+
         image = new Texture("libgdx.png");
+
+        ModelBuilder builder = new ModelBuilder();
+
+        //TODO: Make the grids configurable
+        worldGrid = builder.createLineGrid(100, 100, 1, 1, new Material(ColorAttribute.createDiffuse(0.2f, 0.2f, 0.2f, 1)), 1);
+        levelGrid = builder.createLineGrid(35, 35, 1, 1, new Material(ColorAttribute.createDiffuse(0.3f, 0.3f, 0.3f, 1)), 1);
+        worldGridInstance = new ModelInstance(worldGrid);
+        levelGridInstance = new ModelInstance(levelGrid);
+        levelGridInstance.transform.setToRotation(new Vector3(1, 0, 0), 90);
+        levelGridInstance.transform.setTranslation(new Vector3(0, 50, 0));
+
+        cameraInputController = new CameraInputController(camera);
+        cameraInputController.forwardKey = Input.Keys.W;
+        cameraInputController.backwardKey = Input.Keys.S;
+        cameraInputController.rotateRightKey = -1;
+        cameraInputController.rotateLeftKey = -1;
+        Gdx.input.setInputProcessor(cameraInputController);
     }
 
     @Override
     public void render() {
-        ScreenUtils.clear(0.15f, 0.15f, 0.2f, 1f);
-        batch.begin();
-        batch.draw(image, 140, 210);
-        batch.end();
+        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
+        Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
+        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
+        Gdx.gl.glDisable(GL_CULL_FACE);
+
+        viewport.setScreenPosition(200, 200);
+        viewport.update(Gdx.graphics.getWidth() - 200, Gdx.graphics.getHeight(), false);
+
+        Vector3 gridPos = new Vector3(camera.position);
+        gridPos.x = Math.round(gridPos.x);
+        gridPos.y = 0;
+        gridPos.z = Math.round(gridPos.z);
 
+        worldGridInstance.transform.setTranslation(gridPos);
+
+        gridPos = new Vector3(camera.position);
+        gridPos.x = Math.round(gridPos.x);
+        gridPos.y = Math.round(gridPos.y);
+        gridPos.z = 0;
+
+        levelGridInstance.transform.setTranslation(gridPos);
+
+        cameraInputController.update();
+        batch.begin(camera);
+        batch.render(worldGridInstance);
+        batch.render(levelGridInstance);
+        if (modelCache != null) {
+            batch.render(modelCache);
+        }
+        batch.end();
         Ui.render();
+        Shortcut.check();
     }
 
     @Override
     public void dispose() {
         batch.dispose();
         image.dispose();
+        worldGrid.dispose();
+        levelGrid.dispose();
         Ui.dispose();
     }
+
+    @Override
+    public void resize(int width, int height) {
+
+    }
 }

+ 12 - 0
PowerGDEditor/src/main/java/xyz/tbvns/Models/Face.java

@@ -0,0 +1,12 @@
+package xyz.tbvns.Models;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Face {
+    public List<Integer> points = new ArrayList<>();
+    public boolean Has4Point = false;
+    public Color color = new Color(0, 0, 0);
+    public Integer colorId = 0;
+}

+ 33 - 0
PowerGDEditor/src/main/java/xyz/tbvns/Models/ReadMTL.java

@@ -0,0 +1,33 @@
+package xyz.tbvns.Models;
+
+import java.awt.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class ReadMTL {
+    public static HashMap<String, Color> getColors(File file) throws FileNotFoundException {
+        BufferedReader reader = new BufferedReader(new FileReader(file));
+        HashMap<String, Color> materials = new HashMap<>();
+        AtomicReference<String> name = new AtomicReference<>("");
+
+        reader.lines().forEach(l -> {
+            if (l.startsWith("newmtl")) {
+                String[] s = l.split(" ");
+                name.set(s[1]);
+            } else if (l.startsWith("Kd")) {
+                String[] s = l.split(" ");
+                float r = Float.parseFloat(s[1]);
+                float g = Float.parseFloat(s[2]);
+                float b = Float.parseFloat(s[3]);
+
+                materials.put(name.get(), new Color(r, g, b));
+            }
+        });
+
+        return materials;
+    }
+}

+ 125 - 0
PowerGDEditor/src/main/java/xyz/tbvns/Models/ReadOBJ.java

@@ -0,0 +1,125 @@
+package xyz.tbvns.Models;
+
+import lombok.extern.slf4j.Slf4j;
+import org.joml.Vector4f;
+
+import java.awt.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+@Slf4j
+public class ReadOBJ {
+    public ArrayList<Vector4f> getPoints(File OBJFile) throws FileNotFoundException {
+        BufferedReader reader = new BufferedReader(new FileReader(OBJFile));
+        ArrayList<Vector4f> Points = new ArrayList<>();
+        reader.lines().forEach(l -> {
+            if (l.startsWith("v ")) {
+                String substring = l.substring(2);
+                String[] cord = substring.split(" ");
+                Vector4f vector4f = new Vector4f();
+                vector4f.x = Float.parseFloat(cord[0]);
+                vector4f.y = Float.parseFloat(cord[1]);
+                vector4f.z = Float.parseFloat(cord[2]);
+                Points.add(vector4f);
+            }
+        });
+        return Points;
+    }
+
+    public ArrayList<Face> getFace(File OBJFile, File MTLFile) throws FileNotFoundException {
+        BufferedReader reader = new BufferedReader(new FileReader(OBJFile));
+        ArrayList<Face> Faces = new ArrayList<>();
+        AtomicReference<HashMap<String, Color>> materials = new AtomicReference<>(new HashMap<>());
+        AtomicReference<Color> color = new AtomicReference<>(new Color(0, 0, 0));
+        reader.lines().forEach(l -> {
+                try {
+                    materials.set(ReadMTL.getColors(MTLFile));
+                } catch (FileNotFoundException e) {
+                    throw new RuntimeException(e);
+                }
+
+                if (l.startsWith("usemtl")) {
+                    color.set(materials.get().get(l.split(" ")[1]));
+                }
+
+            if (l.startsWith("f")) {
+                Face face = new Face();
+                String substring = l.substring(2);
+                String[] cord = substring.split(" ");
+                if (cord.length == 3) {
+                    for (int i = 0; i < cord.length; i++) {
+                        String id = cord[i].split("/")[0];
+                        face.points.add(Integer.valueOf(id));
+                    }
+
+                    face.color = color.get();
+
+                    Faces.add(face);
+                } else if (cord.length == 4) {
+                    for (int i = 0; i < cord.length; i++) {
+                        String id = cord[i].split("/")[0];
+                        face.points.add(Integer.valueOf(id));
+                    }
+                    face.Has4Point = true;
+
+                    face.color = color.get();
+
+                    Faces.add(face);
+                } else {
+                    log.error("A face had more than 4 point, ignoring it");
+                }
+            }
+        });
+        return Faces;
+    }
+
+    public ArrayList<Face> getFaceAnimation(File OBJFile, File MTLFile) throws FileNotFoundException {
+        BufferedReader reader = new BufferedReader(new FileReader(OBJFile));
+        ArrayList<Face> Faces = new ArrayList<>();
+        AtomicReference<HashMap<String, Color>> materials = new AtomicReference<>(new HashMap<>());
+        AtomicReference<Color> color = new AtomicReference<>(new Color(0, 0, 0));
+        reader.lines().forEach(l -> {
+            try {
+                materials.set(ReadMTL.getColors(MTLFile));
+            } catch (FileNotFoundException e) {
+                throw new RuntimeException(e);
+            }
+            if (l.startsWith("usemtl")) {
+                color.set(materials.get().get(l.split(" ")[1]));
+            }
+            if (l.startsWith("f")) {
+                Face face = new Face();
+                String substring = l.substring(2);
+                String[] cord = substring.split(" ");
+                if (cord.length == 3) {
+                    for (int i = 0; i < cord.length; i++) {
+                        String id = cord[i].split("/")[0];
+                        face.points.add(Integer.valueOf(id));
+                    }
+
+                    face.color = color.get();
+
+                    Faces.add(face);
+                } else if (cord.length == 4) {
+                    for (int i = 0; i < cord.length; i++) {
+                        String id = cord[i].split("/")[0];
+                        face.points.add(Integer.valueOf(id));
+                    }
+                    face.Has4Point = true;
+
+                    face.color = color.get();
+
+                    Faces.add(face);
+                } else {
+                    log.error("A face had more than 4 point, ignoring it");
+                }
+            }
+        });
+        return Faces;
+    }
+}

+ 54 - 0
PowerGDEditor/src/main/java/xyz/tbvns/ui/LevelSelector.java

@@ -0,0 +1,54 @@
+package xyz.tbvns.ui;
+
+import imgui.ImGui;
+import imgui.flag.ImGuiInputTextFlags;
+import imgui.flag.ImGuiWindowFlags;
+import imgui.type.ImString;
+import xyz.tbvns.DataManager;
+import xyz.tbvns.Decoder;
+import xyz.tbvns.GeometryDash.LevelUtils;
+import xyz.tbvns.LevelInfo;
+import xyz.tbvns.Main;
+import xyz.tbvns.Objects.Level;
+
+import java.io.IOException;
+import java.util.List;
+
+public class LevelSelector {
+    private static List<Level> levelList;
+    static {
+        try {
+            levelList = DataManager.getLevels();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void update() {
+        try {
+            levelList = DataManager.getLevels();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void render() {
+        ImGui.begin("Load a level:", ImGuiWindowFlags.NoCollapse);
+        ImGui.setWindowFocus();
+        ImString string = new ImString();
+        ImGui.inputTextWithHint("##", "Search...", string, ImGuiInputTextFlags.AutoSelectAll);
+        for (Level level : levelList) {
+            if (level.getName().toLowerCase().contains(string.get().toLowerCase()) && ImGui.button(level.getName())) {
+                try {
+                    Main.modelCache = LevelUtils.generateModelCache(level);
+                    LevelInfo.setLevel(level);
+                    LevelInfo.setLevelString(Decoder.decodeLevel(level.getEncodedLevelString()));
+                    Ui.setShowLevelSelector(false);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+        ImGui.end();
+    }
+}

+ 45 - 1
PowerGDEditor/src/main/java/xyz/tbvns/ui/Ui.java

@@ -8,17 +8,56 @@ import imgui.ImGuiIO;
 import imgui.flag.ImGuiWindowFlags;
 import imgui.gl3.ImGuiImplGl3;
 import imgui.glfw.ImGuiImplGlfw;
+import lombok.Setter;
 import xyz.tbvns.Main;
 
 public class Ui {
+    @Setter
+    private static boolean showLevelSelector = true;
+
     static private ImGuiImplGlfw imGuiGlfw;
     static private ImGuiImplGl3 imGuiGl3;
     private static InputProcessor tmpProcessor;
 
     public static void render() {
         startImGui();
+
+        //TODO: Add functionality
         ImGui.beginMainMenuBar();
-        ImGui.button("Button world !");
+
+        if (ImGui.beginMenu("Files")) {
+            ImGui.menuItem("Save", "CTRL S");
+            ImGui.menuItem("Export", "SHIFT S");
+            if (ImGui.menuItem("Open", "O")) {
+                //TODO: Add save dialog if the level was modified
+                showLevelSelector = true;
+                Main.modelCache = null;
+            }
+            ImGui.menuItem("Close", "C");
+            ImGui.endMenu();
+        }
+
+        if (ImGui.beginMenu("View")) {
+            ImGui.checkbox("Level grid", true);
+            ImGui.checkbox("World grid", true);
+            ImGui.endMenu();
+        }
+
+        if (ImGui.beginMenu("Tools")) {
+            ImGui.menuItem("Edit level string", "L");
+            ImGui.menuItem("BPM to FPS", "B");
+            ImGui.endMenu();
+        }
+
+        if (ImGui.beginMenu("About")) {
+            ImGui.menuItem("Help", "H");
+            ImGui.menuItem("Wiki", "CTRL - H");
+            ImGui.menuItem("Info", "I");
+            ImGui.menuItem("Discord");
+            ImGui.menuItem("Git");
+            ImGui.endMenu();
+        }
+
 
         ImGui.endMainMenuBar();
 
@@ -31,6 +70,11 @@ public class Ui {
         ImGui.setWindowSize(Gdx.graphics.getWidth(), 201);
         ImGui.setWindowPos(0, Gdx.graphics.getHeight() - 201);
         ImGui.end();
+
+        if (showLevelSelector) {
+            LevelSelector.render();
+        }
+
         endImGui();
     }