Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/main/java/engine/demos/ray/RaycastComponent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package engine.demos.ray;

import engine.components.Component;
import math.Ray3f;

public interface RaycastComponent extends Component {

/**
* Tests the given ray against this component.
*
* @param ray the ray in world space
* @return a RaycastHit if an intersection occurred, otherwise null
*/
RaycastHit raycast(Ray3f ray);
}
29 changes: 29 additions & 0 deletions src/main/java/engine/demos/ray/RaycastHit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package engine.demos.ray;

import engine.scene.SceneNode;
import math.Vector3f;

public class RaycastHit {

private final SceneNode target;
private final Vector3f point;
private final float distance;

public RaycastHit(SceneNode target, Vector3f point, float distance) {
this.target = target;
this.point = point;
this.distance = distance;
}

public SceneNode getTarget() {
return target;
}

public Vector3f getPoint() {
return point;
}

public float getDistance() {
return distance;
}
}
31 changes: 31 additions & 0 deletions src/main/java/engine/demos/ray/RaycastQuery.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package engine.demos.ray;

import engine.scene.SceneNode;
import engine.scene.SceneNodeVisitor;
import math.Ray3f;

public final class RaycastQuery implements SceneNodeVisitor {

private final Ray3f ray;
private RaycastHit closestHit;

public RaycastQuery(Ray3f ray) {
this.ray = ray;
}

@Override
public void visit(SceneNode node) {
for (RaycastComponent rc : node.getComponents(RaycastComponent.class)) {
RaycastHit hit = rc.raycast(ray);
if (hit != null) {
if (closestHit == null || hit.getDistance() < closestHit.getDistance()) {
closestHit = hit;
}
}
}
}

public RaycastHit getResult() {
return closestHit;
}
}
19 changes: 19 additions & 0 deletions src/main/java/engine/demos/ray/Raycaster.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package engine.demos.ray;

import engine.components.Transform;
import engine.scene.camera.Camera;
import math.Ray3f;
import math.Vector3f;

public class Raycaster {

public static Ray3f crossHairRay(Camera camera) {
Transform t = camera.getTransform();

Vector3f origin = t.getPosition();
Vector3f direction = t.getForward();

return new Ray3f(origin, direction);
}

}
104 changes: 104 additions & 0 deletions src/main/java/engine/resources/MaterialLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package engine.resources;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import engine.render.Material;

public class MaterialLoader {
private static final String KEY_NEW_MATERIAL = "newmtl";
private static final String KEY_SHININESS = "Ns";
private static final String KEY_AMBIENT_COLOR = "Ka";
private static final String KEY_DIFFUSE_COLOR = "Kd";
private static final String KEY_SPECULAR_COLOR = "Ks";
private static final String KEY_DISSOLVE = "d"; // opacity
private static final String KEY_DIFFUSE_MAP = "map_Kd";
private static final String KEY_OPACITY_MAP = "map_d";

private Map<String, Material> materials = new HashMap<>();
private String directoryPath;

public Map<String, Material> loadMaterials(String filePath) throws IOException {
directoryPath = filePath.substring(0, filePath.lastIndexOf('/'));
BufferedReader reader = new BufferedReader(new FileReader(filePath));
Material currentMaterial = null;

String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("\\s+", 2);
String keyword = parts[0];

switch (keyword) {
case KEY_NEW_MATERIAL:
currentMaterial = new Material();
currentMaterial.setName(parts[1]);
materials.put(parts[1], currentMaterial);
break;
case KEY_DIFFUSE_COLOR:
currentMaterial.setDiffuse(parseColor(parts[1]));
break;
case KEY_SPECULAR_COLOR:
currentMaterial.setSpecular(parseColor(parts[1]));
break;
case "Ns":
currentMaterial.setShininess(Float.parseFloat(parts[1]));
break;
case KEY_DISSOLVE:
currentMaterial.setOpacity(Float.parseFloat(parts[1]));
break;
case KEY_DIFFUSE_MAP:
String file = parts[1];

System.out.println(parts[1]);

try {
BufferedImage image;
image = ImageIO.read(new File(directoryPath + "/" + file));
Texture texture = TextureManager.getInstance().createTexture(image);

currentMaterial.setDiffuseTexture(texture);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

break;

case KEY_OPACITY_MAP:
String file1 = parts[1];

System.out.println(parts[1]);

try {
BufferedImage image;
image = ImageIO.read(new File(directoryPath + "/" + file1));
Texture opactityMap = TextureManager.getInstance().createTexture(image);

currentMaterial.setOpacityMap(opactityMap);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}

reader.close();
return materials;
}

private float[] parseColor(String line) {
String[] values = line.split(" ");
float red = Float.parseFloat(values[0]);
float green = Float.parseFloat(values[1]);
float blue = Float.parseFloat(values[2]);
return new float[] {red, green, blue};
}
}
75 changes: 75 additions & 0 deletions src/main/java/engine/resources/Model.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package engine.resources;

import java.util.ArrayList;
import java.util.List;

import engine.render.Material;
import mesh.Mesh3D;
import mesh.SubMesh;

public class Model {
private String name;
private Mesh3D mesh;
private List<SubMesh> meshes;
private List<Material> materials;

public Model(String name) {
if (name == null) {
throw new IllegalArgumentException("Name cannot be null");
}
this.name = name;
mesh = new Mesh3D();
meshes = new ArrayList<SubMesh>();
materials = new ArrayList<Material>();
}

public void addSubMesh(SubMesh mesh) {
if (mesh == null) {
throw new IllegalArgumentException("Mesh cannot be null.");
}
meshes.add(mesh);
}

public void addMaterial(Material material) {
if (material == null) {
throw new IllegalArgumentException("Material cannot be null.");
}
// material.setUseLighting(false);
materials.add(material);
}

public String getName() {
return name;
}

public Mesh3D getMesh() {
return mesh;
}

public void setMesh(Mesh3D mesh) {
this.mesh = mesh;
}

public List<SubMesh> getSubMeshes() {
return meshes;
}

public void setUseLighting(boolean useLighting) {
for (Material material : materials) {
material.setUseLighting(useLighting);
}
}

public List<Material> getMaterials() {
return materials;
}

public Material getMaterial(String name) {
for (int i = 0; i < materials.size(); i++) {
Material material = materials.get(i);
if (material.getName().equals(name)) return material;
}
// Exception??
return null;
}
}
25 changes: 25 additions & 0 deletions src/main/java/engine/resources/ModelLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package engine.resources;

public class ModelLoader {

// Core method to load models
public static Model load(String filePath, String extension) {
// String extension = getFileExtension(filePath);
ModelLoaderStrategy loader = getLoaderForExtension(extension);
return loader.load(filePath);
}

// Helper to get appropriate loader
private static ModelLoaderStrategy getLoaderForExtension(String extension) {
switch (extension.toLowerCase()) {
case "obj":
return new OBJLoader();
case "gltf":
return new GLTFLoader();
// case "fbx":
// return new FBXLoader();
default:
throw new UnsupportedOperationException("Unsupported format: " + extension);
}
}
}
Loading
Loading