-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #70 from ArtifactForms/working2
Working2
- Loading branch information
Showing
24 changed files
with
1,617 additions
and
249 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package engine.animation.skeleton; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import math.Matrix4; | ||
|
||
public class Bone { | ||
|
||
private final String name; | ||
private Bone parent; | ||
private final List<Bone> children; | ||
private Matrix4 localTransform; | ||
private Matrix4 globalTransform; | ||
private Matrix4 inverseBindPose; | ||
private boolean transformDirty = true; | ||
private float weight; | ||
private int index; | ||
|
||
public Bone(String name) { | ||
if (name == null) { | ||
throw new IllegalArgumentException("Name cannot be null."); | ||
} | ||
this.name = name; | ||
this.children = new ArrayList<>(); | ||
this.localTransform = new Matrix4().identity(); | ||
this.globalTransform = new Matrix4().identity(); | ||
this.weight = 1.0f; | ||
} | ||
|
||
public void updateGlobalTransform() { | ||
if (!transformDirty) return; | ||
globalTransform = | ||
(parent != null) ? parent.globalTransform.multiply(localTransform) : localTransform; | ||
transformDirty = false; | ||
} | ||
|
||
public void updateChildrenTransforms() { | ||
for (Bone child : children) { | ||
child.markDirty(); | ||
child.updateGlobalTransform(); | ||
child.updateChildrenTransforms(); | ||
} | ||
} | ||
|
||
public void markDirty() { | ||
transformDirty = true; | ||
} | ||
|
||
public void addChild(Bone child) { | ||
if (child == null) { | ||
throw new IllegalArgumentException("Child bone cannot be null."); | ||
} | ||
if (isAncestorOf(child)) { | ||
throw new IllegalArgumentException("Cannot add a child that would create a cycle."); | ||
} | ||
if (child.getParent() != null) { | ||
child.getParent().removeChild(child); | ||
} | ||
children.add(child); | ||
child.setParent(this); | ||
} | ||
|
||
private boolean isAncestorOf(Bone bone) { | ||
Bone current = this; | ||
while (current != null) { | ||
if (current == bone) { | ||
return true; | ||
} | ||
current = current.getParent(); | ||
} | ||
return false; | ||
} | ||
|
||
public void removeChild(Bone child) { | ||
if (children.remove(child)) { | ||
child.setParent(null); | ||
} | ||
} | ||
|
||
private void setParent(Bone parent) { | ||
if (this.parent == parent) return; | ||
this.parent = parent; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public Bone getParent() { | ||
return parent; | ||
} | ||
|
||
public List<Bone> getChildren() { | ||
return Collections.unmodifiableList(children); | ||
} | ||
|
||
public Matrix4 getLocalTransform() { | ||
return new Matrix4(localTransform); | ||
} | ||
|
||
public void setLocalTransform(Matrix4 localTransform) { | ||
if (localTransform == null) { | ||
throw new IllegalArgumentException("LocalTransform cannot be null."); | ||
} | ||
this.localTransform = localTransform; | ||
markDirty(); | ||
} | ||
|
||
public Matrix4 getGlobalTransform() { | ||
return new Matrix4(globalTransform); | ||
} | ||
|
||
public Matrix4 getInverseBindPose() { | ||
return new Matrix4(inverseBindPose); | ||
} | ||
|
||
public void setInverseBindPose(Matrix4 bindPose) { | ||
this.inverseBindPose = bindPose.invert(); | ||
} | ||
|
||
public float getWeight() { | ||
return weight; | ||
} | ||
|
||
public void setWeight(float weight) { | ||
if (weight < 0.0f || weight > 1.0f) { | ||
throw new IllegalArgumentException("Weight must be between 0.0 and 1.0."); | ||
} | ||
this.weight = weight; | ||
} | ||
|
||
public int getIndex() { | ||
return index; | ||
} | ||
|
||
public void setIndex(int index) { | ||
this.index = index; | ||
} | ||
|
||
public void printHierarchy(int depth) { | ||
System.out.println(" ".repeat(depth) + name); | ||
for (Bone child : children) { | ||
child.printHierarchy(depth + 1); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package engine.animation.skeleton; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
public class Skeleton { | ||
|
||
private Bone rootBone; | ||
|
||
private final Map<String, Bone> allBones; | ||
|
||
public Skeleton(Bone rootBone) { | ||
this.rootBone = rootBone; | ||
this.allBones = new HashMap<>(); | ||
collectBones(rootBone); | ||
} | ||
|
||
private void collectBones(Bone bone) { | ||
allBones.put(bone.getName(), bone); | ||
for (Bone child : bone.getChildren()) { | ||
collectBones(child); | ||
} | ||
} | ||
|
||
public Bone getBone(String name) { | ||
return allBones.get(name); | ||
} | ||
|
||
public void update() { | ||
if (rootBone != null) { | ||
rootBone.updateGlobalTransform(); | ||
} | ||
} | ||
|
||
public Bone getRootBone() { | ||
return rootBone; | ||
} | ||
|
||
public void setRootBone(Bone rootBone) { | ||
this.rootBone = rootBone; | ||
allBones.clear(); | ||
collectBones(rootBone); | ||
} | ||
|
||
public List<Bone> getAllBones() { | ||
return new ArrayList<>(allBones.values()); | ||
} | ||
|
||
public void printHierarchy() { | ||
printHierarchy(rootBone, 0); | ||
} | ||
|
||
private void printHierarchy(Bone bone, int level) { | ||
for (int i = 0; i < level; i++) { | ||
System.out.print(" "); | ||
} | ||
System.out.println(bone.getName()); | ||
for (Bone child : bone.getChildren()) { | ||
printHierarchy(child, level + 1); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/** | ||
* The CrossLineReticle class represents a visual reticle consisting of cross lines rendered on a | ||
* plane. It is designed to be part of a 3D scene and implements the {@link RenderableComponent} | ||
* interface for rendering capabilities. | ||
* | ||
* <p>The reticle is created as a textured plane using a {@link Mesh3D} and is configurable with | ||
* parameters like radius, thickness, and color. The texture is generated dynamically. | ||
*/ | ||
package engine.components; | ||
|
||
import java.awt.Graphics2D; | ||
import java.awt.image.BufferedImage; | ||
|
||
import engine.resources.FilterMode; | ||
import engine.resources.Texture; | ||
import engine.resources.TextureManager; | ||
import math.Color; | ||
import math.Mathf; | ||
import mesh.Mesh3D; | ||
import mesh.creator.primitives.PlaneCreatorUV; | ||
import mesh.modifier.RotateXModifier; | ||
import workspace.ui.Graphics; | ||
|
||
public class CrossLineReticle extends AbstractComponent implements RenderableComponent { | ||
|
||
/** The radius of the reticle, defining its size. */ | ||
private int radius; | ||
|
||
/** The thickness of the cross lines. */ | ||
private int thickness; | ||
|
||
/** The color of the cross lines. */ | ||
private Color color; | ||
|
||
/** The mesh used to represent the plane of the reticle. */ | ||
private Mesh3D mesh; | ||
|
||
/** The texture used for rendering the reticle. */ | ||
private Texture texture; | ||
|
||
/** Creates a default CrossLineReticle with a radius of 9, thickness of 2, and white color. */ | ||
public CrossLineReticle() { | ||
this(9, 2, Color.WHITE); | ||
} | ||
|
||
/** | ||
* Creates a CrossLineReticle with the specified radius, thickness, and color. | ||
* | ||
* @param radius The radius of the reticle. | ||
* @param thickness The thickness of the cross lines. | ||
* @param color The color of the cross lines. | ||
*/ | ||
public CrossLineReticle(int radius, int thickness, Color color) { | ||
this.radius = radius; | ||
this.color = color; | ||
this.thickness = thickness; | ||
this.mesh = new PlaneCreatorUV(radius).create(); | ||
this.mesh.apply(new RotateXModifier(-Mathf.HALF_PI)); | ||
this.texture = createTexture(); | ||
} | ||
|
||
/** | ||
* Renders the reticle onto the provided {@link Graphics} context. | ||
* | ||
* @param g The graphics context used for rendering. | ||
*/ | ||
@Override | ||
public void render(Graphics g) { | ||
float centerX = g.getWidth() / 2.0f; | ||
float centerY = g.getHeight() / 2.0f; | ||
g.pushMatrix(); | ||
g.translate(centerX, centerY); | ||
g.bindTexture(texture, 0); | ||
g.fillFaces(mesh); | ||
g.unbindTexture(0); | ||
g.popMatrix(); | ||
} | ||
|
||
/** | ||
* Creates a {@link Texture} for the reticle using a dynamically generated {@link BufferedImage}. | ||
* | ||
* @return The generated texture. | ||
*/ | ||
private Texture createTexture() { | ||
BufferedImage image = createTextureImage(); | ||
Texture texture = TextureManager.getInstance().createTexture(image); | ||
texture.setFilterMode(FilterMode.POINT); | ||
return texture; | ||
} | ||
|
||
/** | ||
* Generates a {@link BufferedImage} containing the cross lines of the reticle. | ||
* | ||
* @return The generated image. | ||
*/ | ||
private BufferedImage createTextureImage() { | ||
int size = radius + radius; | ||
BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); | ||
Graphics2D g2d = (Graphics2D) image.getGraphics(); | ||
g2d.setColor(new java.awt.Color(this.color.getRGBA())); | ||
g2d.fillRect(radius - (thickness / 2), 0, thickness, size); | ||
g2d.fillRect(0, radius - (thickness / 2), size, thickness); | ||
return image; | ||
} | ||
|
||
/** | ||
* Called during each update cycle. This reticle does not require updates. | ||
* | ||
* @param tpf The time per frame in seconds. | ||
*/ | ||
@Override | ||
public void onUpdate(float tpf) {} | ||
|
||
/** Called when the component is attached to a {@link engine.SceneNode}. */ | ||
@Override | ||
public void onAttach() {} | ||
|
||
/** Called when the component is detached from a {@link engine.SceneNode}. */ | ||
@Override | ||
public void onDetach() {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.