From ab41020e1ccbb5a80e3e0691c65f0d583d4c758b Mon Sep 17 00:00:00 2001 From: austin Date: Tue, 3 May 2022 16:36:57 -0400 Subject: [PATCH] Basic character editor ui functional --- assets/Data/creatures/human.json | 8 + .../electrosphere/menu/MenuGenerators.java | 61 +---- .../menu/MenuGeneratorsMultiplayer.java | 51 +++- .../renderer/actor/ActorStaticMorph.java | 56 ++++- .../renderer/ui/elements/ActorPanel.java | 230 ++++++++++++++++++ 5 files changed, 337 insertions(+), 69 deletions(-) create mode 100644 src/main/java/electrosphere/renderer/ui/elements/ActorPanel.java diff --git a/assets/Data/creatures/human.json b/assets/Data/creatures/human.json index a3b12199..7a795e9c 100644 --- a/assets/Data/creatures/human.json +++ b/assets/Data/creatures/human.json @@ -68,6 +68,14 @@ "primaryBone" : "UpperTorso", "minValue" : -0.2, "maxValue" : 0.2 + }, + { + "attributeId" : "HeadWidth", + "type" : "bone", + "subtype" : "scalex", + "primaryBone" : "Head", + "minValue" : 0.8, + "maxValue" : 1.2 } ], "movementSystems" : [ diff --git a/src/main/java/electrosphere/menu/MenuGenerators.java b/src/main/java/electrosphere/menu/MenuGenerators.java index b4828338..6855e517 100644 --- a/src/main/java/electrosphere/menu/MenuGenerators.java +++ b/src/main/java/electrosphere/menu/MenuGenerators.java @@ -785,64 +785,9 @@ public class MenuGenerators { float minVal = attribute.getMinValue(); float range = attribute.getMaxValue() - minVal; float actualValue = minVal + range * value; - switch(attribute.getSubtype()){ - case "yaw": - staticMorph.setYaw(attribute.getPrimaryBone(), actualValue); - if(attribute.getMirrorBone() != null){ - staticMorph.setYaw(attribute.getMirrorBone(), -actualValue); - } - break; - case "pitch": - staticMorph.setPitch(attribute.getPrimaryBone(), actualValue); - if(attribute.getMirrorBone() != null){ - staticMorph.setPitch(attribute.getMirrorBone(), -actualValue); - } - break; - case "roll": - staticMorph.setRoll(attribute.getPrimaryBone(), actualValue); - if(attribute.getMirrorBone() != null){ - staticMorph.setRoll(attribute.getMirrorBone(), -actualValue); - } - break; - case "scalex": - staticMorph.setScaleX(attribute.getPrimaryBone(), actualValue); - if(attribute.getMirrorBone() != null){ - staticMorph.setScaleX(attribute.getMirrorBone(), -actualValue); - } - break; - case "scaley": - staticMorph.setScaleY(attribute.getPrimaryBone(), actualValue); - if(attribute.getMirrorBone() != null){ - staticMorph.setScaleY(attribute.getMirrorBone(), -actualValue); - } - break; - case "scalez": - staticMorph.setScaleZ(attribute.getPrimaryBone(), actualValue); - if(attribute.getMirrorBone() != null){ - staticMorph.setScaleZ(attribute.getMirrorBone(), -actualValue); - } - break; - case "offx": - staticMorph.setOffsetX(attribute.getPrimaryBone(), actualValue); - if(attribute.getMirrorBone() != null){ - staticMorph.setOffsetX(attribute.getMirrorBone(), -actualValue); - } - break; - case "offy": - staticMorph.setOffsetY(attribute.getPrimaryBone(), actualValue); - if(attribute.getMirrorBone() != null){ - staticMorph.setOffsetY(attribute.getMirrorBone(), -actualValue); - } - break; - case "offz": - staticMorph.setOffsetZ(attribute.getPrimaryBone(), actualValue); - if(attribute.getMirrorBone() != null){ - staticMorph.setOffsetZ(attribute.getMirrorBone(), -actualValue); - } - break; - case "offl": - //TODO - break; + staticMorph.updateValue(attribute.getSubtype(), attribute.getPrimaryBone(), event.getAsFloat()); + if(attribute.getMirrorBone() != null){ + staticMorph.updateValue(attribute.getSubtype(), attribute.getMirrorBone(), event.getAsFloat()); } }}); scrollable.addChild(attributeSlider); diff --git a/src/main/java/electrosphere/menu/MenuGeneratorsMultiplayer.java b/src/main/java/electrosphere/menu/MenuGeneratorsMultiplayer.java index a769c5bc..e128f440 100644 --- a/src/main/java/electrosphere/menu/MenuGeneratorsMultiplayer.java +++ b/src/main/java/electrosphere/menu/MenuGeneratorsMultiplayer.java @@ -3,15 +3,24 @@ package electrosphere.menu; import java.util.LinkedList; import java.util.List; +import org.joml.Quaternionf; import org.joml.Vector3f; +import electrosphere.entity.types.camera.CameraEntityUtils; import electrosphere.game.data.creature.type.CreatureType; import electrosphere.game.data.creature.type.visualattribute.AttributeVariant; import electrosphere.game.data.creature.type.visualattribute.VisualAttribute; import electrosphere.main.Globals; +import electrosphere.renderer.Camera; +import electrosphere.renderer.actor.Actor; +import electrosphere.renderer.actor.ActorStaticMorph; +import electrosphere.renderer.actor.ActorUtils; +import electrosphere.renderer.actor.ActorStaticMorph.StaticMorphTransforms; +import electrosphere.renderer.anim.Animation; import electrosphere.renderer.ui.ClickableElement; import electrosphere.renderer.ui.Element; import electrosphere.renderer.ui.ValueElement.ValueChangeEventCallback; +import electrosphere.renderer.ui.elements.ActorPanel; import electrosphere.renderer.ui.elements.Button; import electrosphere.renderer.ui.elements.ImagePanel; import electrosphere.renderer.ui.elements.Label; @@ -78,9 +87,25 @@ public class MenuGeneratorsMultiplayer { int verticalPosition = 125; int horizontalPosition = 300; + //figure out race data + CreatureType selectedRaceType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(race); + + //spawn camera so renderer doesn't crash (once render pipeline is modularized this shouldn't be necessary) + Globals.playerCamera = CameraEntityUtils.spawnBasicCameraEntity(new Vector3f(0,0,0), new Vector3f(-1,0.2f,0).normalize()); + + //create actor panel + Actor characterActor = ActorUtils.createActorFromModelPath(selectedRaceType.getModelPath()); + ActorPanel actorPanel = new ActorPanel(1200, 100, 500, 500, characterActor); + actorPanel.setAnimation(Animation.ANIMATION_IDLE_1); + actorPanel.setPosition(new Vector3f(-5,-2,0)); + actorPanel.setRotation(new Quaternionf().rotateLocalY((float)(Math.PI/4.0))); + actorPanel.setScale(new Vector3f(0.03f,0.03f,0.03f)); + + //have to build static morph while looping through attributes + ActorStaticMorph staticMorph = new ActorStaticMorph(); + List controlsToAdd = new LinkedList(); //create edit controls here - CreatureType selectedRaceType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(race); for(VisualAttribute attribute : selectedRaceType.getVisualAttributes()){ if(attribute.getType().equals(VisualAttribute.TYPE_BONE)){ //add label for slider @@ -95,6 +120,23 @@ public class MenuGeneratorsMultiplayer { boneSlider.setMaximum(max); boneSlider.setValue(min + (max - min)/2.0f); controlsToAdd.add(boneSlider); + //actually add attributes to static morph + if(attribute.getPrimaryBone() != null && staticMorph.getBoneTransforms(attribute.getPrimaryBone()) == null){ + staticMorph.initBoneTransforms(attribute.getPrimaryBone()); + } + if(attribute.getMirrorBone() != null && staticMorph.getBoneTransforms(attribute.getMirrorBone()) == null){ + staticMorph.initBoneTransforms(attribute.getMirrorBone()); + } + //set callback for when we change the slider value to update the static morph + boneSlider.setOnValueChangeCallback(new ValueChangeEventCallback() {public void execute(ValueChangeEvent event) { + if(characterActor.getStaticMorph() != null){ + ActorStaticMorph staticMorph = characterActor.getStaticMorph(); + staticMorph.updateValue(attribute.getSubtype(), attribute.getPrimaryBone(), event.getAsFloat()); + if(attribute.getMirrorBone() != null){ + staticMorph.updateValue(attribute.getSubtype(), attribute.getMirrorBone(), -event.getAsFloat()); + } + } + }}); } else if(attribute.getType().equals(VisualAttribute.TYPE_REMESH)){ //add label for carousel Label sliderName = new Label(20, verticalPosition, 0.6f); @@ -109,6 +151,8 @@ public class MenuGeneratorsMultiplayer { } verticalPosition = verticalPosition + 100; } + //finally set static morph + characterActor.setActorStaticMorph(staticMorph); //add button to actually create the character Button createCharacterButton = new Button(); @@ -121,13 +165,16 @@ public class MenuGeneratorsMultiplayer { return false; }}); - int width = 1000; + int width = 1800; int height = verticalPosition + 300; ScrollableContainer scrollable = new ScrollableContainer(0, 0, width, height); for(Element newControl : controlsToAdd){ scrollable.addChild(newControl); } + + + scrollable.addChild(actorPanel); // rVal.addChild(scrollable); // Label testLabel = new Label(100,215,1.0f); diff --git a/src/main/java/electrosphere/renderer/actor/ActorStaticMorph.java b/src/main/java/electrosphere/renderer/actor/ActorStaticMorph.java index a91118aa..6fbb0ad2 100644 --- a/src/main/java/electrosphere/renderer/actor/ActorStaticMorph.java +++ b/src/main/java/electrosphere/renderer/actor/ActorStaticMorph.java @@ -19,60 +19,98 @@ public class ActorStaticMorph { return boneTransformMap.get(boneName); } - public void setYaw(String boneName, float yaw){ + void setYaw(String boneName, float yaw){ if(boneTransformMap.containsKey(boneName)){ boneTransformMap.get(boneName).yaw = yaw; } } - public void setPitch(String boneName, float pitch){ + void setPitch(String boneName, float pitch){ if(boneTransformMap.containsKey(boneName)){ boneTransformMap.get(boneName).pitch = pitch; } } - public void setRoll(String boneName, float roll){ + void setRoll(String boneName, float roll){ if(boneTransformMap.containsKey(boneName)){ boneTransformMap.get(boneName).roll = roll; } } - public void setOffsetX(String boneName, float offsetX){ + void setOffsetX(String boneName, float offsetX){ if(boneTransformMap.containsKey(boneName)){ boneTransformMap.get(boneName).offset.x = offsetX; } } - public void setOffsetY(String boneName, float offsetY){ + void setOffsetY(String boneName, float offsetY){ if(boneTransformMap.containsKey(boneName)){ boneTransformMap.get(boneName).offset.y = offsetY; } } - public void setOffsetZ(String boneName, float offsetZ){ + void setOffsetZ(String boneName, float offsetZ){ if(boneTransformMap.containsKey(boneName)){ boneTransformMap.get(boneName).offset.z = offsetZ; } } - public void setScaleX(String boneName, float scaleX){ + void setScaleX(String boneName, float scaleX){ if(boneTransformMap.containsKey(boneName)){ boneTransformMap.get(boneName).scale.x = scaleX; } } - public void setScaleY(String boneName, float scaleY){ + void setScaleY(String boneName, float scaleY){ if(boneTransformMap.containsKey(boneName)){ boneTransformMap.get(boneName).scale.y = scaleY; } } - public void setScaleZ(String boneName, float scaleZ){ + void setScaleZ(String boneName, float scaleZ){ if(boneTransformMap.containsKey(boneName)){ boneTransformMap.get(boneName).scale.z = scaleZ; } } + /** + * Instead of having this code be duplicated every time we want to update a static morph, putting it in here + */ + public void updateValue(String subtype, String bone, float value){ + switch(subtype){ + case "yaw": + this.setYaw(bone, value); + break; + case "pitch": + this.setPitch(bone, value); + break; + case "roll": + this.setRoll(bone, value); + break; + case "scalex": + this.setScaleX(bone, value); + break; + case "scaley": + this.setScaleY(bone, value); + break; + case "scalez": + this.setScaleZ(bone, value); + break; + case "offx": + this.setOffsetX(bone, value); + break; + case "offy": + this.setOffsetY(bone, value); + break; + case "offz": + this.setOffsetZ(bone, value); + break; + case "offl": + //TODO + break; + } + } + public class StaticMorphTransforms { diff --git a/src/main/java/electrosphere/renderer/ui/elements/ActorPanel.java b/src/main/java/electrosphere/renderer/ui/elements/ActorPanel.java new file mode 100644 index 00000000..352a8fcd --- /dev/null +++ b/src/main/java/electrosphere/renderer/ui/elements/ActorPanel.java @@ -0,0 +1,230 @@ +package electrosphere.renderer.ui.elements; + +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; +import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.glClear; +import static org.lwjgl.opengl.GL11.glClearColor; +import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER; +import static org.lwjgl.opengl.GL30.glBindFramebuffer; + +import electrosphere.logger.LoggerInterface; +import electrosphere.main.Globals; +import electrosphere.main.Main; +import electrosphere.renderer.Material; +import electrosphere.renderer.Model; +import electrosphere.renderer.actor.Actor; +import electrosphere.renderer.framebuffer.Framebuffer; +import electrosphere.renderer.framebuffer.FramebufferUtils; +import electrosphere.renderer.texture.Texture; +import electrosphere.renderer.ui.DraggableElement; +import electrosphere.renderer.ui.DrawableElement; +import electrosphere.renderer.ui.events.DragEvent; +import electrosphere.renderer.ui.events.Event; +import electrosphere.renderer.ui.events.DragEvent.DragEventType; + +public class ActorPanel implements DrawableElement, DraggableElement { + + Material customMat = new Material(); + Framebuffer elementBuffer; + + Actor actor; + Matrix4f modelMatrix = new Matrix4f(); + String currentAnim; + Vector3f actorPosition = new Vector3f(0,0,0); + Quaternionf actorRotation = new Quaternionf(); + Vector3f actorScale = new Vector3f(1,1,1); + + + Vector3f texPosition = new Vector3f(0,0,0); + Vector3f texScale = new Vector3f(1,1,0); + + DragEventCallback onDragStart; + DragEventCallback onDrag; + DragEventCallback onDragRelease; + + public ActorPanel(int x, int y, int width, int height, Actor actor){ + elementBuffer = FramebufferUtils.generateTextureFramebuffer(width, height); + customMat.setTexturePointer(elementBuffer.getTexturePointer()); + this.actor = actor; + this.positionX = x; + this.positionY = y; + this.width = width; + this.height = height; + recalculateModelMatrix(); + } + + + + @Override + public void draw(int parentFramebufferPointer, int parentWidth, int parentHeight) { + + elementBuffer.bind(); +// Globals.renderingEngine.setViewportSize(width, height); + + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if(currentAnim != null){ + if(!actor.isPlayingAnimation() || !actor.isPlayingAnimation(currentAnim)){ + actor.playAnimation(currentAnim,3); + actor.incrementAnimationTime(Main.deltaFrames); + } + } + + actor.applyModelMatrix(modelMatrix); + actor.draw(true); + + //this call binds the screen as the "texture" we're rendering to + //have to call before actually rendering + glBindFramebuffer(GL_FRAMEBUFFER, parentFramebufferPointer); + + float ndcX = (float)positionX/parentWidth; + float ndcY = (float)positionY/parentHeight; + float ndcWidth = (float)width/parentWidth; + float ndcHeight = (float)height/parentHeight; + + Vector3f boxPosition = new Vector3f(ndcX,ndcY,0); + Vector3f boxDimensions = new Vector3f(ndcWidth,ndcHeight,0); + + Model planeModel = Globals.assetManager.fetchModel(ImagePanel.imagePanelModelPath); + if(planeModel != null){ + planeModel.pushUniformToMesh("plane", "mPosition", boxPosition); + planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions); + planeModel.pushUniformToMesh("plane", "tPosition", texPosition); + planeModel.pushUniformToMesh("plane", "tDimension", texScale); + planeModel.meshes.get(0).setMaterial(customMat); + planeModel.drawUI(); + } else { + LoggerInterface.loggerRenderer.ERROR("Actor Panel unable to find plane model!!", new Exception()); + } + } + + public int width = 1; + public int height = 1; + + public int positionX = 0; + public int positionY = 0; + + public int parentWidth = 1; + public int parentHeight = 1; + + public boolean visible = false; + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getPositionX() { + return positionX; + } + + public int getPositionY() { + return positionY; + } + + public boolean getVisible() { + return visible; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setPositionX(int positionX) { + this.positionX = positionX; + } + + public void setPositionY(int positionY) { + this.positionY = positionY; + } + + public void setVisible(boolean draw) { + this.visible = draw; + } + + public void setParentWidth(int width){ + parentWidth = width; + } + + public void setParentHeight(int height){ + this.parentHeight = height; + } + + public void setAnimation(String animation){ + currentAnim = animation; + } + + public void setPosition(Vector3f position){ + this.actorPosition.set(position); + recalculateModelMatrix(); + } + + public void setRotation(Quaternionf rotation){ + this.actorRotation.set(rotation); + recalculateModelMatrix(); + } + + public void setScale(Vector3f scale){ + this.actorScale.set(scale); + recalculateModelMatrix(); + } + + void recalculateModelMatrix(){ + modelMatrix.identity(); + modelMatrix.translate(actorPosition); + modelMatrix.rotate(actorRotation); + modelMatrix.scale(actorScale); + actor.applyModelMatrix(modelMatrix); + } + + public boolean handleEvent(Event event){ + boolean propagate = true; + if(event instanceof DragEvent){ + if(onDragStart != null && ((DragEvent)event).getType() == DragEventType.START){ + if(!onDragStart.execute((DragEvent)event)){ + propagate = false; + } + } + if(onDrag != null && ((DragEvent)event).getType() == DragEventType.DRAG){ + if(!onDrag.execute((DragEvent)event)){ + propagate = false; + } + } + if(onDragRelease != null && ((DragEvent)event).getType() == DragEventType.RELEASE){ + if(!onDragRelease.execute((DragEvent)event)){ + propagate = false; + } + } + } + return propagate; + } + + @Override + public void setOnDragStart(DragEventCallback callback) { + onDragStart = callback; + } + + @Override + public void setOnDrag(DragEventCallback callback) { + onDrag = callback; + } + + @Override + public void setOnDragRelease(DragEventCallback callback) { + onDragRelease = callback; + } + + + +}