/******************************************************************************* * Copyright 2015 Maximilian Stark | Dakror <mail@dakror.de> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package de.dakror.vloxlands.util; import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.util.Locale; import javax.swing.JOptionPane; import javax.swing.UIManager; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.assets.AssetManager; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20; import com.badlogic.gdx.math.Bezier; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.utils.viewport.ScreenViewport; /** * Controls: <br> * <ul> * <li>x - reset bezier * <li>c - copy bezier to clipboard * <li>v - load bezier from clipboard</li> * <li>b - run a example of possible voxel generation using this bezier curve with custom params</li> * <li>n - run a example of possible voxel generation using this bezier curve with last used params</li> * <li>SHIFT+DRAG - drag only on X-Axis</li> * <li>CTRL+DRAG - drag only on Y-Axis</li> * </ul> * * @author Dakror */ public class BezierEditor extends InputListener implements ApplicationListener { Stage stage; SpriteBatch fontBatch; Skin skin; AssetManager assets; BitmapFont font; final float SIZE = 200f; final float X = (380 - SIZE) / 2; final Vector2[] startPos = { new Vector2(X + SIZE, X + SIZE), new Vector2(X + SIZE, X), new Vector2(X, X + SIZE), new Vector2(X, X) }; final Vector2 tmpV = new Vector2(); final Vector2 tmpV2 = new Vector2(); Actor selected; int SAMPLE_POINTS = 100; float SAMPLE_POINT_DISTANCE = 1f / SAMPLE_POINTS; int lastRad; int lastHeight; ImmediateModeRenderer20 renderer; Image[] knobs; Bezier<Vector2> bezier; Bezier<Vector2> bezierLogic; @Override public void create() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { e.printStackTrace(); } stage = new Stage(new ScreenViewport()); fontBatch = new SpriteBatch(); font = new BitmapFont(); assets = new AssetManager(); assets.load("img/gui/knob.png", Texture.class); assets.finishLoading(); skin = new Skin(Gdx.files.internal("skin/default/uiskin.json")); skin.add("knob", assets.get("img/gui/knob.png", Texture.class)); knobs = new Image[4]; renderer = new ImmediateModeRenderer20(false, false, 0); Vector2[] v = new Vector2[4]; Vector2[] w = new Vector2[4]; for (int i = 0; i < knobs.length; i++) { knobs[i] = new Image(skin.getDrawable("knob")); knobs[i].setPosition(startPos[i].x, startPos[i].y); stage.addActor(knobs[i]); v[i] = new Vector2(startPos[i].x, startPos[i].y); w[i] = new Vector2((startPos[i].x - X) / SIZE, (startPos[i].y - X) / SIZE); } bezier = new Bezier<Vector2>(v); bezierLogic = new Bezier<Vector2>(w); stage.addListener(this); stage.getCamera().rotate(Vector3.Z, -270); Gdx.input.setInputProcessor(stage); } @Override public void render() { Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); for (int i = 0; i < knobs.length; i++) { bezier.points.get(i).set(knobs[i].getX() + 12, knobs[i].getY() + 12); bezierLogic.points.get(i).set((knobs[i].getX() - X) / SIZE, (knobs[i].getY() - X) / SIZE); } renderer.begin(stage.getBatch().getProjectionMatrix(), GL20.GL_LINE_STRIP); float val = 0f; while (val <= 1f) { renderer.color(0f, 0f, 0f, 1f); bezier.valueAt(tmpV, val); renderer.vertex(tmpV.x, tmpV.y, 0); val += SAMPLE_POINT_DISTANCE; } renderer.end(); renderer.begin(stage.getBatch().getProjectionMatrix(), GL20.GL_LINE_STRIP); renderer.color(0f, 0f, 0f, 1f); renderer.vertex(bezier.points.get(0).x, bezier.points.get(0).y, 0); renderer.vertex(bezier.points.get(1).x, bezier.points.get(1).y, 0); renderer.end(); renderer.begin(stage.getBatch().getProjectionMatrix(), GL20.GL_LINE_STRIP); renderer.color(0f, 0f, 0f, 1f); renderer.vertex(bezier.points.get(2).x, bezier.points.get(2).y, 0); renderer.vertex(bezier.points.get(3).x, bezier.points.get(3).y, 0); renderer.end(); stage.act(); stage.draw(); fontBatch.begin(); fontBatch.setColor(Color.WHITE); font.draw(fontBatch, s(), 0, 400); fontBatch.end(); } public String s() { return String.format(Locale.ENGLISH, "%.1ff, %.1ff, %.1ff, %.1ff, %.1ff, %.1ff, %.1ff, %.1ff", // bezierLogic.points.get(0).x,// bezierLogic.points.get(0).y,// bezierLogic.points.get(1).x,// bezierLogic.points.get(1).y,// bezierLogic.points.get(2).x,// bezierLogic.points.get(2).y,// bezierLogic.points.get(3).x,// bezierLogic.points.get(3).y); } @Override public void resize(int width, int height) {} @Override public void pause() {} @Override public void resume() {} @Override public void dispose() {} @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { Actor a = stage.hit(x, y, true); if (a != null) selected = a; return true; } @Override public void touchDragged(InputEvent event, float x, float y, int pointer) { if (selected == null) return; float x1 = Gdx.input.isKeyPressed(Keys.CONTROL_LEFT) ? selected.getX() : x - 12; float y1 = Gdx.input.isKeyPressed(Keys.SHIFT_LEFT) ? selected.getY() : y - 12; selected.setPosition(x1, y1); } @Override public void touchUp(InputEvent event, float x, float y, int pointer, int button) { selected = null; } @Override public boolean keyUp(InputEvent event, int keycode) { if (keycode == Keys.X) { for (int i = 0; i < knobs.length; i++) { knobs[i].setPosition(startPos[i].x, startPos[i].y); } } else if (keycode == Keys.C) { Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(s()), null); } else if (keycode == Keys.V) { try { String s = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor); String[] p = s.split(", "); if (p.length != 8) return true; for (int i = 0, j = 0; i < knobs.length; i++) { knobs[i].setX(Float.parseFloat(p[j++]) * SIZE + X); knobs[i].setY(Float.parseFloat(p[j++]) * SIZE + X); } } catch (Exception e) { e.printStackTrace(); } } else if (keycode == Keys.B || keycode == Keys.N) { try { if (keycode == Keys.B || lastRad == 0) { lastRad = Integer.parseInt(JOptionPane.showInputDialog("Maximum Radius (int)")); lastHeight = Integer.parseInt(JOptionPane.showInputDialog("Height / Length (int)")); } String[] lines = new String[lastHeight]; int highest = 0; for (int i = 0; i < lastHeight; i++) { bezierLogic.valueAt(tmpV2, i / (float) lastHeight); int y = (int) Math.floor(tmpV2.y * lastRad); if (y > highest) highest = y; lines[i] = ""; for (int j = 0; j < y; j++) lines[i] += "="; } for (String line : lines) { for (int i = 0; i < Math.round(highest - line.length() / 2f); i++) System.out.print(" "); System.out.print(line); System.out.println(); } } catch (Exception e) { return true; } } return true; } }