Train work

This commit is contained in:
2026-07-16 13:02:28 +02:00
parent b43d76bbc2
commit bc17e7886d
11 changed files with 220 additions and 140 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
java.home=C\:/Program Files/Java/jdk25
java.home=C\:/Program Files/Eclipse Adoptium/jdk25
jvm.arguments=
offline.mode=false
override.workspace.settings=true
@@ -17,8 +17,9 @@ public record ID(String domain, String path) implements Comparable<ID> {
public String fileLocation() { return domain+"/"+path; }
public boolean isRoot() { return !path.contains("/"); }
public boolean isRootFolder(String folder) { return path.indexOf('/', folder.length()+1) < 0; }
public boolean isRootFolder(String folder) { return path.indexOf('/', folder.length()+1) == -1; }
public boolean endsWith(String suffix) { return path.endsWith(suffix); }
public boolean startsWith(String prefix) { return path.startsWith(prefix); }
@Override
public final String toString() {
@@ -14,11 +14,11 @@ import speiger.src.coreengine.rendering.input.window.Window;
public interface GraphicsDevice {
public Window getWindow();
public GraphicsSurface createSurface();
public GraphicsCommandBuffer createBuffer(ExecutionType type);
public GraphicsCommandBuffer createCommandBuffer(ExecutionType type);
public GraphicsCommandQueue getQueue();
public VertexBuffer createBuffer(BufferType type, BufferState state);
public VertexBuffer createBuffer(BufferType type, BufferState state, int allocatedBytes);
public Texture createTexture(TextureSettings data, int width, int height);
public Sampler createSampler(SamplerSettings settings);
public Mesh createMesh(Mesh.Builder builder, boolean autocreate);
public Mesh createMesh(Mesh.Builder builder);
}
@@ -1,7 +1,14 @@
package speiger.src.coreengine.graphics.api.mesh;
import java.util.Objects;
import java.util.OptionalInt;
import org.jspecify.annotations.Nullable;
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
import speiger.src.coreengine.graphics.api.buffer.states.BufferState;
import speiger.src.coreengine.graphics.api.buffer.states.IndeciesType;
import speiger.src.coreengine.graphics.api.utils.GraphicsResource;
import speiger.src.coreengine.graphics.api.vertex.VertexLayout;
@@ -12,7 +19,7 @@ public abstract class Mesh implements GraphicsResource {
protected VertexBuffer indeciesBuffer;
protected IndeciesType indeciesType;
public Mesh(Int2ObjectMap<LayoutInfo> layouts, Int2ObjectMap<VertexBuffer> buffers, VertexBuffer indeciesBuffer) {
public Mesh(Int2ObjectMap<LayoutInfo> layouts, Int2ObjectMap<VertexBuffer> buffers, @Nullable VertexBuffer indeciesBuffer, @Nullable IndeciesType type) {
this.layouts = layouts;
this.buffers = buffers;
this.indeciesBuffer = indeciesBuffer;
@@ -52,11 +59,39 @@ public abstract class Mesh implements GraphicsResource {
}
public static class Builder {
Int2ObjectMap<BufferState> allocateState = new Int2ObjectOpenHashMap<BufferState>().setDefaultReturnValue(BufferState.STATIC_READ);
Int2ObjectMap<LayoutInfo> layouts = Int2ObjectMap.builder().linkedMap();
IndeciesType type = IndeciesType.INT;
OptionalInt preallocated = OptionalInt.empty();
boolean autoGenerate;
private Builder() {}
public Builder autogenerate() {
autoGenerate = true;
return this;
}
public Builder preallocate(int bytes) {
preallocated = OptionalInt.of(bytes);
return this;
}
public Builder indecies(IndeciesType type) {
type = Objects.requireNonNull(type);
return this;
}
public Builder bufferState(BufferState state) {
allocateState.setDefaultReturnValue(Objects.requireNonNull(state));
return this;
}
public Builder bufferState(int index, BufferState state) {
allocateState.put(index, state);
return this;
}
public Builder layout(VertexLayout layout) {
return layout(layouts.size(), layout);
}
@@ -66,12 +101,35 @@ public abstract class Mesh implements GraphicsResource {
}
public Builder layout(int index, VertexLayout layout, int instanceCount) {
layouts.put(index, new LayoutInfo(layout, instanceCount));
if(layout.isEmpty()) throw new IllegalStateException("Empty Layouts are not valid");
layouts.put(index, new LayoutInfo(Objects.requireNonNull(layout), instanceCount));
return this;
}
public void validate() {
if(layouts.isEmpty()) throw new IllegalStateException("Layouts have to be provided");
}
public boolean isAutogenerated() {
return autoGenerate;
}
public IndeciesType indecies() {
return type;
}
public OptionalInt preAllocated() {
return preallocated;
}
public BufferState getState(int index) {
return allocateState.get(index);
}
public Int2ObjectMap<LayoutInfo> info() {
return layouts.unmodifiable();
}
}
public record LayoutInfo(VertexLayout layout, int instanceCount) {
}
public record LayoutInfo(VertexLayout layout, int instanceCount) {}
}
@@ -27,8 +27,9 @@ public class VertexLayout implements ObjectIterable<Element> {
}
public int stride() { return stride; }
public int size() { return elements.size(); }
public int bytes() { return bytes; }
public boolean isEmpty() { return elements.isEmpty(); }
public int size() { return elements.size(); }
public int offset(int index) { return offsets.getInt(index); }
public Element get(int index) { return elements.get(index); }
public boolean contains(String key) { return mapped.containsKey(key); }
@@ -15,7 +15,6 @@ import speiger.src.coreengine.graphics.api.target.ScreenTarget;
import speiger.src.coreengine.graphics.api.target.TextureTarget;
import speiger.src.coreengine.graphics.api.texture.Texture;
import speiger.src.coreengine.graphics.api.utils.PushableResource;
import speiger.src.coreengine.graphics.opengl.shader.GLRenderPass;
import speiger.src.coreengine.graphics.opengl.texture.FrameBufferCache;
import speiger.src.coreengine.graphics.opengl.texture.GLTexture;
import speiger.src.coreengine.math.vector.floats.Vec4f;
@@ -24,7 +23,6 @@ import speiger.src.coreengine.rendering.input.window.Window;
public class GLCommandQueue implements GraphicsCommandQueue {
GLGraphicsDevice device;
FrameBufferCache fboCache = new FrameBufferCache();
GLRenderPass activePass;
RenderTarget renderTarget = ScreenTarget.INSTANCE;
ScreenBuffer targetFBO;
Vec4f clearColor = Vec4f.mutable(0F, 0F, 0F, 1F);
@@ -3,24 +3,31 @@ package speiger.src.coreengine.graphics.opengl.core;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL33;
import org.lwjgl.opengl.GL43;
import org.lwjgl.opengl.GL45;
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectLinkedOpenHashMap;
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.coreengine.assets.api.IAssetProvider;
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
import speiger.src.coreengine.graphics.api.buffer.states.BufferState;
import speiger.src.coreengine.graphics.api.buffer.states.BufferType;
import speiger.src.coreengine.graphics.api.core.GraphicsCommandBuffer;
import speiger.src.coreengine.graphics.api.core.GraphicsDevice;
import speiger.src.coreengine.graphics.api.mesh.Mesh;
import speiger.src.coreengine.graphics.api.mesh.Mesh.LayoutInfo;
import speiger.src.coreengine.graphics.api.sampler.SamplerSettings;
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
import speiger.src.coreengine.graphics.api.texture.TextureSettings;
import speiger.src.coreengine.graphics.api.texture.states.SwizzleMask;
import speiger.src.coreengine.graphics.api.utils.ExecutionType;
import speiger.src.coreengine.graphics.opengl.buffer.GLVertexBuffer;
import speiger.src.coreengine.graphics.opengl.mesh.GLMesh;
import speiger.src.coreengine.graphics.opengl.sampler.GLSampler;
import speiger.src.coreengine.graphics.opengl.shader.ShaderInstance;
import speiger.src.coreengine.graphics.opengl.texture.GLTexture;
@@ -48,7 +55,7 @@ public class GLGraphicsDevice implements GraphicsDevice {
}
@Override
public GraphicsCommandBuffer createBuffer(ExecutionType type) {
public GraphicsCommandBuffer createCommandBuffer(ExecutionType type) {
return null;
}
@@ -94,8 +101,19 @@ public class GLGraphicsDevice implements GraphicsDevice {
}
@Override
public Mesh createMesh(Mesh.Builder builder, boolean autocreate) {
return null;
public GLMesh createMesh(Mesh.Builder builder) {
builder.validate();
if(builder.isAutogenerated()) {
Int2ObjectMap<LayoutInfo> info = builder.info();
OptionalInt preAllocation = builder.preAllocated();
Int2ObjectMap<VertexBuffer> buffers = new Int2ObjectLinkedOpenHashMap<>();
for(Int2ObjectMap.Entry<LayoutInfo> entry : info.int2ObjectEntrySet()) {
int key = entry.getIntKey();
buffers.put(key, preAllocation.isPresent() ? createBuffer(BufferType.ARRAY_BUFFER, builder.getState(key), preAllocation.getAsInt()) : createBuffer(BufferType.ARRAY_BUFFER, builder.getState(key)));
}
return new GLMesh(info, buffers, createBuffer(BufferType.ELEMENT_BUFFER, builder.getState(-1)), builder.indecies(), true);
}
return new GLMesh(builder.info(), new Int2ObjectOpenHashMap<>(), null, null, false);
}
public ShaderInstance createShader(ShaderPipeline line, IAssetProvider provider) {
@@ -0,0 +1,85 @@
package speiger.src.coreengine.graphics.opengl.core;
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
import speiger.src.coreengine.graphics.api.core.GraphicsCommandBuffer;
import speiger.src.coreengine.graphics.api.mesh.Mesh;
import speiger.src.coreengine.graphics.api.sampler.Sampler;
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
import speiger.src.coreengine.graphics.api.texture.Texture;
public class GLImmidateCommandBuffer implements GraphicsCommandBuffer {
boolean recording = false;
ShaderPipeline pipeline;
Mesh mesh;
int recorded = 0;
protected void ensureDrawing() {
if(!recording) throw new IllegalStateException("CommandBuffer isn't recording");
}
@Override
public boolean isRemoved() { return false; }
@Override
public void remove() {}
@Override
public GraphicsCommandBuffer begin() {
if(recording) throw new IllegalStateException("CommandBuffer already recording");
recording = true;
return this;
}
@Override
public GraphicsCommandBuffer setScissors(int x, int y, int width, int height) {
return this;
}
@Override
public GraphicsCommandBuffer pipeline(ShaderPipeline pipeline) {
this.pipeline = pipeline;
return this;
}
@Override
public GraphicsCommandBuffer mesh(Mesh mesh) {
this.mesh = mesh;
return this;
}
@Override
public GraphicsCommandBuffer texture(int set, int binding, Texture texture, Sampler sampler) {
return this;
}
@Override
public GraphicsCommandBuffer uniform(int set, int binding, VertexBuffer buffer) {
return this;
}
@Override
public GraphicsCommandBuffer drawIndexed(int start, int count) {
return this;
}
@Override
public GraphicsCommandBuffer pushScissors(int x, int y, int width, int height) {
return this;
}
@Override
public GraphicsCommandBuffer popScissors() {
return this;
}
@Override
public GraphicsCommandBuffer end() {
if(!recording) throw new IllegalStateException("Already Stopped Recording");
pipeline = null;
mesh = null;
recording = false;
return this;
}
@Override
public int commandCount() { return recorded; }
}
@@ -1,9 +1,12 @@
package speiger.src.coreengine.graphics.opengl.mesh;
import org.jspecify.annotations.Nullable;
import org.lwjgl.opengl.GL45;
import speiger.src.collections.ints.collections.IntIterator;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
import speiger.src.coreengine.graphics.api.buffer.states.IndeciesType;
import speiger.src.coreengine.graphics.api.mesh.Mesh;
import speiger.src.coreengine.graphics.api.vertex.VertexLayout;
import speiger.src.coreengine.graphics.api.vertex.VertexLayout.Element;
@@ -14,23 +17,40 @@ public class GLMesh extends Mesh {
int vao;
boolean managed;
public GLMesh(Int2ObjectMap<LayoutInfo> layouts, Int2ObjectMap<VertexBuffer> buffers, VertexBuffer indeciesBuffer, boolean managed) {
super(layouts, buffers, indeciesBuffer);
public GLMesh(Int2ObjectMap<LayoutInfo> layouts, Int2ObjectMap<VertexBuffer> buffers, @Nullable VertexBuffer indeciesBuffer, @Nullable IndeciesType indeciesType, boolean managed) {
super(layouts, buffers, indeciesBuffer, indeciesType);
this.managed = managed;
vao = GL45.glCreateVertexArrays();
if(managed) {
bindElement();
for(IntIterator iter = layouts.keySet().iterator();iter.hasNext();) {
bindBuffer(iter.nextInt());
}
}
}
@Override
public boolean isRemoved() { return vao == 0; }
@Override
public Mesh buffer(int binding, VertexBuffer buffer) {
public GLMesh buffer(int binding, VertexBuffer buffer) {
super.buffer(binding, buffer);
bind(binding);
bindBuffer(binding);
return this;
}
private void bind(int binding) {
@Override
public GLMesh indexBuffer(VertexBuffer indexBuffer, IndeciesType indeciesType) {
super.indexBuffer(indexBuffer, indeciesType);
bindElement();
return this;
}
private void bindElement() {
GL45.glVertexArrayElementBuffer(vao, ((GLVertexBuffer)indeciesBuffer).id());
}
private void bindBuffer(int binding) {
LayoutInfo info = layouts.get(binding);
VertexLayout layout = info.layout();
GLVertexBuffer buffer = (GLVertexBuffer)buffers.get(binding);
@@ -60,5 +80,4 @@ public class GLMesh extends Mesh {
close();
managed = wasManaged;
}
}
@@ -1,100 +0,0 @@
package speiger.src.coreengine.graphics.opengl.shader;
import java.util.Map;
import java.util.Objects;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL45;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.misc.pairs.ObjectObjectPair;
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
import speiger.src.coreengine.graphics.api.buffer.states.IndeciesType;
import speiger.src.coreengine.graphics.api.core.GraphicsCommandQueue.DrawArea;
import speiger.src.coreengine.graphics.api.sampler.Sampler;
import speiger.src.coreengine.graphics.api.shader.CompiledPipeline;
import speiger.src.coreengine.graphics.api.shader.RenderPass;
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
import speiger.src.coreengine.graphics.api.texture.Texture;
import speiger.src.coreengine.graphics.opengl.core.GLCommandQueue;
public class GLRenderPass extends RenderPass {
boolean scissors;
GLCommandQueue queue;
int fbo;
VertexBuffer[] buffers = new VertexBuffer[4];
Map<String, ObjectObjectPair<Texture, Sampler>> textures = Object2ObjectMap.builder().linkedMap();
Map<String, VertexBuffer> uniforms = Object2ObjectMap.builder().linkedMap();
VertexBuffer indecies;
IndeciesType indeciesType;
ShaderPipeline pipeline;
CompiledPipeline compiled;
public GLRenderPass(GLCommandQueue queue, DrawArea area, boolean scissors, boolean hasColor, boolean hasDepth, int fbo) {
super(area, hasColor, hasDepth);
this.scissors = scissors;
this.queue = queue;
this.fbo = fbo;
}
@Override
public void setShader(ShaderPipeline pipeline) {
this.pipeline = Objects.requireNonNull(pipeline);
}
@Override
public void setTexture(String name, Texture texture, Sampler sampler) {
Objects.requireNonNull(name, "Sampler Name is needed");
Objects.requireNonNull(texture, "Texture is required");
Objects.requireNonNull(sampler, "Sampler is required");
textures.put(name, ObjectObjectPair.of(texture, sampler));
}
@Override
public void clearTextures() {
textures.clear();
}
@Override
public void removeTexture(String name) {
Objects.requireNonNull(name, "Sampler Name is needed");
textures.remove(name);
}
@Override
public void setUniform(String name, VertexBuffer buffer) {
Objects.requireNonNull(name, "Uniform name is needed");
Objects.requireNonNull(buffer, "Vertex Buffer is required");
uniforms.put(name, buffer);
}
@Override
public void setIndecies(VertexBuffer buffer, IndeciesType type) {
indecies = Objects.requireNonNull(buffer, "Buffer is required");
indeciesType = Objects.requireNonNull(type, "Type is required");
}
@Override
public void clearIndecies() {
indecies = null;
indeciesType = null;
}
@Override
public void setVertexBuffer(int index, VertexBuffer buffer) {
if(index < 0 || index >= 4) throw new ArrayIndexOutOfBoundsException(index);
buffers[index] = buffer;
}
public void applyState() {
}
@Override
public void close() {
if(fbo == -1) return;
if(scissors) GL11.glDisable(GL11.GL_SCISSOR_TEST);
if(fbo != 0) GL45.glBindFramebuffer(GL45.GL_DRAW_FRAMEBUFFER, 0);
fbo = -1;
}
}
@@ -15,11 +15,11 @@ import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonWriter;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.api.ID;
public class ShaderCache {
public static final ShaderCache INSTANCE = new ShaderCache();
Map<AssetLocation, String> hashCache;
Map<ID, String> hashCache;
Path cache;
public void init(Path cache) {
@@ -32,10 +32,10 @@ public class ShaderCache {
}
}
try(BufferedReader reader = Files.newBufferedReader(cache.resolve("cache.json"))) {
Map<AssetLocation, String> knownCache = new Object2ObjectOpenHashMap<>();
Map<ID, String> knownCache = new Object2ObjectOpenHashMap<>();
for(JsonElement element : JsonParser.parseReader(reader).getAsJsonObject().getAsJsonArray("shaders")) {
JsonObject shader = element.getAsJsonObject();
knownCache.put(AssetLocation.of(shader.get("id").getAsString()), shader.get("hash").getAsString());
knownCache.put(ID.of(shader.get("id").getAsString()), shader.get("hash").getAsString());
}
hashCache = knownCache;
}
@@ -62,23 +62,23 @@ public class ShaderCache {
catch(Exception e) { e.printStackTrace(); }
}
public byte[] get(AssetLocation shaderLocation, String fileHash) {
String known = hashCache.get(shaderLocation);
public byte[] get(ID shaderId, String fileHash) {
String known = hashCache.get(shaderId);
if(!Objects.equals(known, fileHash)) return null;
Path path = toFile(shaderLocation);
Path path = toFile(shaderId);
if(Files.notExists(path)) return null;
try { return Files.readAllBytes(path); }
catch(Exception e) { e.printStackTrace(); }
return null;
}
public void store(AssetLocation shaderLocation, String fileHash, byte[] shader) {
Objects.requireNonNull(shaderLocation);
public void store(ID shaderId, String fileHash, byte[] shader) {
Objects.requireNonNull(shaderId);
Objects.requireNonNull(fileHash);
Objects.requireNonNull(shader);
hashCache.put(shaderLocation, fileHash);
hashCache.put(shaderId, fileHash);
try {
Path file = toFile(shaderLocation);
Path file = toFile(shaderId);
if(Files.notExists(file.getParent())) Files.createDirectories(file.getParent());
Files.write(file, shader);
}
@@ -88,14 +88,14 @@ public class ShaderCache {
save();
}
public void delete(AssetLocation shaderLocation) {
if(hashCache.remove(shaderLocation) == null) return;
try { Files.deleteIfExists(toFile(shaderLocation)); }
public void delete(ID shaderId) {
if(hashCache.remove(shaderId) == null) return;
try { Files.deleteIfExists(toFile(shaderId)); }
catch(Exception e) { e.printStackTrace(); }
save();
}
private Path toFile(AssetLocation id) {
return cache.resolve(id.domain()).resolve(id.location()+".bin");
private Path toFile(ID id) {
return cache.resolve(id.domain()).resolve(id.path()+".bin");
}
}