mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-05 09:44:58 +01:00
Merge remote-tracking branch 'origin/1.18/dev' into 1.18/fabric/dev
Conflicts: README.md build.gradle gradle.properties src/main/java/com/jozufozu/flywheel/backend/RenderWork.java src/main/java/com/jozufozu/flywheel/backend/material/MaterialManagerImpl.java src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java src/main/java/com/jozufozu/flywheel/config/FlwCommands.java src/main/java/com/jozufozu/flywheel/config/FlwPackets.java src/main/java/com/jozufozu/flywheel/config/SConfigureBooleanPacket.java src/main/java/com/jozufozu/flywheel/core/PartialModel.java src/main/java/com/jozufozu/flywheel/core/StitchedSprite.java src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java src/main/java/com/jozufozu/flywheel/event/RenderLayerEvent.java src/main/java/com/jozufozu/flywheel/mixin/LeakChunkStorageArrayMixin.java src/main/java/com/jozufozu/flywheel/mixin/RenderHooksMixin.java src/main/java/com/jozufozu/flywheel/util/ChunkIter.java src/main/resources/META-INF/mods.toml src/main/resources/flywheel.mixins.json
This commit is contained in:
commit
6fede0851e
152 changed files with 1376 additions and 1572 deletions
89
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
89
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
|
@ -0,0 +1,89 @@
|
|||
name: Bug Report
|
||||
description: Create a bug report to help us improve Flywheel
|
||||
labels: [ "bug" ]
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the Bug
|
||||
description: A clear and concise description of what the bug is
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
description: Tell us about the steps to reproduce the bug
|
||||
value: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Result
|
||||
description: A clear and concise description of what you expected to happen
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots and Videos
|
||||
description: If applicable, add screenshots or videos to help explain your problem
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
attributes:
|
||||
label: Crash Report or Log
|
||||
description: If applicable, please add a link to the crash report or log that was created when this issue occured
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "*[Pastebin](https://pastebin.com/) is standard.*"
|
||||
- type: input
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: The operating system you were using when the bug occured
|
||||
placeholder: Windows 11
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Mod Version
|
||||
description: The version of the mod you were using when the bug occured
|
||||
options:
|
||||
- "0.4.1"
|
||||
- "0.3.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Minecraft Version
|
||||
description: The version of Minecraft you were using when the bug occured
|
||||
options:
|
||||
- "1.18.1"
|
||||
- "1.17.1"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Fabric API Version
|
||||
description: The version of Fabric API you were using when the bug occured
|
||||
placeholder: 0.44.0+1.18
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Other Mods
|
||||
description: Please list any other mods that were running when the crash happened
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any extra context about the bug here
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Thank you for taking the time to make this bug report and to help improve Flywheel"
|
|
@ -2,7 +2,7 @@
|
|||
<img src="https://i.imgur.com/yVFgPpr.png" alt="Logo by @voxel_dani on Twitter" width="250">
|
||||
<h1>Flywheel</h1>
|
||||
<h6>A modern engine for modded Minecraft.</h6>
|
||||
<a href='https://ci.tterrag.com/job/Flywheel/job/Fabric/job/1.17/'><img src='https://ci.tterrag.com/job/Flywheel/job/Fabric/job/1.17/badge/icon' alt="Jenkins"></a>
|
||||
<a href='https://ci.tterrag.com/job/Flywheel/job/Fabric/job/1.18/'><img src='https://ci.tterrag.com/job/Flywheel/job/Fabric/job/1.18/badge/icon' alt="Jenkins"></a>
|
||||
<a href="https://discord.gg/xjD59ThnXy"><img src="https://img.shields.io/discord/841464837406195712?color=5865f2&label=Discord&style=flat" alt="Discord"></a>
|
||||
<a href="https://www.curseforge.com/minecraft/mc-mods/flywheel"><img src="http://cf.way2muchnoise.eu/486392.svg" alt="Curseforge Downloads"></a>
|
||||
<br>
|
||||
|
@ -49,6 +49,6 @@ dependencies {
|
|||
implementation fg.deobf("com.jozufozu.flywheel:Flywheel-Fabric:${flywheel_version}")
|
||||
}
|
||||
```
|
||||
`${flywheel_version}` gets replaced by the version of Flywheel you want to use, eg. `0.3.0.5`
|
||||
`${flywheel_version}` gets replaced by the version of Flywheel you want to use, eg. `1.18-0.3.0.3`
|
||||
|
||||
For a list of available Flywheel versions, you can check [the maven](https://maven.tterrag.com/com/jozufozu/flywheel/Flywheel-Fabric/).
|
||||
|
|
28
build.gradle
28
build.gradle
|
@ -13,10 +13,10 @@ version = "${mc_update_version}-${mod_version}" + (dev ? ".${buildnumber}" : '')
|
|||
group = 'com.jozufozu.flywheel'
|
||||
archivesBaseName = 'flywheel-fabric'
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_16
|
||||
targetCompatibility = JavaVersion.VERSION_16
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
java.toolchain.languageVersion = JavaLanguageVersion.of(16)
|
||||
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
|
||||
|
||||
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
|
||||
|
||||
|
@ -33,10 +33,11 @@ repositories {
|
|||
dependencies {
|
||||
// To change the versions see the gradle.properties file
|
||||
minecraft "com.mojang:minecraft:${minecraft_version}"
|
||||
mappings loom.layered() {
|
||||
officialMojangMappings()
|
||||
parchment("org.parchmentmc.data:parchment-${minecraft_version}:${parchment_version}@zip")
|
||||
}
|
||||
// mappings loom.layered() {
|
||||
// officialMojangMappings()
|
||||
// parchment("org.parchmentmc.data:parchment-${minecraft_version}:${parchment_version}@zip")
|
||||
// }
|
||||
mappings loom.officialMojangMappings() // TODO: waiting for parchment 1.18
|
||||
modImplementation "net.fabricmc:fabric-loader:${loader_version}"
|
||||
|
||||
// Fabric API
|
||||
|
@ -56,14 +57,8 @@ processResources {
|
|||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
// If Javadoc is generated, this must be specified in that task too.
|
||||
it.options.encoding = 'UTF-8'
|
||||
|
||||
// Minecraft 1.17 (21w19a) upwards uses Java 16.
|
||||
it.options.release = 16
|
||||
// Minecraft 1.18 (1.18-pre2) upwards uses Java 17.
|
||||
it.options.release = 17
|
||||
}
|
||||
|
||||
java {
|
||||
|
@ -141,6 +136,7 @@ curseforge {
|
|||
changelog = file('changelog.txt')
|
||||
releaseType = project.curse_type
|
||||
mainArtifact jar
|
||||
addGameVersion '1.17.1'
|
||||
addGameVersion '1.18'
|
||||
addGameVersion '1.18.1'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,25 @@
|
|||
0.3.0:
|
||||
Update to 1.17
|
||||
New
|
||||
0.4.1:
|
||||
Update to 1.18.1
|
||||
Changes
|
||||
- Use cylindrical fog to match vanilla
|
||||
Fixes
|
||||
- Fix crash affecting systems that don't support persistent mapping
|
||||
- Fix crash when Create contraptions extend below Y=0
|
||||
- Fix Create contraptions having misaligned light when launched after world load
|
||||
|
||||
0.4.0:
|
||||
Update to 1.18
|
||||
Fixes
|
||||
- Fix potential nullpointer rendering breaking overlay
|
||||
- Fix inconsistency in minecart model
|
||||
- Fix memory leak when instance worlds get reset
|
||||
Technical/API
|
||||
- No more MaterialSpec, everything is StructType
|
||||
- Move most user facing interfaces to flywheel.api package
|
||||
- Refactor InstanceData to have no package private fields
|
||||
- Rename many interfaces
|
||||
- All materials use the same vertex format: UNLIT_MODEL
|
||||
- call #tick and #beginFrame on instance creation
|
||||
- Fixes weird delay in object appearance when reloading chunks
|
||||
- Add instances when chunks are built for rendering
|
||||
- Server worlds are not flywheel worlds
|
||||
|
|
|
@ -2,11 +2,11 @@ org.gradle.jvmargs = -Xmx3G
|
|||
org.gradle.daemon = false
|
||||
|
||||
# mod version info
|
||||
mod_version = 0.3.0
|
||||
mc_update_version = 1.17
|
||||
minecraft_version = 1.17.1
|
||||
loader_version = 0.12.8
|
||||
fabric_version = 0.44.0+1.17
|
||||
mod_version = 0.4.1
|
||||
mc_update_version = 1.18
|
||||
minecraft_version = 1.18.1
|
||||
loader_version = 0.12.11
|
||||
fabric_version = 0.44.0+1.18
|
||||
|
||||
# build dependency versions
|
||||
loom_version = 0.10-SNAPSHOT
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import net.minecraft.world.level.Level;
|
||||
package com.jozufozu.flywheel.api;
|
||||
|
||||
/**
|
||||
* Something (a BlockEntity or Entity) that can be rendered using the instancing API.
|
||||
*/
|
||||
public interface IInstanceRendered {
|
||||
public interface FlywheelRendered {
|
||||
|
||||
/**
|
||||
* @return true if there are parts of the renderer that cannot be implemented with Flywheel.
|
||||
|
@ -13,6 +11,4 @@ public interface IInstanceRendered {
|
|||
default boolean shouldRenderNormally() {
|
||||
return false;
|
||||
}
|
||||
|
||||
Level getWorld();
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
package com.jozufozu.flywheel.api;
|
||||
|
||||
/**
|
||||
* A marker interface custom worlds can override to indicate
|
||||
* that tiles inside the world should render with Flywheel.
|
||||
*
|
||||
* <code>Minecraft.getInstance().world</code> is special cased and will support Flywheel by default.
|
||||
* {@link net.minecraft.client.Minecraft#level Minecraft#level} is special cased and will support Flywheel by default.
|
||||
*/
|
||||
public interface IFlywheelWorld {
|
||||
public interface FlywheelWorld {
|
||||
default boolean supportsFlywheel() {
|
||||
return true;
|
||||
}
|
41
src/main/java/com/jozufozu/flywheel/api/InstanceData.java
Normal file
41
src/main/java/com/jozufozu/flywheel/api/InstanceData.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
package com.jozufozu.flywheel.api;
|
||||
|
||||
public abstract class InstanceData {
|
||||
|
||||
private Instancer<?> owner;
|
||||
|
||||
private boolean dirty;
|
||||
private boolean removed;
|
||||
|
||||
public final void markDirty() {
|
||||
dirty = true;
|
||||
owner.notifyDirty();
|
||||
}
|
||||
|
||||
public final void delete() {
|
||||
removed = true;
|
||||
owner.notifyRemoval();
|
||||
}
|
||||
|
||||
public final boolean checkDirtyAndClear() {
|
||||
if (dirty) {
|
||||
dirty = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean isRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
public Instancer<?> getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public InstanceData setOwner(Instancer<?> owner) {
|
||||
this.owner = owner;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
package com.jozufozu.flywheel.api;
|
||||
|
||||
/**
|
||||
* An instancer is how you interact with an instanced model.
|
||||
|
@ -32,7 +32,22 @@ public interface Instancer<D extends InstanceData> {
|
|||
*/
|
||||
void stealInstance(D inOther);
|
||||
|
||||
void markDirty(InstanceData instanceData);
|
||||
/**
|
||||
* Notify the Instancer that some of its data needs updating.
|
||||
*
|
||||
* <p>
|
||||
* This might be ignored, depending on the implementation. For the GPUInstancer, this triggers a scan of all
|
||||
* instances.
|
||||
* </p>
|
||||
*/
|
||||
void notifyDirty();
|
||||
|
||||
void markRemoval(InstanceData instanceData);
|
||||
/**
|
||||
* Notify the Instances that some of its data should be removed.
|
||||
*
|
||||
* <p>
|
||||
* By the time the next frame is drawn, the instanceData passed will no longer be considered for rendering.
|
||||
* </p>
|
||||
*/
|
||||
void notifyRemoval();
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
package com.jozufozu.flywheel.backend.material;
|
||||
package com.jozufozu.flywheel.api;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceData;
|
||||
import com.jozufozu.flywheel.backend.instancing.Instancer;
|
||||
import com.jozufozu.flywheel.core.PartialModel;
|
||||
import com.jozufozu.flywheel.core.model.BlockModel;
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
import com.jozufozu.flywheel.util.RenderUtil;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
@ -19,10 +17,10 @@ public interface Material<D extends InstanceData> {
|
|||
* Get an instancer for the given model. Calling this method twice with the same key will return the same instancer.
|
||||
*
|
||||
* @param key An object that uniquely identifies the model.
|
||||
* @param modelSupplier A factory that creates the IModel that you want to render.
|
||||
* @param modelSupplier A factory that creates the Model that you want to render.
|
||||
* @return An instancer for the given model, capable of rendering many copies for little cost.
|
||||
*/
|
||||
Instancer<D> model(Object key, Supplier<IModel> modelSupplier);
|
||||
Instancer<D> model(Object key, Supplier<Model> modelSupplier);
|
||||
|
||||
default Instancer<D> getModel(PartialModel partial, BlockState referenceState) {
|
||||
return model(partial, () -> new BlockModel(partial.get(), referenceState));
|
14
src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java
Normal file
14
src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java
Normal file
|
@ -0,0 +1,14 @@
|
|||
package com.jozufozu.flywheel.api;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
||||
public interface MaterialGroup {
|
||||
/**
|
||||
* Get the material as defined by the given {@link StructType type}.
|
||||
*
|
||||
* @param spec The material you want to create instances with.
|
||||
* @param <D> The type representing the per instance data.
|
||||
* @return A material you can use to render models.
|
||||
*/
|
||||
<D extends InstanceData> Material<D> material(StructType<D> spec);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.material;
|
||||
package com.jozufozu.flywheel.api;
|
||||
|
||||
import com.jozufozu.flywheel.backend.state.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.Vec3i;
|
||||
|
@ -11,7 +11,7 @@ public interface MaterialManager {
|
|||
* Get a material group that will render in the given layer with the given state.
|
||||
*
|
||||
* @param layer The {@link RenderLayer} you want to draw in.
|
||||
* @param state The {@link net.minecraft.client.renderer.RenderType} you need to draw with.
|
||||
* @param state The {@link RenderType} you need to draw with.
|
||||
* @return A material group whose children will
|
||||
*/
|
||||
MaterialGroup state(RenderLayer layer, RenderType state);
|
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
package com.jozufozu.flywheel.api.instance;
|
||||
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance;
|
||||
|
||||
/**
|
||||
|
@ -13,9 +15,9 @@ import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance;
|
|||
*/
|
||||
public interface IDynamicInstance extends IInstance {
|
||||
/**
|
||||
* Called every frame.
|
||||
* Called every frame, and after initialization.
|
||||
* <br>
|
||||
* <em>DISPATCHED IN PARALLEL</em>, don't attempt to mutate anything outside of this instance.
|
||||
* <em>DISPATCHED IN PARALLEL</em>, don't attempt to mutate anything outside this instance.
|
||||
* <br>
|
||||
* {@link Instancer}/{@link InstanceData} creation/acquisition is safe here.
|
||||
*/
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
package com.jozufozu.flywheel.api.instance;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
package com.jozufozu.flywheel.api.instance;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance;
|
||||
|
||||
/**
|
||||
|
@ -21,7 +23,7 @@ import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance;
|
|||
public interface ITickableInstance extends IInstance {
|
||||
|
||||
/**
|
||||
* Called every tick.
|
||||
* Called every tick, and after initialization.
|
||||
* <br>
|
||||
* <em>DISPATCHED IN PARALLEL</em>, don't attempt to mutate anything outside of this instance.
|
||||
* <br>
|
|
@ -1,5 +1,5 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.backend.state;
|
||||
package com.jozufozu.flywheel.api.instance;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.backend.material;
|
||||
package com.jozufozu.flywheel.api;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
13
src/main/java/com/jozufozu/flywheel/api/struct/Batched.java
Normal file
13
src/main/java/com/jozufozu/flywheel/api/struct/Batched.java
Normal file
|
@ -0,0 +1,13 @@
|
|||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
public interface Batched<S> extends StructType<S> {
|
||||
|
||||
BatchingTransformer<S> getTransformer(Model model);
|
||||
|
||||
@Override
|
||||
default Batched<S> asBatched() {
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
public abstract class BatchingTransformer<S> {
|
||||
|
||||
public void draw(S s, PoseStack stack, VertexConsumer consumer) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package com.jozufozu.flywheel.backend.struct;
|
||||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
|
||||
public interface Writeable<S> extends StructType<S> {
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface Instanced<S> extends StructType<S> {
|
||||
/**
|
||||
* Create a {@link StructWriter} that will consume instances of S and write them to the given buffer.
|
||||
*
|
||||
|
@ -10,8 +12,10 @@ public interface Writeable<S> extends StructType<S> {
|
|||
*/
|
||||
StructWriter<S> getWriter(VecBuffer backing);
|
||||
|
||||
ResourceLocation getProgramSpec();
|
||||
|
||||
@Override
|
||||
default Writeable<S> asWriteable() {
|
||||
default Instanced<S> asInstanced() {
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.struct;
|
||||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
|
||||
|
@ -18,5 +18,7 @@ public interface StructType<S> {
|
|||
*/
|
||||
VertexFormat format();
|
||||
|
||||
Writeable<S> asWriteable();
|
||||
Instanced<S> asInstanced();
|
||||
|
||||
Batched<S> asBatched();
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.struct;
|
||||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
/**
|
||||
* StructWriters can quickly consume many instances of S and write them to some backing buffer.
|
|
@ -0,0 +1,6 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
|
@ -13,9 +13,10 @@ import org.apache.logging.log4j.Logger;
|
|||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.jozufozu.flywheel.api.FlywheelWorld;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceData;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialSpec;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.config.FlwConfig;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
|
||||
|
@ -41,8 +42,8 @@ public class Backend {
|
|||
private boolean instancedArrays;
|
||||
private boolean enabled;
|
||||
|
||||
private final List<IShaderContext<?>> contexts = new ArrayList<>();
|
||||
private final Map<ResourceLocation, MaterialSpec<?>> materialRegistry = new HashMap<>();
|
||||
private final List<ShaderContext<?>> contexts = new ArrayList<>();
|
||||
private final Map<ResourceLocation, StructType<?>> materialRegistry = new HashMap<>();
|
||||
private final Map<ResourceLocation, ProgramSpec> programSpecRegistry = new HashMap<>();
|
||||
|
||||
protected Backend() {
|
||||
|
@ -82,7 +83,7 @@ public class Backend {
|
|||
/**
|
||||
* Register a shader context.
|
||||
*/
|
||||
public <C extends IShaderContext<?>> C register(C spec) {
|
||||
public <C extends ShaderContext<?>> C register(C spec) {
|
||||
contexts.add(spec);
|
||||
return spec;
|
||||
}
|
||||
|
@ -90,15 +91,13 @@ public class Backend {
|
|||
/**
|
||||
* Register an instancing material.
|
||||
*/
|
||||
public <D extends InstanceData> MaterialSpec<D> register(MaterialSpec<D> spec) {
|
||||
ResourceLocation name = spec.name;
|
||||
public <D extends InstanceData> StructType<D> register(ResourceLocation name, StructType<D> spec) {
|
||||
if (materialRegistry.containsKey(name)) {
|
||||
throw new IllegalStateException("Material spec '" + name + "' already registered.");
|
||||
}
|
||||
materialRegistry.put(name, spec);
|
||||
|
||||
log.debug("registered material '" + name + "' with vertex size " + spec.getModelFormat()
|
||||
.getStride() + " and instance size " + spec.getInstanceType().format().getStride());
|
||||
log.debug("registered material '" + name + "' with instance size " + spec.format().getStride());
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
@ -133,7 +132,7 @@ public class Backend {
|
|||
|
||||
compat = new GlCompat(capabilities);
|
||||
|
||||
instancedArrays = compat.vertexArrayObjectsSupported() && compat.drawInstancedSupported() && compat.instancedArraysSupported();
|
||||
instancedArrays = compat.instancedArraysSupported();
|
||||
|
||||
enabled = FlwConfig.get()
|
||||
.enabled() && !OptifineHandler.usingShaders();
|
||||
|
@ -143,7 +142,7 @@ public class Backend {
|
|||
return canUseInstancing() && isFlywheelWorld(world);
|
||||
}
|
||||
|
||||
public Collection<MaterialSpec<?>> allMaterials() {
|
||||
public Collection<StructType<?>> allMaterials() {
|
||||
return materialRegistry.values();
|
||||
}
|
||||
|
||||
|
@ -151,7 +150,7 @@ public class Backend {
|
|||
return programSpecRegistry.values();
|
||||
}
|
||||
|
||||
public Collection<IShaderContext<?>> allContexts() {
|
||||
public Collection<ShaderContext<?>> allContexts() {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
|
@ -161,7 +160,9 @@ public class Backend {
|
|||
public static boolean isFlywheelWorld(@Nullable LevelAccessor world) {
|
||||
if (world == null) return false;
|
||||
|
||||
if (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel()) return true;
|
||||
if (!world.isClientSide()) return false;
|
||||
|
||||
if (world instanceof FlywheelWorld && ((FlywheelWorld) world).supportsFlywheel()) return true;
|
||||
|
||||
return world == Minecraft.getInstance().level;
|
||||
}
|
||||
|
@ -180,7 +181,7 @@ public class Backend {
|
|||
public void _clearContexts() {
|
||||
GameStateRegistry.clear();
|
||||
programSpecRegistry.clear();
|
||||
contexts.forEach(IShaderContext::delete);
|
||||
contexts.forEach(ShaderContext::delete);
|
||||
contexts.clear();
|
||||
materialRegistry.clear();
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ public class Loader {
|
|||
|
||||
Resolver.INSTANCE.resolve(sources);
|
||||
|
||||
for (IShaderContext<?> context : backend.allContexts()) {
|
||||
for (ShaderContext<?> context : backend.allContexts()) {
|
||||
context.load();
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ public class Loader {
|
|||
ClientLevel world = Minecraft.getInstance().level;
|
||||
if (Backend.isFlywheelWorld(world)) {
|
||||
// TODO: looks like it might be good to have another event here
|
||||
InstancedRenderDispatcher.loadAllInWorld(world);
|
||||
InstancedRenderDispatcher.resetInstanceWorld(world);
|
||||
CrumblingRenderer.reset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.state;
|
||||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
|
@ -6,7 +6,7 @@ import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
|||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface IShaderContext<P extends GlProgram> {
|
||||
public interface ShaderContext<P extends GlProgram> {
|
||||
|
||||
default P getProgram(ResourceLocation loc) {
|
||||
return this.getProgramSupplier(loc)
|
|
@ -22,4 +22,8 @@ public class GlTexture extends GlObject {
|
|||
public void unbind() {
|
||||
GL20.glBindTexture(textureType, 0);
|
||||
}
|
||||
|
||||
public void setParameteri(int parameter, int value) {
|
||||
GL20.glTexParameteri(textureType, parameter, value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
package com.jozufozu.flywheel.backend.gl;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
public class GlVertexArray extends GlObject {
|
||||
public GlVertexArray() {
|
||||
setHandle(Backend.getInstance().compat.vao.genVertexArrays());
|
||||
setHandle(GlStateManager._glGenVertexArrays());
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
Backend.getInstance().compat.vao.bindVertexArray(handle());
|
||||
GlStateManager._glBindVertexArray(handle());
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
Backend.getInstance().compat.vao.bindVertexArray(0);
|
||||
public static void unbind() {
|
||||
GlStateManager._glBindVertexArray(0);
|
||||
}
|
||||
|
||||
protected void deleteInternal(int handle) {
|
||||
Backend.getInstance().compat.vao.deleteVertexArrays(handle);
|
||||
GlStateManager._glDeleteVertexArrays(handle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,11 +40,11 @@ public abstract class GlBuffer extends GlObject {
|
|||
}
|
||||
|
||||
public void bind() {
|
||||
GL20.glBindBuffer(type.glEnum, handle());
|
||||
type.bind(handle());
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
GL20.glBindBuffer(type.glEnum, 0);
|
||||
type.unbind();
|
||||
}
|
||||
|
||||
public void doneForThisFrame() {
|
||||
|
|
|
@ -8,6 +8,8 @@ import org.lwjgl.opengl.GL40;
|
|||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
public enum GlBufferType {
|
||||
ARRAY_BUFFER(GL15C.GL_ARRAY_BUFFER),
|
||||
ELEMENT_ARRAY_BUFFER(GL15C.GL_ELEMENT_ARRAY_BUFFER),
|
||||
|
@ -29,4 +31,12 @@ public enum GlBufferType {
|
|||
GlBufferType(int glEnum) {
|
||||
this.glEnum = glEnum;
|
||||
}
|
||||
|
||||
public void bind(int buffer) {
|
||||
GlStateManager._glBindBuffer(glEnum, buffer);
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
GlStateManager._glBindBuffer(glEnum, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
/**
|
||||
* Interface for generically dealing with mapped buffers.
|
||||
*/
|
||||
public interface Mappable {
|
||||
GlBufferType getType();
|
||||
|
||||
/**
|
||||
* Indicates that this buffer need not be #flush()'d for its contents to sync.
|
||||
* @return true if this buffer is persistently mapped.
|
||||
*/
|
||||
boolean isPersistent();
|
||||
}
|
|
@ -1,133 +1,45 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
public abstract class MappedBuffer extends VecBuffer implements AutoCloseable {
|
||||
public class MappedBuffer extends VecBuffer implements AutoCloseable {
|
||||
|
||||
protected boolean mapped;
|
||||
protected final GlBuffer owner;
|
||||
protected final long offset;
|
||||
protected final long length;
|
||||
protected final Mappable owner;
|
||||
|
||||
public MappedBuffer(GlBuffer owner) {
|
||||
public MappedBuffer(Mappable owner, ByteBuffer internal, long offset, long length) {
|
||||
this.internal = internal;
|
||||
this.owner = owner;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public long addr() {
|
||||
return MemoryUtil.memAddress(this.internal, internal.position());
|
||||
}
|
||||
|
||||
protected abstract void checkAndMap();
|
||||
|
||||
/**
|
||||
* Make the changes in client memory available to the GPU.
|
||||
*/
|
||||
public void flush() {
|
||||
if (mapped) {
|
||||
GL15.glUnmapBuffer(owner.type.glEnum);
|
||||
mapped = false;
|
||||
setInternal(null);
|
||||
if (owner.isPersistent()) return;
|
||||
|
||||
if (internal == null) return;
|
||||
|
||||
GL15.glUnmapBuffer(owner.getType().glEnum);
|
||||
internal = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappedBuffer position(int p) {
|
||||
if (p < offset || p >= offset + length) {
|
||||
throw new IndexOutOfBoundsException("Index " + p + " is not mapped");
|
||||
}
|
||||
super.position(p - (int) offset);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
flush();
|
||||
}
|
||||
|
||||
public MappedBuffer putFloatArray(float[] floats) {
|
||||
checkAndMap();
|
||||
super.putFloatArray(floats);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer putByteArray(byte[] bytes) {
|
||||
checkAndMap();
|
||||
super.putByteArray(bytes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer put(FloatBuffer floats) {
|
||||
checkAndMap();
|
||||
super.put(floats);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int position() {
|
||||
checkAndMap();
|
||||
return super.position();
|
||||
}
|
||||
|
||||
/**
|
||||
* Position this buffer relative to the 0-index in GPU memory.
|
||||
*
|
||||
* @return This buffer.
|
||||
*/
|
||||
public MappedBuffer position(int p) {
|
||||
checkAndMap();
|
||||
super.position(p);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer putFloat(float f) {
|
||||
checkAndMap();
|
||||
super.putFloat(f);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer putInt(int i) {
|
||||
checkAndMap();
|
||||
super.putInt(i);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer putShort(short s) {
|
||||
checkAndMap();
|
||||
super.putShort(s);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer put(byte b) {
|
||||
checkAndMap();
|
||||
super.put(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer put(ByteBuffer b) {
|
||||
checkAndMap();
|
||||
super.put(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer putVec4(float x, float y, float z, float w) {
|
||||
checkAndMap();
|
||||
super.putVec4(x, y, z, w);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer putVec3(float x, float y, float z) {
|
||||
checkAndMap();
|
||||
super.putVec3(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer putVec2(float x, float y) {
|
||||
checkAndMap();
|
||||
super.putVec2(x, y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer putVec3(byte x, byte y, byte z) {
|
||||
checkAndMap();
|
||||
super.putVec3(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBuffer putVec2(byte x, byte y) {
|
||||
checkAndMap();
|
||||
super.putVec2(x, y);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlException;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
public class MappedBufferRange extends MappedBuffer {
|
||||
|
||||
long offset, length;
|
||||
int access;
|
||||
|
||||
public MappedBufferRange(GlBuffer buffer, long offset, long length, int access) {
|
||||
super(buffer);
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
this.access = access;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappedBuffer position(int p) {
|
||||
if (p < offset || p >= offset + length) {
|
||||
throw new IndexOutOfBoundsException("Index " + p + " is not mapped");
|
||||
}
|
||||
return super.position(p - (int) offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkAndMap() {
|
||||
if (!mapped) {
|
||||
setInternal(Backend.getInstance().compat.mapBufferRange.mapBuffer(owner.type, offset, length, access));
|
||||
|
||||
GlError error = GlError.poll();
|
||||
|
||||
if (error != null) {
|
||||
throw new GlException(error, StringUtil.args("mapBufferRange", owner.type, offset, length, access));
|
||||
}
|
||||
mapped = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlException;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
public class MappedFullBuffer extends MappedBuffer {
|
||||
|
||||
MappedBufferUsage usage;
|
||||
|
||||
public MappedFullBuffer(GlBuffer buffer, MappedBufferUsage usage) {
|
||||
super(buffer);
|
||||
this.usage = usage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkAndMap() {
|
||||
if (!mapped) {
|
||||
setInternal(GL15.glMapBuffer(owner.type.glEnum, usage.glEnum));
|
||||
|
||||
GlError error = GlError.poll();
|
||||
|
||||
if (error != null) {
|
||||
throw new GlException(error, StringUtil.args("mapBuffer", owner.type, usage));
|
||||
}
|
||||
|
||||
mapped = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,10 +5,11 @@ import java.nio.ByteBuffer;
|
|||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.MapBufferRange;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlException;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
public class MappedGlBuffer extends GlBuffer {
|
||||
public class MappedGlBuffer extends GlBuffer implements Mappable {
|
||||
|
||||
protected final GlBufferUsage usage;
|
||||
|
||||
|
@ -30,12 +31,22 @@ public class MappedGlBuffer extends GlBuffer {
|
|||
}
|
||||
|
||||
public MappedBuffer getBuffer(int offset, int length) {
|
||||
if (Backend.getInstance().compat.mapBufferRange != MapBufferRange.UNSUPPORTED) {
|
||||
return new MappedBufferRange(this, offset, length, GL30.GL_MAP_WRITE_BIT);
|
||||
} else {
|
||||
MappedFullBuffer fullBuffer = new MappedFullBuffer(this, MappedBufferUsage.WRITE_ONLY);
|
||||
fullBuffer.position(offset);
|
||||
return fullBuffer;
|
||||
}
|
||||
ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, offset, length, GL30.GL_MAP_WRITE_BIT);
|
||||
|
||||
if (byteBuffer == null) {
|
||||
throw new GlException(GlError.poll(), "Could not map buffer");
|
||||
}
|
||||
|
||||
return new MappedBuffer(this, byteBuffer, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlBufferType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPersistent() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,16 +6,17 @@ import static org.lwjgl.opengl.GL44.GL_MAP_PERSISTENT_BIT;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlFence;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlException;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
public class PersistentGlBuffer extends GlBuffer implements Mappable {
|
||||
|
||||
public class PersistentGlBuffer extends GlBuffer {
|
||||
|
||||
private PersistentMappedBuffer buffer;
|
||||
private MappedBuffer buffer;
|
||||
int flags;
|
||||
|
||||
long size;
|
||||
|
@ -49,17 +50,24 @@ public class PersistentGlBuffer extends GlBuffer {
|
|||
Backend.getInstance().compat.bufferStorage.bufferStorage(type, size, flags);
|
||||
|
||||
GlError error = GlError.poll();
|
||||
|
||||
if (error != null) {
|
||||
// If this error is being thrown but everything seems fine,
|
||||
// GlError.poll() might be returning an error from something earlier.
|
||||
throw new GlException(error, StringUtil.args("bufferStorage", type, size, flags));
|
||||
}
|
||||
|
||||
buffer = new PersistentMappedBuffer(this);
|
||||
ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, 0, size, flags);
|
||||
|
||||
if (byteBuffer == null) {
|
||||
throw new GlException(GlError.poll(), "Could not map buffer");
|
||||
}
|
||||
|
||||
buffer = new MappedBuffer(this, byteBuffer, 0, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(ByteBuffer directBuffer) {
|
||||
|
||||
throw new UnsupportedOperationException("FIXME: Nothing calls #upload on a persistent buffer as of 12/10/2021.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,4 +79,14 @@ public class PersistentGlBuffer extends GlBuffer {
|
|||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlBufferType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPersistent() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlException;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
public class PersistentMappedBuffer extends MappedBuffer {
|
||||
|
||||
private final long offset;
|
||||
private final long length;
|
||||
PersistentGlBuffer owner;
|
||||
|
||||
public PersistentMappedBuffer(PersistentGlBuffer buffer) {
|
||||
super(buffer);
|
||||
owner = buffer;
|
||||
offset = 0;
|
||||
length = owner.size;
|
||||
|
||||
ByteBuffer byteBuffer = Backend.getInstance().compat.mapBufferRange.mapBuffer(owner.type, offset, length, owner.flags);
|
||||
|
||||
GlError error = GlError.poll();
|
||||
|
||||
if (error != null) {
|
||||
throw new GlException(error, StringUtil.args("mapBuffer", owner.type, offset, length, owner.flags));
|
||||
}
|
||||
|
||||
setInternal(byteBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappedBuffer position(int p) {
|
||||
if (p < offset || p >= offset + length) {
|
||||
throw new IndexOutOfBoundsException("Index " + p + " is not mapped");
|
||||
}
|
||||
return super.position(p - (int) offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkAndMap() {
|
||||
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class VecBuffer {
|
||||
|
||||
protected ByteBuffer internal;
|
||||
|
@ -22,10 +24,6 @@ public class VecBuffer {
|
|||
return new VecBuffer(buffer);
|
||||
}
|
||||
|
||||
protected void setInternal(ByteBuffer internal) {
|
||||
this.internal = internal;
|
||||
}
|
||||
|
||||
public ByteBuffer unwrap() {
|
||||
return internal;
|
||||
}
|
||||
|
|
|
@ -35,16 +35,16 @@ public enum GlError {
|
|||
this.glEnum = glEnum;
|
||||
}
|
||||
|
||||
|
||||
// Great for use in your debugger's expression evaluator
|
||||
public static GlError poll() {
|
||||
return errorLookup.get(GL20.glGetError());
|
||||
}
|
||||
|
||||
public static void pollAndThrow(Supplier<String> context) {
|
||||
// TODO: build flag? to enable or disable this function
|
||||
GlError poll = GlError.poll();
|
||||
if (poll != null) {
|
||||
Flywheel.log.error("{}: {}", poll.name(), context.get());
|
||||
GlError err = GlError.poll();
|
||||
if (err != null) {
|
||||
Flywheel.log.error("{}: {}", err.name(), context.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,35 +4,12 @@ public class GlException extends RuntimeException {
|
|||
|
||||
final GlError errorCode;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String s = getClass().getName();
|
||||
String message = getLocalizedMessage();
|
||||
String withCode = s + ": " + errorCode;
|
||||
return (message != null) ? (withCode + ": " + message) : withCode;
|
||||
}
|
||||
|
||||
public GlException(GlError errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public GlException(GlError errorCode, String message) {
|
||||
super(message);
|
||||
super(updateMessage(errorCode, message));
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public GlException(GlError errorCode, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public GlException(GlError errorCode, Throwable cause) {
|
||||
super(cause);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public GlException(GlError errorCode, String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
this.errorCode = errorCode;
|
||||
private static String updateMessage(GlError error, String message) {
|
||||
return String.format("%s: %s", error, message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,6 @@ import org.lwjgl.opengl.GLCapabilities;
|
|||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.framebuffer.Blit;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.framebuffer.Framebuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.instancing.BaseVertex;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.instancing.DrawInstanced;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.instancing.InstancedArrays;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.instancing.VertexArrayObject;
|
||||
|
||||
/**
|
||||
* An instance of this class stores information about what OpenGL features are available.
|
||||
* <br>
|
||||
|
@ -23,52 +16,19 @@ import com.jozufozu.flywheel.backend.gl.versioned.instancing.VertexArrayObject;
|
|||
* system.
|
||||
*/
|
||||
public class GlCompat {
|
||||
public final MapBufferRange mapBufferRange;
|
||||
|
||||
public final VertexArrayObject vao;
|
||||
public final InstancedArrays instancedArrays;
|
||||
public final DrawInstanced drawInstanced;
|
||||
public final Blit blit;
|
||||
public final Framebuffer fbo;
|
||||
public final BufferStorage bufferStorage;
|
||||
|
||||
public final RGPixelFormat pixelFormat;
|
||||
public final BaseVertex baseVertex;
|
||||
|
||||
public GlCompat(GLCapabilities caps) {
|
||||
mapBufferRange = getLatest(MapBufferRange.class, caps);
|
||||
|
||||
vao = getLatest(VertexArrayObject.class, caps);
|
||||
instancedArrays = getLatest(InstancedArrays.class, caps);
|
||||
drawInstanced = getLatest(DrawInstanced.class, caps);
|
||||
baseVertex = getLatest(BaseVertex.class, caps);
|
||||
blit = getLatest(Blit.class, caps);
|
||||
fbo = getLatest(Framebuffer.class, caps);
|
||||
bufferStorage = getLatest(BufferStorage.class, caps);
|
||||
|
||||
pixelFormat = getLatest(RGPixelFormat.class, caps);
|
||||
}
|
||||
|
||||
public boolean vertexArrayObjectsSupported() {
|
||||
return vao != VertexArrayObject.UNSUPPORTED;
|
||||
}
|
||||
|
||||
public boolean instancedArraysSupported() {
|
||||
return instancedArrays != InstancedArrays.UNSUPPORTED;
|
||||
}
|
||||
|
||||
public boolean drawInstancedSupported() {
|
||||
return drawInstanced != DrawInstanced.UNSUPPORTED;
|
||||
}
|
||||
|
||||
public boolean fbosSupported() {
|
||||
return fbo != Framebuffer.UNSUPPORTED;
|
||||
}
|
||||
|
||||
public boolean blitSupported() {
|
||||
return blit != Blit.UNSUPPORTED;
|
||||
}
|
||||
|
||||
public boolean bufferStorageSupported() {
|
||||
return bufferStorage != BufferStorage.UNSUPPORTED;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package com.jozufozu.flywheel.backend.gl.versioned.instancing;
|
||||
package com.jozufozu.flywheel.backend.gl.versioned;
|
||||
|
||||
import org.lwjgl.opengl.ARBInstancedArrays;
|
||||
import org.lwjgl.opengl.GL33;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlVersioned;
|
||||
|
||||
public enum InstancedArrays implements GlVersioned {
|
||||
GL33_INSTANCED_ARRAYS {
|
||||
@Override
|
|
@ -1,49 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.versioned;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.opengl.ARBMapBufferRange;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
|
||||
public enum MapBufferRange implements GlVersioned {
|
||||
|
||||
GL30_RANGE {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.OpenGL30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access) {
|
||||
return GL30.glMapBufferRange(target.glEnum, offset, length, access);
|
||||
}
|
||||
},
|
||||
ARB_RANGE {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.GL_ARB_map_buffer_range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access) {
|
||||
return ARBMapBufferRange.glMapBufferRange(target.glEnum, offset, length, access);
|
||||
}
|
||||
},
|
||||
UNSUPPORTED {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access) {
|
||||
throw new UnsupportedOperationException("glMapBuffer not supported");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public abstract ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access);
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.versioned;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
public enum RGPixelFormat implements GlVersioned {
|
||||
GL30_RG {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.OpenGL30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int internalFormat() {
|
||||
return GL30.GL_RG8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int format() {
|
||||
return GL30.GL_RG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int byteCount() {
|
||||
return 2;
|
||||
}
|
||||
},
|
||||
GL11_RGB {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.OpenGL11;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int internalFormat() {
|
||||
return GL11.GL_RGB8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int format() {
|
||||
return GL11.GL_RGB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int byteCount() {
|
||||
return 3;
|
||||
}
|
||||
},
|
||||
UNSUPPORTED {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int internalFormat() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int format() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int byteCount() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
public abstract int internalFormat();
|
||||
|
||||
public abstract int format();
|
||||
|
||||
public abstract int byteCount();
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.versioned.framebuffer;
|
||||
|
||||
import org.lwjgl.opengl.EXTFramebufferBlit;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlVersioned;
|
||||
|
||||
public enum Blit implements GlVersioned {
|
||||
CORE {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.OpenGL30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
|
||||
GL30.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
}
|
||||
},
|
||||
EXT {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.GL_EXT_framebuffer_blit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
|
||||
EXTFramebufferBlit.glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
}
|
||||
},
|
||||
UNSUPPORTED {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
|
||||
throw new UnsupportedOperationException("Framebuffer blitting not supported.");
|
||||
}
|
||||
};
|
||||
|
||||
public abstract void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter);
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.versioned.framebuffer;
|
||||
|
||||
import org.lwjgl.opengl.ARBFramebufferObject;
|
||||
import org.lwjgl.opengl.EXTFramebufferObject;
|
||||
import org.lwjgl.opengl.GL30C;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlVersioned;
|
||||
|
||||
public enum Framebuffer implements GlVersioned {
|
||||
CORE {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.OpenGL30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindFramebuffer(int target, int framebuffer) {
|
||||
GL30C.glBindFramebuffer(target, framebuffer);
|
||||
}
|
||||
},
|
||||
ARB {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.GL_ARB_framebuffer_object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindFramebuffer(int target, int framebuffer) {
|
||||
ARBFramebufferObject.glBindFramebuffer(target, framebuffer);
|
||||
}
|
||||
},
|
||||
EXT {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.GL_EXT_framebuffer_object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindFramebuffer(int target, int framebuffer) {
|
||||
EXTFramebufferObject.glBindFramebufferEXT(target, framebuffer);
|
||||
}
|
||||
},
|
||||
UNSUPPORTED {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindFramebuffer(int target, int framebuffer) {
|
||||
throw new UnsupportedOperationException("Framebuffers not supported");
|
||||
}
|
||||
};
|
||||
|
||||
public abstract void bindFramebuffer(int target, int framebuffer);
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.versioned.instancing;
|
||||
|
||||
import org.lwjgl.opengl.ARBDrawElementsBaseVertex;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlVersioned;
|
||||
|
||||
public enum BaseVertex implements GlVersioned {
|
||||
GL31_CORE {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.OpenGL31;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawElementsInstancedBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int instanceCount, int baseVertex) {
|
||||
GL32.glDrawElementsInstancedBaseVertex(mode.glEnum, elementCount, type.getGlEnum(), indices, instanceCount, baseVertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawElementsBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int baseVertex) {
|
||||
GL32.glDrawElementsBaseVertex(mode.glEnum, elementCount, type.getGlEnum(), indices, baseVertex);
|
||||
}
|
||||
},
|
||||
ARB {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.GL_ARB_draw_elements_base_vertex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawElementsInstancedBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int instanceCount, int baseVertex) {
|
||||
ARBDrawElementsBaseVertex.glDrawElementsInstancedBaseVertex(mode.glEnum, elementCount, type.getGlEnum(), indices, instanceCount, baseVertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawElementsBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int baseVertex) {
|
||||
ARBDrawElementsBaseVertex.glDrawElementsBaseVertex(mode.glEnum, elementCount, type.getGlEnum(), indices, baseVertex);
|
||||
}
|
||||
},
|
||||
UNSUPPORTED {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public void drawElementsInstancedBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int instanceCount, int baseVertex) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
public void drawElementsBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int baseVertex) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.versioned.instancing;
|
||||
|
||||
import org.lwjgl.opengl.ARBDrawInstanced;
|
||||
import org.lwjgl.opengl.EXTDrawInstanced;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlVersioned;
|
||||
|
||||
public enum DrawInstanced implements GlVersioned {
|
||||
GL31_CORE {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.OpenGL31;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawArraysInstanced(GlPrimitive mode, int first, int count, int primcount) {
|
||||
GL31.glDrawArraysInstanced(mode.glEnum, first, count, primcount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawElementsInstanced(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int primcount) {
|
||||
GL31.glDrawElementsInstanced(mode.glEnum, elementCount, type.getGlEnum(), indices, primcount);
|
||||
}
|
||||
},
|
||||
ARB {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.GL_ARB_draw_instanced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawArraysInstanced(GlPrimitive mode, int first, int count, int primcount) {
|
||||
ARBDrawInstanced.glDrawArraysInstancedARB(mode.glEnum, first, count, primcount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawElementsInstanced(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int primcount) {
|
||||
ARBDrawInstanced.glDrawElementsInstancedARB(mode.glEnum, elementCount, type.getGlEnum(), indices, primcount);
|
||||
}
|
||||
},
|
||||
EXT {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.GL_EXT_draw_instanced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawArraysInstanced(GlPrimitive mode, int first, int count, int primcount) {
|
||||
EXTDrawInstanced.glDrawArraysInstancedEXT(mode.glEnum, first, count, primcount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawElementsInstanced(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int primcount) {
|
||||
EXTDrawInstanced.glDrawElementsInstancedEXT(mode.glEnum, elementCount, type.getGlEnum(), indices, primcount);
|
||||
}
|
||||
},
|
||||
UNSUPPORTED {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public void drawArraysInstanced(GlPrimitive mode, int first, int count, int primcount) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void drawElementsInstanced(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int primcount) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.versioned.instancing;
|
||||
|
||||
import org.lwjgl.opengl.ARBVertexArrayObject;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlVersioned;
|
||||
|
||||
public enum VertexArrayObject implements GlVersioned {
|
||||
GL30_VAO {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.OpenGL30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int genVertexArrays() {
|
||||
return GL30.glGenVertexArrays();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindVertexArray(int array) {
|
||||
GL30.glBindVertexArray(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteVertexArrays(int array) {
|
||||
GL30.glDeleteVertexArrays(array);
|
||||
}
|
||||
},
|
||||
ARB_VAO {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return caps.GL_ARB_vertex_array_object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int genVertexArrays() {
|
||||
return ARBVertexArrayObject.glGenVertexArrays();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindVertexArray(int array) {
|
||||
ARBVertexArrayObject.glBindVertexArray(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteVertexArrays(int array) {
|
||||
ARBVertexArrayObject.glDeleteVertexArrays(array);
|
||||
}
|
||||
},
|
||||
UNSUPPORTED {
|
||||
@Override
|
||||
public boolean supported(GLCapabilities caps) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int genVertexArrays() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindVertexArray(int array) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteVertexArrays(int array) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
public abstract int genVertexArrays();
|
||||
|
||||
public abstract void bindVertexArray(int array);
|
||||
|
||||
public abstract void deleteVertexArrays(int array);
|
||||
}
|
|
@ -3,10 +3,13 @@ package com.jozufozu.flywheel.backend.instancing;
|
|||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.jozufozu.flywheel.api.instance.IDynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.IInstance;
|
||||
import com.jozufozu.flywheel.api.instance.ITickableInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManager;
|
||||
import com.jozufozu.flywheel.core.materials.IFlatLight;
|
||||
import com.jozufozu.flywheel.light.ILightUpdateListener;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.core.materials.FlatLit;
|
||||
import com.jozufozu.flywheel.light.LightListener;
|
||||
import com.jozufozu.flywheel.light.ImmutableBox;
|
||||
import com.jozufozu.flywheel.light.LightProvider;
|
||||
import com.jozufozu.flywheel.light.ListenerStatus;
|
||||
|
@ -19,7 +22,7 @@ import net.minecraft.world.level.LightLayer;
|
|||
* A general interface providing information about any type of thing that could use Flywheel's instanced rendering.
|
||||
* Right now, that's only {@link TileInstanceManager}, but there could be an entity equivalent in the future.
|
||||
*/
|
||||
public abstract class AbstractInstance implements IInstance, ILightUpdateListener {
|
||||
public abstract class AbstractInstance implements IInstance, LightListener {
|
||||
|
||||
protected final MaterialManager materialManager;
|
||||
public final Level world;
|
||||
|
@ -84,19 +87,19 @@ public abstract class AbstractInstance implements IInstance, ILightUpdateListene
|
|||
updateLight();
|
||||
}
|
||||
|
||||
protected void relight(BlockPos pos, IFlatLight<?>... models) {
|
||||
protected void relight(BlockPos pos, FlatLit<?>... models) {
|
||||
relight(world.getBrightness(LightLayer.BLOCK, pos), world.getBrightness(LightLayer.SKY, pos), models);
|
||||
}
|
||||
|
||||
protected <L extends IFlatLight<?>> void relight(BlockPos pos, Stream<L> models) {
|
||||
protected <L extends FlatLit<?>> void relight(BlockPos pos, Stream<L> models) {
|
||||
relight(world.getBrightness(LightLayer.BLOCK, pos), world.getBrightness(LightLayer.SKY, pos), models);
|
||||
}
|
||||
|
||||
protected void relight(int block, int sky, IFlatLight<?>... models) {
|
||||
protected void relight(int block, int sky, FlatLit<?>... models) {
|
||||
relight(block, sky, Arrays.stream(models));
|
||||
}
|
||||
|
||||
protected <L extends IFlatLight<?>> void relight(int block, int sky, Stream<L> models) {
|
||||
protected <L extends FlatLit<?>> void relight(int block, int sky, Stream<L> models) {
|
||||
models.forEach(model -> model.setBlockLight(block)
|
||||
.setSkyLight(sky));
|
||||
}
|
||||
|
|
|
@ -3,19 +3,20 @@ package com.jozufozu.flywheel.backend.instancing;
|
|||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
|
||||
import com.jozufozu.flywheel.backend.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
public class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
|
||||
public abstract class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
|
||||
|
||||
protected final StructType<D> type;
|
||||
protected final IModel modelData;
|
||||
protected final Model modelData;
|
||||
protected final ArrayList<D> data = new ArrayList<>();
|
||||
|
||||
boolean anyToRemove;
|
||||
boolean anyToUpdate;
|
||||
protected boolean anyToRemove;
|
||||
|
||||
public AbstractInstancer(StructType<D> type, IModel modelData) {
|
||||
protected AbstractInstancer(StructType<D> type, Model modelData) {
|
||||
this.type = type;
|
||||
this.modelData = modelData;
|
||||
}
|
||||
|
@ -25,9 +26,7 @@ public class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
|
|||
*/
|
||||
@Override
|
||||
public D createInstance() {
|
||||
D data = type.create();
|
||||
data.owner = this;
|
||||
return _add(data);
|
||||
return _add(type.create());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,24 +37,17 @@ public class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
|
|||
*/
|
||||
@Override
|
||||
public void stealInstance(D inOther) {
|
||||
if (inOther.owner == this) return;
|
||||
if (inOther.getOwner() == this) return;
|
||||
|
||||
inOther.delete();
|
||||
// sike, we want to keep it, changing the owner reference will still delete it in the other
|
||||
inOther.removed = false;
|
||||
// Changing the owner reference will delete it in the other instancer
|
||||
inOther.getOwner()
|
||||
.notifyRemoval();
|
||||
_add(inOther);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty(InstanceData instanceData) {
|
||||
anyToUpdate = true;
|
||||
instanceData.dirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markRemoval(InstanceData instanceData) {
|
||||
public void notifyRemoval() {
|
||||
anyToRemove = true;
|
||||
instanceData.removed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,10 +64,8 @@ public class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
|
|||
|
||||
for (int i = 0; i < size; i++) {
|
||||
D element = data.get(i);
|
||||
if (element.dirty) {
|
||||
if (element.checkDirtyAndClear()) {
|
||||
dirtySet.set(i);
|
||||
|
||||
element.dirty = false;
|
||||
}
|
||||
}
|
||||
return dirtySet;
|
||||
|
@ -88,7 +78,7 @@ public class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
|
|||
final BitSet removeSet = new BitSet(oldSize);
|
||||
for (int i = 0; i < oldSize; i++) {
|
||||
final D element = this.data.get(i);
|
||||
if (element.removed || element.owner != this) {
|
||||
if (element.isRemoved() || element.getOwner() != this) {
|
||||
removeSet.set(i);
|
||||
removeCount++;
|
||||
}
|
||||
|
@ -103,22 +93,22 @@ public class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
|
|||
if (i != j) {
|
||||
D element = data.get(i);
|
||||
data.set(j, element);
|
||||
element.dirty = true;
|
||||
// Marking the data dirty marks us dirty too.
|
||||
// Perhaps there will be some wasted cycles, but the JVM should be able to
|
||||
// generate code that moves the repeated segment out of the loop.
|
||||
element.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
anyToUpdate = true;
|
||||
|
||||
data.subList(newSize, oldSize)
|
||||
.clear();
|
||||
|
||||
}
|
||||
|
||||
private D _add(D instanceData) {
|
||||
instanceData.owner = this;
|
||||
instanceData.setOwner(this);
|
||||
|
||||
instanceData.dirty = true;
|
||||
anyToUpdate = true;
|
||||
instanceData.markDirty();
|
||||
synchronized (data) {
|
||||
data.add(instanceData);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
|
||||
public interface Engine extends RenderDispatcher, MaterialManager {
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
public abstract class InstanceData {
|
||||
|
||||
Instancer<?> owner;
|
||||
|
||||
boolean dirty;
|
||||
boolean removed;
|
||||
|
||||
public void markDirty() {
|
||||
owner.markDirty(this);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
owner.markRemoval(this);
|
||||
}
|
||||
|
||||
}
|
|
@ -9,8 +9,10 @@ import java.util.Set;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManager;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManagerImpl;
|
||||
import com.jozufozu.flywheel.api.instance.IDynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.ITickableInstance;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.light.LightUpdater;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
|
@ -19,7 +21,7 @@ import net.minecraft.client.Camera;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public abstract class InstanceManager<T> implements MaterialManagerImpl.OriginShiftListener {
|
||||
public abstract class InstanceManager<T> implements InstancingEngine.OriginShiftListener {
|
||||
|
||||
public final MaterialManager materialManager;
|
||||
|
||||
|
@ -33,7 +35,7 @@ public abstract class InstanceManager<T> implements MaterialManagerImpl.OriginSh
|
|||
protected int frame;
|
||||
protected int tick;
|
||||
|
||||
public InstanceManager(MaterialManagerImpl<?> materialManager) {
|
||||
public InstanceManager(MaterialManager materialManager) {
|
||||
this.materialManager = materialManager;
|
||||
this.queuedUpdates = new HashSet<>(64);
|
||||
this.queuedAdditions = new HashSet<>(64);
|
||||
|
@ -41,8 +43,6 @@ public abstract class InstanceManager<T> implements MaterialManagerImpl.OriginSh
|
|||
|
||||
this.dynamicInstances = new Object2ObjectOpenHashMap<>();
|
||||
this.tickableInstances = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
materialManager.addListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,6 +213,10 @@ public abstract class InstanceManager<T> implements MaterialManagerImpl.OriginSh
|
|||
}
|
||||
|
||||
protected void processQueuedAdditions() {
|
||||
if (queuedAdditions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<T> queued;
|
||||
|
||||
synchronized (queuedAdditions) {
|
||||
|
@ -220,7 +224,7 @@ public abstract class InstanceManager<T> implements MaterialManagerImpl.OriginSh
|
|||
queuedAdditions.clear();
|
||||
}
|
||||
|
||||
if (queued.size() > 0) {
|
||||
if (!queued.isEmpty()) {
|
||||
queued.forEach(this::addInternal);
|
||||
}
|
||||
}
|
||||
|
@ -292,9 +296,15 @@ public abstract class InstanceManager<T> implements MaterialManagerImpl.OriginSh
|
|||
.addListener(renderer);
|
||||
instances.put(obj, renderer);
|
||||
|
||||
if (renderer instanceof IDynamicInstance) dynamicInstances.put(obj, (IDynamicInstance) renderer);
|
||||
if (renderer instanceof ITickableInstance r) {
|
||||
tickableInstances.put(obj, r);
|
||||
r.tick();
|
||||
}
|
||||
|
||||
if (renderer instanceof ITickableInstance) tickableInstances.put(obj, ((ITickableInstance) renderer));
|
||||
if (renderer instanceof IDynamicInstance r) {
|
||||
dynamicInstances.put(obj, r);
|
||||
r.beginFrame();
|
||||
}
|
||||
}
|
||||
|
||||
return renderer;
|
||||
|
@ -306,4 +316,10 @@ public abstract class InstanceManager<T> implements MaterialManagerImpl.OriginSh
|
|||
invalidate();
|
||||
instancedTiles.forEach(this::add);
|
||||
}
|
||||
|
||||
public void detachLightListeners() {
|
||||
for (AbstractInstance value : instances.values()) {
|
||||
LightUpdater.get(value.world).removeListener(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import com.jozufozu.flywheel.api.instance.IDynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.ITickableInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManager;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManagerImpl;
|
||||
import com.jozufozu.flywheel.backend.instancing.batching.BatchingEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.core.Contexts;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
import com.jozufozu.flywheel.util.ChunkIter;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
|
@ -22,20 +22,28 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
|||
* </p>
|
||||
*/
|
||||
public class InstanceWorld {
|
||||
protected final MaterialManagerImpl<WorldProgram> materialManager;
|
||||
protected final Engine engine;
|
||||
protected final InstanceManager<Entity> entityInstanceManager;
|
||||
protected final InstanceManager<BlockEntity> tileEntityInstanceManager;
|
||||
|
||||
public InstanceWorld() {
|
||||
|
||||
materialManager = MaterialManagerImpl.builder(Contexts.WORLD)
|
||||
// TODO: finish impl
|
||||
if (false) {
|
||||
engine = new BatchingEngine();
|
||||
entityInstanceManager = new EntityInstanceManager(engine);
|
||||
tileEntityInstanceManager = new TileInstanceManager(engine);
|
||||
} else {
|
||||
InstancingEngine<WorldProgram> manager = InstancingEngine.builder(Contexts.WORLD)
|
||||
.build();
|
||||
entityInstanceManager = new EntityInstanceManager(materialManager);
|
||||
tileEntityInstanceManager = new TileInstanceManager(materialManager);
|
||||
}
|
||||
|
||||
public MaterialManager getMaterialManager() {
|
||||
return materialManager;
|
||||
entityInstanceManager = new EntityInstanceManager(manager);
|
||||
tileEntityInstanceManager = new TileInstanceManager(manager);
|
||||
|
||||
manager.addListener(entityInstanceManager);
|
||||
manager.addListener(tileEntityInstanceManager);
|
||||
engine = manager;
|
||||
}
|
||||
}
|
||||
|
||||
public InstanceManager<Entity> getEntityInstanceManager() {
|
||||
|
@ -50,18 +58,9 @@ public class InstanceWorld {
|
|||
* Free all acquired resources and invalidate this instance world.
|
||||
*/
|
||||
public void delete() {
|
||||
materialManager.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate all the necessary instances to render the given world.
|
||||
*/
|
||||
public void loadAll(ClientLevel world) {
|
||||
ChunkIter.forEachChunk(world, chunk -> {
|
||||
chunk.getBlockEntities().values().forEach(tileEntityInstanceManager::add);
|
||||
});
|
||||
world.entitiesForRendering()
|
||||
.forEach(entityInstanceManager::add);
|
||||
engine.delete();
|
||||
entityInstanceManager.detachLightListeners();
|
||||
tileEntityInstanceManager.detachLightListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,7 +72,7 @@ public class InstanceWorld {
|
|||
* </p>
|
||||
*/
|
||||
public void beginFrame(BeginFrameEvent event) {
|
||||
materialManager.beginFrame(event.getInfo());
|
||||
engine.beginFrame(event.getInfo());
|
||||
|
||||
tileEntityInstanceManager.beginFrame(event.getInfo());
|
||||
entityInstanceManager.beginFrame(event.getInfo());
|
||||
|
@ -99,6 +98,6 @@ public class InstanceWorld {
|
|||
* Draw the given layer.
|
||||
*/
|
||||
public void renderLayer(RenderLayerEvent event) {
|
||||
materialManager.render(event.layer, event.viewProjection, event.camX, event.camY, event.camZ);
|
||||
engine.render(event, event.buffers.bufferSource());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,13 +76,12 @@ public class InstancedRenderDispatcher {
|
|||
ClientLevel world = event.getWorld();
|
||||
if (Backend.getInstance()
|
||||
.canUseInstancing() && world != null) {
|
||||
loadAllInWorld(world);
|
||||
resetInstanceWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadAllInWorld(ClientLevel world) {
|
||||
instanceWorlds.replace(world, InstanceWorld::delete)
|
||||
.loadAll(world);
|
||||
public static void resetInstanceWorld(ClientLevel world) {
|
||||
instanceWorlds.replace(world, InstanceWorld::delete);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,11 +5,12 @@ import java.util.Map;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.jozufozu.flywheel.api.FlywheelRendered;
|
||||
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.entity.IEntityInstanceFactory;
|
||||
import com.jozufozu.flywheel.backend.instancing.tile.ITileInstanceFactory;
|
||||
import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManager;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
|
||||
|
@ -34,11 +35,11 @@ public class InstancedRenderRegistry {
|
|||
}
|
||||
|
||||
public <T extends BlockEntity> boolean shouldSkipRender(T type) {
|
||||
return _skipRender(type.getType()) || ((type instanceof IInstanceRendered) && !((IInstanceRendered) type).shouldRenderNormally());
|
||||
return _skipRender(type.getType()) || ((type instanceof FlywheelRendered) && !((FlywheelRendered) type).shouldRenderNormally());
|
||||
}
|
||||
|
||||
public <T extends Entity> boolean shouldSkipRender(T type) {
|
||||
return _skipRender(type.getType()) || ((type instanceof IInstanceRendered) && !((IInstanceRendered) type).shouldRenderNormally());
|
||||
return _skipRender(type.getType()) || ((type instanceof FlywheelRendered) && !((FlywheelRendered) type).shouldRenderNormally());
|
||||
}
|
||||
|
||||
public <T extends BlockEntity> boolean canInstance(BlockEntityType<? extends T> type) {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
|
||||
public interface RenderDispatcher {
|
||||
/**
|
||||
* Render every model for every material.
|
||||
*
|
||||
* @param event Context for rendering.
|
||||
* @param buffers The buffer source for which batched rendering should happen.
|
||||
*/
|
||||
void render(RenderLayerEvent event, MultiBufferSource buffers);
|
||||
|
||||
/**
|
||||
* Maintain the integer origin coordinate to be within a certain distance from the camera in all directions.
|
||||
* <p>
|
||||
* This prevents floating point precision issues at high coordinates.
|
||||
*/
|
||||
void beginFrame(Camera info);
|
||||
|
||||
default void delete() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.Material;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
public class BatchedMaterial<D extends InstanceData> implements Material<D> {
|
||||
|
||||
protected final Map<Object, CPUInstancer<D>> models;
|
||||
private final StructType<D> type;
|
||||
|
||||
public BatchedMaterial(StructType<D> type) {
|
||||
this.type = type;
|
||||
|
||||
this.models = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instancer<D> model(Object key, Supplier<Model> modelSupplier) {
|
||||
return models.computeIfAbsent(key, $ -> new CPUInstancer<>(type, modelSupplier.get()));
|
||||
}
|
||||
|
||||
public void render(PoseStack stack, VertexConsumer buffer) {
|
||||
for (CPUInstancer<D> instancer : models.values()) {
|
||||
instancer.drawAll(stack, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all instance data without freeing resources.
|
||||
*/
|
||||
public void clear() {
|
||||
models.values()
|
||||
.forEach(CPUInstancer::clear);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class BatchedMaterialGroup implements MaterialGroup {
|
||||
|
||||
protected final RenderType state;
|
||||
|
||||
private final Map<StructType<? extends InstanceData>, BatchedMaterial<?>> materials = new HashMap<>();
|
||||
|
||||
public BatchedMaterialGroup(RenderType state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the material as defined by the given {@link StructType type}.
|
||||
* @param spec The material you want to create instances with.
|
||||
* @param <D> The type representing the per instance data.
|
||||
* @return A
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <D extends InstanceData> BatchedMaterial<D> material(StructType<D> spec) {
|
||||
return (BatchedMaterial<D>) materials.computeIfAbsent(spec, BatchedMaterial::new);
|
||||
}
|
||||
|
||||
public void render(PoseStack stack, MultiBufferSource source) {
|
||||
VertexConsumer buffer = source.getBuffer(state);
|
||||
|
||||
for (BatchedMaterial<?> value : materials.values()) {
|
||||
value.render(stack, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
materials.values().forEach(BatchedMaterial::clear);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
materials.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
|
||||
public class BatchingEngine implements Engine {
|
||||
|
||||
protected BlockPos originCoordinate = BlockPos.ZERO;
|
||||
|
||||
protected final Map<RenderLayer, Map<RenderType, BatchedMaterialGroup>> layers;
|
||||
|
||||
public BatchingEngine() {
|
||||
this.layers = new EnumMap<>(RenderLayer.class);
|
||||
for (RenderLayer value : RenderLayer.values()) {
|
||||
layers.put(value, new HashMap<>());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialGroup state(RenderLayer layer, RenderType state) {
|
||||
return layers.get(layer).computeIfAbsent(state, BatchedMaterialGroup::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getOriginCoordinate() {
|
||||
return originCoordinate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(RenderLayerEvent event, MultiBufferSource buffers) {
|
||||
for (Map.Entry<RenderType, BatchedMaterialGroup> entry : layers.get(event.getLayer()).entrySet()) {
|
||||
BatchedMaterialGroup group = entry.getValue();
|
||||
|
||||
group.render(event.stack, buffers);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(Camera info) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.struct.BatchingTransformer;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||
|
||||
private final BatchingTransformer<D> renderer;
|
||||
|
||||
public CPUInstancer(StructType<D> type, Model modelData) {
|
||||
super(type, modelData);
|
||||
|
||||
renderer = type.asBatched()
|
||||
.getTransformer(modelData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDirty() {
|
||||
// noop
|
||||
}
|
||||
|
||||
public void drawAll(PoseStack stack, VertexConsumer buffer) {
|
||||
if (renderer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderSetup();
|
||||
|
||||
for (D d : data) {
|
||||
renderer.draw(d, stack, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderSetup() {
|
||||
if (anyToRemove) {
|
||||
removeDeletedInstances();
|
||||
}
|
||||
|
||||
anyToRemove = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
|
@ -1,13 +1,13 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.entity;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.IDynamicInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.ITickableInstance;
|
||||
import com.jozufozu.flywheel.api.instance.IDynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.ITickableInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManager;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.light.GridAlignedBB;
|
||||
import com.jozufozu.flywheel.light.ILightUpdateListener;
|
||||
import com.jozufozu.flywheel.light.IMovingListener;
|
||||
import com.jozufozu.flywheel.light.LightListener;
|
||||
import com.jozufozu.flywheel.light.MovingListener;
|
||||
import com.jozufozu.flywheel.light.LightProvider;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
|
@ -34,7 +34,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
*
|
||||
* @param <E> The type of {@link Entity} your class is an instance of.
|
||||
*/
|
||||
public abstract class EntityInstance<E extends Entity> extends AbstractInstance implements ILightUpdateListener, IMovingListener {
|
||||
public abstract class EntityInstance<E extends Entity> extends AbstractInstance implements LightListener, MovingListener {
|
||||
|
||||
protected final E entity;
|
||||
protected final GridAlignedBB bounds;
|
||||
|
|
|
@ -4,7 +4,7 @@ import com.jozufozu.flywheel.backend.Backend;
|
|||
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManagerImpl;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
@ -13,7 +13,7 @@ import net.minecraft.world.level.Level;
|
|||
|
||||
public class EntityInstanceManager extends InstanceManager<Entity> {
|
||||
|
||||
public EntityInstanceManager(MaterialManagerImpl<?> materialManager) {
|
||||
public EntityInstanceManager(MaterialManager materialManager) {
|
||||
super(materialManager);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.entity;
|
||||
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManager;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
|
@ -9,11 +10,13 @@ import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
|||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.backend.model.IBufferedModel;
|
||||
import com.jozufozu.flywheel.backend.model.ModelAllocator;
|
||||
import com.jozufozu.flywheel.backend.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.util.AttribUtil;
|
||||
|
||||
public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||
|
@ -29,12 +32,19 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
private boolean deleted;
|
||||
private boolean initialized;
|
||||
|
||||
public GPUInstancer(StructType<D> type, IModel model, ModelAllocator modelAllocator) {
|
||||
protected boolean anyToUpdate;
|
||||
|
||||
public GPUInstancer(StructType<D> type, Model model, ModelAllocator modelAllocator) {
|
||||
super(type, model);
|
||||
this.modelAllocator = modelAllocator;
|
||||
this.instanceFormat = type.format();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDirty() {
|
||||
anyToUpdate = true;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if (invalid()) return;
|
||||
|
||||
|
@ -51,10 +61,6 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
|
||||
// persistent mapping sync point
|
||||
instanceVBO.doneForThisFrame();
|
||||
|
||||
vao.unbind();
|
||||
|
||||
GlError.pollAndThrow(() -> modelData.name() + "_unbind");
|
||||
}
|
||||
|
||||
private boolean invalid() {
|
||||
|
@ -72,16 +78,12 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
vao.bind();
|
||||
|
||||
model.setupState();
|
||||
|
||||
vao.unbind();
|
||||
});
|
||||
|
||||
vao.bind();
|
||||
|
||||
instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
|
||||
AttribUtil.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount());
|
||||
|
||||
vao.unbind();
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
|
@ -135,9 +137,11 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
final int offset = size * instanceFormat.getStride();
|
||||
final int length = glBufferSize - offset;
|
||||
if (length > 0) {
|
||||
instanceVBO.getBuffer(offset, length)
|
||||
.putByteArray(new byte[length])
|
||||
.flush();
|
||||
try (MappedBuffer buf = instanceVBO.getBuffer(offset, length)) {
|
||||
buf.putByteArray(new byte[length]);
|
||||
} catch (Exception e) {
|
||||
Flywheel.log.error("Error clearing buffer tail:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,16 +162,19 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
final int length = (1 + lastDirty - firstDirty) * stride;
|
||||
|
||||
if (length > 0) {
|
||||
MappedBuffer mapped = instanceVBO.getBuffer(offset, length);
|
||||
try (MappedBuffer mapped = instanceVBO.getBuffer(offset, length)) {
|
||||
|
||||
StructWriter<D> writer = type.asWriteable().getWriter(mapped);
|
||||
StructWriter<D> writer = type.asInstanced()
|
||||
.getWriter(mapped);
|
||||
|
||||
dirtySet.stream()
|
||||
.forEach(i -> {
|
||||
writer.seek(i);
|
||||
writer.write(data.get(i));
|
||||
});
|
||||
mapped.flush();
|
||||
} catch (Exception e) {
|
||||
Flywheel.log.error("Error updating GPUInstancer:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,12 +186,15 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
glBufferSize = requiredSize + stride * 16;
|
||||
instanceVBO.alloc(glBufferSize);
|
||||
|
||||
MappedBuffer buffer = instanceVBO.getBuffer(0, glBufferSize);
|
||||
StructWriter<D> writer = type.asWriteable().getWriter(buffer);
|
||||
try (MappedBuffer buffer = instanceVBO.getBuffer(0, glBufferSize)) {
|
||||
StructWriter<D> writer = type.asInstanced()
|
||||
.getWriter(buffer);
|
||||
for (D datum : data) {
|
||||
writer.write(datum);
|
||||
}
|
||||
buffer.flush();
|
||||
} catch (Exception e) {
|
||||
Flywheel.log.error("Error reallocating GPUInstancer:", e);
|
||||
}
|
||||
|
||||
glInstanceCount = size;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.material;
|
||||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -6,27 +6,28 @@ import java.util.function.Supplier;
|
|||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.jozufozu.flywheel.backend.RenderWork;
|
||||
import com.jozufozu.flywheel.backend.instancing.GPUInstancer;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceData;
|
||||
import com.jozufozu.flywheel.backend.instancing.Instancer;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.Material;
|
||||
import com.jozufozu.flywheel.backend.model.ModelPool;
|
||||
import com.jozufozu.flywheel.backend.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
/**
|
||||
* A collection of Instancers that all have the same format.
|
||||
* @param <D>
|
||||
*/
|
||||
public class MaterialImpl<D extends InstanceData> implements Material<D> {
|
||||
public class InstancedMaterial<D extends InstanceData> implements Material<D> {
|
||||
|
||||
final ModelPool modelPool;
|
||||
protected final Cache<Object, GPUInstancer<D>> models;
|
||||
protected final StructType<D> type;
|
||||
|
||||
public MaterialImpl(MaterialSpec<D> spec) {
|
||||
this.type = spec.getInstanceType();
|
||||
public InstancedMaterial(StructType<D> spec) {
|
||||
this.type = spec;
|
||||
|
||||
modelPool = new ModelPool(spec.getModelFormat(), 64);
|
||||
modelPool = new ModelPool(Formats.UNLIT_MODEL, 64);
|
||||
this.models = CacheBuilder.newBuilder()
|
||||
.removalListener(notification -> {
|
||||
GPUInstancer<?> instancer = (GPUInstancer<?>) notification.getValue();
|
||||
|
@ -43,7 +44,7 @@ public class MaterialImpl<D extends InstanceData> implements Material<D> {
|
|||
* @return An instancer for the given model, capable of rendering many copies for little cost.
|
||||
*/
|
||||
@Override
|
||||
public Instancer<D> model(Object key, Supplier<IModel> modelSupplier) {
|
||||
public Instancer<D> model(Object key, Supplier<Model> modelSupplier) {
|
||||
try {
|
||||
return models.get(key, () -> new GPUInstancer<>(type, modelSupplier.get(), modelPool));
|
||||
} catch (ExecutionException e) {
|
|
@ -0,0 +1,81 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.util.TextureBinder;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
/**
|
||||
* A group of materials all rendered with the same GL state.
|
||||
*
|
||||
* The children of a material group will all be rendered at the same time.
|
||||
* No guarantees are made about the order of draw calls.
|
||||
*/
|
||||
public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialGroup {
|
||||
|
||||
protected final InstancingEngine<P> owner;
|
||||
protected final RenderType type;
|
||||
|
||||
protected final ArrayList<InstancedMaterialRenderer<P>> renderers = new ArrayList<>();
|
||||
|
||||
private final Map<StructType<? extends InstanceData>, InstancedMaterial<?>> materials = new HashMap<>();
|
||||
|
||||
public InstancedMaterialGroup(InstancingEngine<P> owner, RenderType type) {
|
||||
this.owner = owner;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the material as defined by the given {@link MaterialSpec spec}.
|
||||
* @param spec The material you want to create instances with.
|
||||
* @param <D> The type representing the per instance data.
|
||||
* @return A
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <D extends InstanceData> InstancedMaterial<D> material(StructType<D> spec) {
|
||||
return (InstancedMaterial<D>) materials.computeIfAbsent(spec, this::createInstanceMaterial);
|
||||
}
|
||||
|
||||
public void render(Matrix4f viewProjection, double camX, double camY, double camZ) {
|
||||
type.setupRenderState();
|
||||
TextureBinder.bindActiveTextures();
|
||||
for (InstancedMaterialRenderer<P> renderer : renderers) {
|
||||
renderer.render(viewProjection, camX, camY, camZ);
|
||||
}
|
||||
type.clearRenderState();
|
||||
}
|
||||
|
||||
public void setup(P program) {
|
||||
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
materials.values().forEach(InstancedMaterial::clear);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
materials.values()
|
||||
.forEach(InstancedMaterial::delete);
|
||||
|
||||
materials.clear();
|
||||
renderers.clear();
|
||||
}
|
||||
|
||||
private InstancedMaterial<?> createInstanceMaterial(StructType<? extends InstanceData> type) {
|
||||
InstancedMaterial<?> material = new InstancedMaterial<>(type);
|
||||
|
||||
this.renderers.add(new InstancedMaterialRenderer<>(owner.getProgram(type.asInstanced()
|
||||
.getProgramSpec()), material, this::setup));
|
||||
|
||||
return material;
|
||||
}
|
||||
}
|
|
@ -1,21 +1,20 @@
|
|||
package com.jozufozu.flywheel.backend.material;
|
||||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.GPUInstancer;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
public class MaterialRenderer<P extends WorldProgram> {
|
||||
public class InstancedMaterialRenderer<P extends WorldProgram> {
|
||||
|
||||
protected final Supplier<P> program;
|
||||
protected final MaterialImpl<?> material;
|
||||
protected final InstancedMaterial<?> material;
|
||||
|
||||
protected final Consumer<P> setupFunc;
|
||||
|
||||
public MaterialRenderer(Supplier<P> programSupplier, MaterialImpl<?> material, Consumer<P> setupFunc) {
|
||||
public InstancedMaterialRenderer(Supplier<P> programSupplier, InstancedMaterial<?> material, Consumer<P> setupFunc) {
|
||||
this.program = programSupplier;
|
||||
this.material = material;
|
||||
this.setupFunc = setupFunc;
|
|
@ -1,25 +1,34 @@
|
|||
package com.jozufozu.flywheel.backend.material;
|
||||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.jozufozu.flywheel.backend.state.RenderLayer;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||
import com.jozufozu.flywheel.core.WorldContext;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
import com.jozufozu.flywheel.fabric.helper.Matrix4fHelper;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public class MaterialManagerImpl<P extends WorldProgram> implements MaterialManager {
|
||||
public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||
|
||||
public static int MAX_ORIGIN_DISTANCE = 100;
|
||||
|
||||
|
@ -29,19 +38,19 @@ public class MaterialManagerImpl<P extends WorldProgram> implements MaterialMana
|
|||
protected final GroupFactory<P> groupFactory;
|
||||
protected final boolean ignoreOriginCoordinate;
|
||||
|
||||
protected final Map<RenderLayer, Map<RenderType, MaterialGroupImpl<P>>> layers;
|
||||
protected final Map<RenderLayer, Map<RenderType, InstancedMaterialGroup<P>>> layers;
|
||||
|
||||
private final WeakHashSet<OriginShiftListener> listeners;
|
||||
|
||||
public MaterialManagerImpl(WorldContext<P> context) {
|
||||
this(context, MaterialGroupImpl::new, false);
|
||||
public InstancingEngine(WorldContext<P> context) {
|
||||
this(context, InstancedMaterialGroup::new, false);
|
||||
}
|
||||
|
||||
public static <P extends WorldProgram> Builder<P> builder(WorldContext<P> context) {
|
||||
return new Builder<>(context);
|
||||
}
|
||||
|
||||
public MaterialManagerImpl(WorldContext<P> context, GroupFactory<P> groupFactory, boolean ignoreOriginCoordinate) {
|
||||
public InstancingEngine(WorldContext<P> context, GroupFactory<P> groupFactory, boolean ignoreOriginCoordinate) {
|
||||
this.context = context;
|
||||
this.ignoreOriginCoordinate = ignoreOriginCoordinate;
|
||||
|
||||
|
@ -55,47 +64,65 @@ public class MaterialManagerImpl<P extends WorldProgram> implements MaterialMana
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a material group that will render in the given layer with the given state.
|
||||
* Get a material group that will render in the given layer with the given type.
|
||||
*
|
||||
* @param layer The {@link RenderLayer} you want to draw in.
|
||||
* @param state The {@link RenderType} you need to draw with.
|
||||
* @param type The {@link RenderType} you need to draw with.
|
||||
* @return A material group whose children will
|
||||
*/
|
||||
@Override
|
||||
public MaterialGroup state(RenderLayer layer, RenderType state) {
|
||||
return layers.get(layer).computeIfAbsent(state, $ -> groupFactory.create(this));
|
||||
public MaterialGroup state(RenderLayer layer, RenderType type) {
|
||||
return layers.get(layer).computeIfAbsent(type, t -> groupFactory.create(this, t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render every model for every material.
|
||||
* @param layer Which of the 3 {@link RenderLayer render layers} is being drawn?
|
||||
* @param viewProjection How do we get from camera space to clip space?
|
||||
*/
|
||||
public void render(RenderLayer layer, Matrix4f viewProjection, double camX, double camY, double camZ) {
|
||||
@Override
|
||||
public void render(RenderLayerEvent event, MultiBufferSource buffers) {
|
||||
double camX;
|
||||
double camY;
|
||||
double camZ;
|
||||
Matrix4f viewProjection;
|
||||
if (!ignoreOriginCoordinate) {
|
||||
camX -= originCoordinate.getX();
|
||||
camY -= originCoordinate.getY();
|
||||
camZ -= originCoordinate.getZ();
|
||||
camX = event.camX - originCoordinate.getX();
|
||||
camY = event.camY - originCoordinate.getY();
|
||||
camZ = event.camZ - originCoordinate.getZ();
|
||||
|
||||
Matrix4f translate = Matrix4f.createTranslateMatrix((float) -camX, (float) -camY, (float) -camZ);
|
||||
|
||||
Matrix4fHelper.multiplyBackward(translate, viewProjection);
|
||||
|
||||
viewProjection = translate;
|
||||
viewProjection = Matrix4f.createTranslateMatrix((float) -camX, (float) -camY, (float) -camZ);
|
||||
Matrix4fHelper.multiplyBackward(viewProjection, event.viewProjection);
|
||||
} else {
|
||||
camX = event.camX;
|
||||
camY = event.camY;
|
||||
camZ = event.camZ;
|
||||
viewProjection = event.viewProjection;
|
||||
}
|
||||
|
||||
for (Map.Entry<RenderType, MaterialGroupImpl<P>> entry : layers.get(layer).entrySet()) {
|
||||
RenderType state = entry.getKey();
|
||||
MaterialGroupImpl<P> group = entry.getValue();
|
||||
getGroupsToRender(event.getLayer()).forEach(group -> group.render(viewProjection, camX, camY, camZ));
|
||||
|
||||
group.render(state, viewProjection, camX, camY, camZ);
|
||||
GlBufferType.ELEMENT_ARRAY_BUFFER.unbind();
|
||||
GlBufferType.ARRAY_BUFFER.unbind();
|
||||
GlVertexArray.unbind();
|
||||
}
|
||||
|
||||
private Stream<InstancedMaterialGroup<P>> getGroupsToRender(@Nullable RenderLayer layer) {
|
||||
if (layer != null) {
|
||||
return layers.get(layer)
|
||||
.values()
|
||||
.stream();
|
||||
} else {
|
||||
return layers.values()
|
||||
.stream()
|
||||
.flatMap(it -> it.values()
|
||||
.stream());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
for (Map<RenderType, MaterialGroupImpl<P>> groups : layers.values()) {
|
||||
for (Map<RenderType, InstancedMaterialGroup<P>> groups : layers.values()) {
|
||||
|
||||
groups.values().forEach(MaterialGroupImpl::delete);
|
||||
groups.values().forEach(InstancedMaterialGroup::delete);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,6 +144,7 @@ public class MaterialManagerImpl<P extends WorldProgram> implements MaterialMana
|
|||
*
|
||||
* This prevents floating point precision issues at high coordinates.
|
||||
*/
|
||||
@Override
|
||||
public void beginFrame(Camera info) {
|
||||
int cX = Mth.floor(info.getPosition().x);
|
||||
int cY = Mth.floor(info.getPosition().y);
|
||||
|
@ -130,8 +158,8 @@ public class MaterialManagerImpl<P extends WorldProgram> implements MaterialMana
|
|||
|
||||
originCoordinate = new BlockPos(cX, cY, cZ);
|
||||
|
||||
for (Map<RenderType, MaterialGroupImpl<P>> groups : layers.values()) {
|
||||
groups.values().forEach(MaterialGroupImpl::clear);
|
||||
for (Map<RenderType, InstancedMaterialGroup<P>> groups : layers.values()) {
|
||||
groups.values().forEach(InstancedMaterialGroup::clear);
|
||||
}
|
||||
|
||||
listeners.forEach(OriginShiftListener::onOriginShift);
|
||||
|
@ -145,12 +173,12 @@ public class MaterialManagerImpl<P extends WorldProgram> implements MaterialMana
|
|||
|
||||
@FunctionalInterface
|
||||
public interface GroupFactory<P extends WorldProgram> {
|
||||
MaterialGroupImpl<P> create(MaterialManagerImpl<P> materialManager);
|
||||
InstancedMaterialGroup<P> create(InstancingEngine<P> engine, RenderType type);
|
||||
}
|
||||
|
||||
public static class Builder<P extends WorldProgram> {
|
||||
protected final WorldContext<P> context;
|
||||
protected GroupFactory<P> groupFactory = MaterialGroupImpl::new;
|
||||
protected GroupFactory<P> groupFactory = InstancedMaterialGroup::new;
|
||||
protected boolean ignoreOriginCoordinate;
|
||||
|
||||
public Builder(WorldContext<P> context) {
|
||||
|
@ -167,8 +195,8 @@ public class MaterialManagerImpl<P extends WorldProgram> implements MaterialMana
|
|||
return this;
|
||||
}
|
||||
|
||||
public MaterialManagerImpl<P> build() {
|
||||
return new MaterialManagerImpl<>(context, groupFactory, ignoreOriginCoordinate);
|
||||
public InstancingEngine<P> build() {
|
||||
return new InstancingEngine<>(context, groupFactory, ignoreOriginCoordinate);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.tile;
|
||||
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManager;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.tile;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.IDynamicInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.ITickableInstance;
|
||||
import com.jozufozu.flywheel.backend.material.Material;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManager;
|
||||
import com.jozufozu.flywheel.api.instance.IDynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.ITickableInstance;
|
||||
import com.jozufozu.flywheel.api.Material;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
|
||||
|
|
|
@ -4,7 +4,7 @@ import com.jozufozu.flywheel.backend.Backend;
|
|||
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManagerImpl;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
|
@ -13,7 +13,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
|||
|
||||
public class TileInstanceManager extends InstanceManager<BlockEntity> {
|
||||
|
||||
public TileInstanceManager(MaterialManagerImpl<?> materialManager) {
|
||||
public TileInstanceManager(MaterialManager materialManager) {
|
||||
super(materialManager);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.material;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceData;
|
||||
|
||||
public interface MaterialGroup {
|
||||
/**
|
||||
* Get the material as defined by the given {@link MaterialSpec spec}.
|
||||
*
|
||||
* @param spec The material you want to create instances with.
|
||||
* @param <D> The type representing the per instance data.
|
||||
* @return A material you can use to render models.
|
||||
*/
|
||||
<D extends InstanceData> Material<D> material(MaterialSpec<D> spec);
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.material;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceData;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.util.TextureBinder;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
/**
|
||||
* A group of materials all rendered with the same GL state.
|
||||
*
|
||||
* The children of a material group will all be rendered at the same time.
|
||||
* No guarantees are made about the order of draw calls.
|
||||
*/
|
||||
public class MaterialGroupImpl<P extends WorldProgram> implements MaterialGroup {
|
||||
|
||||
protected final MaterialManagerImpl<P> owner;
|
||||
|
||||
protected final ArrayList<MaterialRenderer<P>> renderers = new ArrayList<>();
|
||||
|
||||
private final Map<MaterialSpec<?>, MaterialImpl<?>> materials = new HashMap<>();
|
||||
|
||||
public MaterialGroupImpl(MaterialManagerImpl<P> owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the material as defined by the given {@link MaterialSpec spec}.
|
||||
* @param spec The material you want to create instances with.
|
||||
* @param <D> The type representing the per instance data.
|
||||
* @return A
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <D extends InstanceData> MaterialImpl<D> material(MaterialSpec<D> spec) {
|
||||
return (MaterialImpl<D>) materials.computeIfAbsent(spec, this::createInstanceMaterial);
|
||||
}
|
||||
|
||||
public void render(RenderType type, Matrix4f viewProjection, double camX, double camY, double camZ) {
|
||||
type.setupRenderState();
|
||||
TextureBinder.bindActiveTextures();
|
||||
for (MaterialRenderer<P> renderer : renderers) {
|
||||
renderer.render(viewProjection, camX, camY, camZ);
|
||||
}
|
||||
type.clearRenderState();
|
||||
}
|
||||
|
||||
public void setup(P program) {
|
||||
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
materials.values().forEach(MaterialImpl::clear);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
materials.values()
|
||||
.forEach(MaterialImpl::delete);
|
||||
|
||||
materials.clear();
|
||||
renderers.clear();
|
||||
}
|
||||
|
||||
private MaterialImpl<?> createInstanceMaterial(MaterialSpec<?> type) {
|
||||
MaterialImpl<?> material = new MaterialImpl<>(type);
|
||||
|
||||
this.renderers.add(new MaterialRenderer<>(owner.getProgram(type.getProgramName()), material, this::setup));
|
||||
|
||||
return material;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.material;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceData;
|
||||
import com.jozufozu.flywheel.backend.struct.StructType;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class MaterialSpec<D extends InstanceData> {
|
||||
|
||||
public final ResourceLocation name;
|
||||
|
||||
private final ResourceLocation programSpec;
|
||||
private final VertexFormat modelFormat;
|
||||
private final StructType<D> instanceType;
|
||||
|
||||
public MaterialSpec(ResourceLocation name, ResourceLocation programSpec, VertexFormat modelFormat, StructType<D> type) {
|
||||
this.name = name;
|
||||
this.programSpec = programSpec;
|
||||
this.modelFormat = modelFormat;
|
||||
this.instanceType = type;
|
||||
}
|
||||
|
||||
public ResourceLocation getProgramName() {
|
||||
return programSpec;
|
||||
}
|
||||
|
||||
public VertexFormat getModelFormat() {
|
||||
return modelFormat;
|
||||
}
|
||||
|
||||
public StructType<D> getInstanceType() {
|
||||
return instanceType;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,14 +3,14 @@ package com.jozufozu.flywheel.backend.model;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.util.AttribUtil;
|
||||
|
||||
public class ArrayModelRenderer extends ModelRenderer {
|
||||
|
||||
protected GlVertexArray vao;
|
||||
|
||||
public ArrayModelRenderer(Supplier<IModel> model) {
|
||||
public ArrayModelRenderer(Supplier<Model> model) {
|
||||
super(model);
|
||||
}
|
||||
|
||||
|
@ -22,14 +22,12 @@ public class ArrayModelRenderer extends ModelRenderer {
|
|||
vao.bind();
|
||||
|
||||
model.drawCall();
|
||||
|
||||
vao.unbind();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
initialized = true;
|
||||
IModel model = modelSupplier.get();
|
||||
Model model = modelSupplier.get();
|
||||
|
||||
if (model.empty()) return;
|
||||
|
||||
|
@ -44,7 +42,7 @@ public class ArrayModelRenderer extends ModelRenderer {
|
|||
|
||||
AttribUtil.enableArrays(this.model.getAttributeCount());
|
||||
|
||||
vao.unbind();
|
||||
GlVertexArray.unbind();
|
||||
|
||||
this.model.clearState();
|
||||
}
|
||||
|
|
|
@ -2,25 +2,27 @@ package com.jozufozu.flywheel.backend.model;
|
|||
|
||||
import static org.lwjgl.opengl.GL11.glDrawArrays;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
|
||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.core.model.VecBufferConsumer;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.VecBufferWriter;
|
||||
import com.jozufozu.flywheel.util.AttribUtil;
|
||||
|
||||
public class BufferedModel implements IBufferedModel {
|
||||
|
||||
protected final IModel model;
|
||||
protected final Model model;
|
||||
protected final GlPrimitive primitiveMode;
|
||||
protected GlBuffer vbo;
|
||||
protected boolean deleted;
|
||||
|
||||
public BufferedModel(GlPrimitive primitiveMode, IModel model) {
|
||||
public BufferedModel(GlPrimitive primitiveMode, Model model) {
|
||||
this.model = model;
|
||||
this.primitiveMode = primitiveMode;
|
||||
|
||||
|
@ -31,9 +33,11 @@ public class BufferedModel implements IBufferedModel {
|
|||
vbo.alloc(model.size());
|
||||
|
||||
// mirror it in system memory so we can write to it, and upload our model.
|
||||
MappedBuffer buffer = vbo.getBuffer(0, model.size());
|
||||
model.buffer(new VecBufferConsumer(buffer, model.format()));
|
||||
buffer.flush();
|
||||
try (MappedBuffer buffer = vbo.getBuffer(0, model.size())) {
|
||||
model.buffer(new VecBufferWriter(buffer));
|
||||
} catch (Exception e) {
|
||||
Flywheel.log.error(String.format("Error uploading model '%s':", model.name()), e);
|
||||
}
|
||||
|
||||
vbo.unbind();
|
||||
}
|
||||
|
@ -74,7 +78,7 @@ public class BufferedModel implements IBufferedModel {
|
|||
public void drawInstances(int instanceCount) {
|
||||
if (!valid()) return;
|
||||
|
||||
Backend.getInstance().compat.drawInstanced.drawArraysInstanced(primitiveMode, 0, getVertexCount(), instanceCount);
|
||||
GL31.glDrawArraysInstanced(primitiveMode.glEnum, 0, getVertexCount(), instanceCount);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
public class ImmediateAllocator implements ModelAllocator {
|
||||
|
||||
public static final ImmediateAllocator INSTANCE = new ImmediateAllocator();
|
||||
|
||||
@Override
|
||||
public IBufferedModel alloc(IModel model, Callback allocationCallback) {
|
||||
public IBufferedModel alloc(Model model, Callback allocationCallback) {
|
||||
IndexedModel out = new IndexedModel(model);
|
||||
allocationCallback.onAlloc(out);
|
||||
return out;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
/**
|
||||
* An indexed triangle model. Just what the driver ordered.
|
||||
|
@ -15,7 +15,7 @@ public class IndexedModel extends BufferedModel {
|
|||
|
||||
protected ElementBuffer ebo;
|
||||
|
||||
public IndexedModel(IModel model) {
|
||||
public IndexedModel(Model model) {
|
||||
super(GlPrimitive.TRIANGLES, model);
|
||||
|
||||
this.ebo = model.createEBO();
|
||||
|
@ -35,6 +35,7 @@ public class IndexedModel extends BufferedModel {
|
|||
|
||||
@Override
|
||||
public void drawCall() {
|
||||
ebo.bind();
|
||||
GL20.glDrawElements(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0);
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,6 @@ public class IndexedModel extends BufferedModel {
|
|||
public void drawInstances(int instanceCount) {
|
||||
if (!valid()) return;
|
||||
|
||||
Backend.getInstance().compat.drawInstanced.drawElementsInstanced(primitiveMode, ebo.elementCount, ebo.eboIndexType, 0, instanceCount);
|
||||
GL31.glDrawElementsInstanced(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, instanceCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
public interface ModelAllocator {
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@ public interface ModelAllocator {
|
|||
* @param model The model to allocate.
|
||||
* @return A handle to the allocated model.
|
||||
*/
|
||||
IBufferedModel alloc(IModel model, Callback allocationCallback);
|
||||
IBufferedModel alloc(Model model, Callback allocationCallback);
|
||||
|
||||
@FunctionalInterface
|
||||
interface Callback {
|
||||
|
|
|
@ -3,15 +3,17 @@ package com.jozufozu.flywheel.backend.model;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
|
||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.core.model.VecBufferConsumer;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.VecBufferWriter;
|
||||
import com.jozufozu.flywheel.util.AttribUtil;
|
||||
|
||||
public class ModelPool implements ModelAllocator {
|
||||
|
@ -48,7 +50,7 @@ public class ModelPool implements ModelAllocator {
|
|||
* @return A handle to the allocated model.
|
||||
*/
|
||||
@Override
|
||||
public PooledModel alloc(IModel model, Callback callback) {
|
||||
public PooledModel alloc(Model model, Callback callback) {
|
||||
PooledModel bufferedModel = new PooledModel(model, vertices);
|
||||
bufferedModel.callback = callback;
|
||||
vertices += model.vertexCount();
|
||||
|
@ -114,34 +116,35 @@ public class ModelPool implements ModelAllocator {
|
|||
}
|
||||
|
||||
private void uploadAll() {
|
||||
MappedBuffer buffer = vbo.getBuffer(0, bufferSize);
|
||||
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) {
|
||||
|
||||
VecBufferConsumer consumer = new VecBufferConsumer(buffer, format);
|
||||
VecBufferWriter consumer = new VecBufferWriter(buffer);
|
||||
|
||||
for (PooledModel model : models) {
|
||||
model.model.buffer(consumer);
|
||||
if (model.callback != null)
|
||||
model.callback.onAlloc(model);
|
||||
if (model.callback != null) model.callback.onAlloc(model);
|
||||
}
|
||||
|
||||
buffer.flush();
|
||||
} catch (Exception e) {
|
||||
Flywheel.log.error("Error uploading pooled models:", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadPending() {
|
||||
MappedBuffer buffer = vbo.getBuffer(0, bufferSize);
|
||||
VecBufferConsumer consumer = new VecBufferConsumer(buffer, format);
|
||||
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) {
|
||||
VecBufferWriter consumer = new VecBufferWriter(buffer);
|
||||
|
||||
int stride = format.getStride();
|
||||
for (PooledModel model : pendingUpload) {
|
||||
int pos = model.first * stride;
|
||||
buffer.position(pos);
|
||||
model.model.buffer(consumer);
|
||||
if (model.callback != null)
|
||||
model.callback.onAlloc(model);
|
||||
if (model.callback != null) model.callback.onAlloc(model);
|
||||
}
|
||||
pendingUpload.clear();
|
||||
|
||||
buffer.flush();
|
||||
} catch (Exception e) {
|
||||
Flywheel.log.error("Error uploading pooled models:", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDirty() {
|
||||
|
@ -157,12 +160,12 @@ public class ModelPool implements ModelAllocator {
|
|||
private final ElementBuffer ebo;
|
||||
private Callback callback;
|
||||
|
||||
private final IModel model;
|
||||
private final Model model;
|
||||
private int first;
|
||||
|
||||
private boolean remove;
|
||||
|
||||
public PooledModel(IModel model, int first) {
|
||||
public PooledModel(Model model, int first) {
|
||||
this.model = model;
|
||||
this.first = first;
|
||||
ebo = model.createEBO();
|
||||
|
@ -195,7 +198,7 @@ public class ModelPool implements ModelAllocator {
|
|||
|
||||
@Override
|
||||
public void drawCall() {
|
||||
Backend.getInstance().compat.baseVertex.drawElementsBaseVertex(GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, first);
|
||||
GL32.glDrawElementsBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, first);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -206,7 +209,7 @@ public class ModelPool implements ModelAllocator {
|
|||
|
||||
//Backend.log.info(StringUtil.args("drawElementsInstancedBaseVertex", GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, instanceCount, first));
|
||||
|
||||
Backend.getInstance().compat.baseVertex.drawElementsInstancedBaseVertex(GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, instanceCount, first);
|
||||
GL32.glDrawElementsInstancedBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, instanceCount, first);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,16 +2,16 @@ package com.jozufozu.flywheel.backend.model;
|
|||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.jozufozu.flywheel.core.model.IModel;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
public class ModelRenderer {
|
||||
|
||||
protected Supplier<IModel> modelSupplier;
|
||||
protected Supplier<Model> modelSupplier;
|
||||
protected IBufferedModel model;
|
||||
|
||||
protected boolean initialized;
|
||||
|
||||
public ModelRenderer(Supplier<IModel> modelSupplier) {
|
||||
public ModelRenderer(Supplier<Model> modelSupplier) {
|
||||
this.modelSupplier = modelSupplier;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class ModelRenderer {
|
|||
|
||||
protected void init() {
|
||||
initialized = true;
|
||||
IModel model = modelSupplier.get();
|
||||
Model model = modelSupplier.get();
|
||||
|
||||
if (model.empty()) return;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
|
||||
import com.jozufozu.flywheel.core.shader.IMultiProgram;
|
||||
import com.jozufozu.flywheel.core.shader.ContextAwareProgram;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
|
||||
|
@ -8,8 +8,8 @@ import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
|||
* The main interface for compiling usable shaders from program specs.
|
||||
* @param <P> the type of the program that this pipeline compiles.
|
||||
*/
|
||||
public interface IShaderPipeline<P extends WorldProgram> {
|
||||
public interface ShaderPipeline<P extends WorldProgram> {
|
||||
|
||||
IMultiProgram<P> compile(ProgramSpec spec);
|
||||
ContextAwareProgram<P> compile(ProgramSpec spec);
|
||||
|
||||
}
|
|
@ -9,14 +9,14 @@ import com.jozufozu.flywheel.backend.source.FileResolution;
|
|||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram;
|
||||
import com.jozufozu.flywheel.core.shader.GameStateProgram;
|
||||
import com.jozufozu.flywheel.core.shader.IMultiProgram;
|
||||
import com.jozufozu.flywheel.core.shader.ContextAwareProgram;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramState;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class WorldShaderPipeline<P extends WorldProgram> implements IShaderPipeline<P> {
|
||||
public class WorldShaderPipeline<P extends WorldProgram> implements ShaderPipeline<P> {
|
||||
|
||||
private final ExtensibleGlProgram.Factory<P> factory;
|
||||
|
||||
|
@ -29,14 +29,14 @@ public class WorldShaderPipeline<P extends WorldProgram> implements IShaderPipel
|
|||
this.header = header;
|
||||
}
|
||||
|
||||
public IMultiProgram<P> compile(ProgramSpec spec) {
|
||||
public ContextAwareProgram<P> compile(ProgramSpec spec) {
|
||||
|
||||
SourceFile file = spec.getSource().getFile();
|
||||
|
||||
return compile(spec.name, file, spec.getStates());
|
||||
}
|
||||
|
||||
public IMultiProgram<P> compile(ResourceLocation name, SourceFile file, List<ProgramState> variants) {
|
||||
public ContextAwareProgram<P> compile(ResourceLocation name, SourceFile file, List<ProgramState> variants) {
|
||||
WorldShader shader = new WorldShader(name, template, header)
|
||||
.setMainSource(file);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.struct;
|
|||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,7 +25,6 @@ import net.fabricmc.loader.api.FabricLoader;
|
|||
|
||||
public class FlwConfig {
|
||||
protected static final Logger LOGGER = LogManager.getLogger("Flywheel Config");
|
||||
protected static final JsonParser PARSER = new JsonParser();
|
||||
protected static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
private static final FlwConfig INSTANCE = new FlwConfig(FabricLoader.getInstance().getConfigDir().resolve("flywheel.json").toFile());
|
||||
|
@ -63,7 +62,7 @@ public class FlwConfig {
|
|||
public void load() {
|
||||
if (file.exists()) {
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
fromJson(PARSER.parse(reader));
|
||||
fromJson(JsonParser.parseReader(reader));
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Could not load config from file '" + file.getAbsolutePath() + "'", e);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.jozufozu.flywheel.core;
|
|||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.GameStateRegistry;
|
||||
import com.jozufozu.flywheel.backend.pipeline.IShaderPipeline;
|
||||
import com.jozufozu.flywheel.backend.pipeline.ShaderPipeline;
|
||||
import com.jozufozu.flywheel.backend.pipeline.InstancingTemplate;
|
||||
import com.jozufozu.flywheel.backend.pipeline.WorldShaderPipeline;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
|
@ -29,8 +29,8 @@ public class Contexts {
|
|||
FileResolution crumblingBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.CRUMBLING, ".glsl"));
|
||||
FileResolution worldBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.WORLD, ".glsl"));
|
||||
|
||||
IShaderPipeline<CrumblingProgram> crumblingPipeline = new WorldShaderPipeline<>(CrumblingProgram::new, InstancingTemplate.INSTANCE, crumblingBuiltins);
|
||||
IShaderPipeline<WorldProgram> worldPipeline = new WorldShaderPipeline<>(WorldProgram::new, InstancingTemplate.INSTANCE, worldBuiltins);
|
||||
ShaderPipeline<CrumblingProgram> crumblingPipeline = new WorldShaderPipeline<>(CrumblingProgram::new, InstancingTemplate.INSTANCE, crumblingBuiltins);
|
||||
ShaderPipeline<WorldProgram> worldPipeline = new WorldShaderPipeline<>(WorldProgram::new, InstancingTemplate.INSTANCE, worldBuiltins);
|
||||
|
||||
CRUMBLING = backend.register(WorldContext.builder(backend, Names.CRUMBLING).build(crumblingPipeline));
|
||||
WORLD = backend.register(WorldContext.builder(backend, Names.WORLD).build(worldPipeline));
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.*;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.util.Lazy;
|
||||
|
||||
|
@ -28,25 +32,27 @@ public class FullscreenQuad {
|
|||
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
vbo.bind();
|
||||
vbo.alloc(bufferSize);
|
||||
vbo.getBuffer(0, bufferSize)
|
||||
.putFloatArray(vertices)
|
||||
.flush();
|
||||
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) {
|
||||
buffer.putFloatArray(vertices);
|
||||
} catch (Exception e) {
|
||||
Flywheel.log.error("Could not create fullscreen quad.", e);
|
||||
}
|
||||
|
||||
vao = new GlVertexArray();
|
||||
vao.bind();
|
||||
|
||||
GL20.glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
GL20.glVertexAttribPointer(0, 4, GlNumericType.FLOAT.getGlEnum(), false, 4 * 4, 0);
|
||||
glVertexAttribPointer(0, 4, GlNumericType.FLOAT.getGlEnum(), false, 4 * 4, 0);
|
||||
|
||||
vao.unbind();
|
||||
GlVertexArray.unbind();
|
||||
vbo.unbind();
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
vao.bind();
|
||||
GL20.glDrawArrays(GL20.GL_TRIANGLES, 0, 6);
|
||||
vao.unbind();
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
GlVertexArray.unbind();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import com.jozufozu.flywheel.backend.material.MaterialSpec;
|
||||
import com.jozufozu.flywheel.backend.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelType;
|
||||
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
|
||||
|
@ -11,17 +11,14 @@ import com.jozufozu.flywheel.event.GatherContextEvent;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class Materials {
|
||||
public static final StructType<OrientedData> ORIENTED_TYPE = new OrientedType();
|
||||
public static final StructType<ModelData> TRANSFORMED_TYPE = new ModelType();
|
||||
|
||||
public static final MaterialSpec<OrientedData> ORIENTED = new MaterialSpec<>(Names.ORIENTED, Programs.ORIENTED, Formats.UNLIT_MODEL, ORIENTED_TYPE);
|
||||
public static final MaterialSpec<ModelData> TRANSFORMED = new MaterialSpec<>(Names.MODEL, Programs.TRANSFORMED, Formats.UNLIT_MODEL, TRANSFORMED_TYPE);
|
||||
public static final StructType<OrientedData> ORIENTED = new OrientedType();
|
||||
public static final StructType<ModelData> TRANSFORMED = new ModelType();
|
||||
|
||||
public static void flwInit(GatherContextEvent event) {
|
||||
event.getBackend()
|
||||
.register(ORIENTED);
|
||||
event.getBackend()
|
||||
.register(TRANSFORMED);
|
||||
Backend backend = event.getBackend();
|
||||
backend.register(Names.ORIENTED, ORIENTED);
|
||||
backend.register(Names.MODEL, TRANSFORMED);
|
||||
}
|
||||
|
||||
public static class Names {
|
||||
|
|
|
@ -6,24 +6,23 @@ import java.util.function.Supplier;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.IShaderContext;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialSpec;
|
||||
import com.jozufozu.flywheel.backend.pipeline.IShaderPipeline;
|
||||
import com.jozufozu.flywheel.core.shader.IMultiProgram;
|
||||
import com.jozufozu.flywheel.backend.ShaderContext;
|
||||
import com.jozufozu.flywheel.backend.pipeline.ShaderPipeline;
|
||||
import com.jozufozu.flywheel.core.shader.ContextAwareProgram;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class WorldContext<P extends WorldProgram> implements IShaderContext<P> {
|
||||
public class WorldContext<P extends WorldProgram> implements ShaderContext<P> {
|
||||
public final Backend backend;
|
||||
protected final Map<ResourceLocation, IMultiProgram<P>> programs = new HashMap<>();
|
||||
protected final Map<ResourceLocation, ContextAwareProgram<P>> programs = new HashMap<>();
|
||||
protected final ResourceLocation name;
|
||||
protected final Supplier<Stream<ResourceLocation>> specStream;
|
||||
|
||||
public final IShaderPipeline<P> pipeline;
|
||||
public final ShaderPipeline<P> pipeline;
|
||||
|
||||
public WorldContext(Backend backend, ResourceLocation name, Supplier<Stream<ResourceLocation>> specStream, IShaderPipeline<P> pipeline) {
|
||||
public WorldContext(Backend backend, ResourceLocation name, Supplier<Stream<ResourceLocation>> specStream, ShaderPipeline<P> pipeline) {
|
||||
this.backend = backend;
|
||||
this.name = name;
|
||||
this.specStream = specStream;
|
||||
|
@ -61,7 +60,7 @@ public class WorldContext<P extends WorldProgram> implements IShaderContext<P> {
|
|||
@Override
|
||||
public void delete() {
|
||||
programs.values()
|
||||
.forEach(IMultiProgram::delete);
|
||||
.forEach(ContextAwareProgram::delete);
|
||||
programs.clear();
|
||||
}
|
||||
|
||||
|
@ -84,11 +83,12 @@ public class WorldContext<P extends WorldProgram> implements IShaderContext<P> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public <P extends WorldProgram> WorldContext<P> build(IShaderPipeline<P> pipeline) {
|
||||
public <P extends WorldProgram> WorldContext<P> build(ShaderPipeline<P> pipeline) {
|
||||
if (specStream == null) {
|
||||
specStream = () -> backend.allMaterials()
|
||||
.stream()
|
||||
.map(MaterialSpec::getProgramName);
|
||||
.map(type -> type.asInstanced()
|
||||
.getProgramSpec());
|
||||
}
|
||||
return new WorldContext<>(backend, name, specStream, pipeline);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package com.jozufozu.flywheel.core.atlas;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.mixin.atlas.SheetDataAccessor;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
@ -24,15 +26,18 @@ public class AtlasInfo {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SheetData getAtlasData(TextureAtlasSprite texture) {
|
||||
return getAtlasData(texture.atlas());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SheetData getAtlasData(TextureAtlas atlas) {
|
||||
return getAtlasData(atlas.location());
|
||||
}
|
||||
|
||||
public static SheetData getAtlasData(ResourceLocation loc) {
|
||||
@Nullable
|
||||
public static SheetData getAtlasData(@Nullable ResourceLocation loc) {
|
||||
return sheetData.get(loc);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.jozufozu.flywheel.core.crumbling;
|
||||
|
||||
import com.jozufozu.flywheel.backend.material.MaterialGroupImpl;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManagerImpl;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialRenderer;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterialGroup;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterialRenderer;
|
||||
import com.jozufozu.flywheel.core.atlas.AtlasInfo;
|
||||
import com.jozufozu.flywheel.core.atlas.SheetData;
|
||||
import com.jozufozu.flywheel.util.RenderTextures;
|
||||
|
@ -11,33 +11,23 @@ import com.mojang.blaze3d.systems.RenderSystem;
|
|||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class CrumblingGroup<P extends CrumblingProgram> extends MaterialGroupImpl<P> {
|
||||
public class CrumblingGroup<P extends CrumblingProgram> extends InstancedMaterialGroup<P> {
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public CrumblingGroup(MaterialManagerImpl<P> owner) {
|
||||
super(owner);
|
||||
public CrumblingGroup(InstancingEngine<P> owner, RenderType type) {
|
||||
super(owner, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(RenderType type, Matrix4f viewProjection, double camX, double camY, double camZ) {
|
||||
public void render(Matrix4f viewProjection, double camX, double camY, double camZ) {
|
||||
type.setupRenderState();
|
||||
|
||||
int renderTex = RenderSystem.getShaderTexture(0);
|
||||
|
||||
ResourceLocation texture = RenderTextures.getShaderTexture(0);
|
||||
|
||||
if (texture != null) {
|
||||
SheetData atlasData = AtlasInfo.getAtlasData(texture);
|
||||
|
||||
width = atlasData.width;
|
||||
height = atlasData.height;
|
||||
} else {
|
||||
width = height = 256;
|
||||
}
|
||||
updateAtlasSize();
|
||||
|
||||
type.clearRenderState();
|
||||
|
||||
|
@ -49,13 +39,25 @@ public class CrumblingGroup<P extends CrumblingProgram> extends MaterialGroupImp
|
|||
RenderSystem.setShaderTexture(4, breakingTex);
|
||||
|
||||
TextureBinder.bindActiveTextures();
|
||||
for (MaterialRenderer<P> renderer : renderers) {
|
||||
for (InstancedMaterialRenderer<P> renderer : renderers) {
|
||||
renderer.render(viewProjection, camX, camY, camZ);
|
||||
}
|
||||
|
||||
CrumblingRenderer._currentLayer.clearRenderState();
|
||||
}
|
||||
|
||||
private void updateAtlasSize() {
|
||||
|
||||
SheetData atlasData = AtlasInfo.getAtlasData(RenderTextures.getShaderTexture(0));
|
||||
|
||||
if (atlasData != null) {
|
||||
width = atlasData.width;
|
||||
height = atlasData.height;
|
||||
} else {
|
||||
width = height = 256;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(P p) {
|
||||
p.setAtlasSize(width, height);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package com.jozufozu.flywheel.core.crumbling;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManagerImpl;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
public class CrumblingInstanceManager extends TileInstanceManager {
|
||||
|
||||
public CrumblingInstanceManager(MaterialManagerImpl<?> materialManager) {
|
||||
public CrumblingInstanceManager(MaterialManager materialManager) {
|
||||
super(materialManager);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,17 +6,15 @@ import java.util.SortedSet;
|
|||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
import com.jozufozu.flywheel.backend.material.MaterialManagerImpl;
|
||||
import com.jozufozu.flywheel.backend.state.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.core.Contexts;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
import com.jozufozu.flywheel.mixin.LevelRendererAccessor;
|
||||
import com.jozufozu.flywheel.util.Lazy;
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
@ -49,17 +47,17 @@ public class CrumblingRenderer {
|
|||
INVALIDATOR = state.getSecond();
|
||||
}
|
||||
|
||||
public static void renderBreaking(ClientLevel world, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) {
|
||||
public static void renderBreaking(RenderLayerEvent event) {
|
||||
if (!Backend.getInstance()
|
||||
.canUseInstancing(world)) return;
|
||||
.canUseInstancing(event.getWorld())) return;
|
||||
|
||||
Int2ObjectMap<List<BlockEntity>> activeStages = getActiveStageTiles(world);
|
||||
Int2ObjectMap<List<BlockEntity>> activeStages = getActiveStageTiles(event.getWorld());
|
||||
|
||||
if (activeStages.isEmpty()) return;
|
||||
|
||||
State state = STATE.get();
|
||||
InstanceManager<BlockEntity> instanceManager = state.instanceManager;
|
||||
MaterialManagerImpl<CrumblingProgram> materials = state.materialManager;
|
||||
InstancingEngine<CrumblingProgram> materials = state.materialManager;
|
||||
|
||||
TextureManager textureManager = Minecraft.getInstance().getTextureManager();
|
||||
Camera info = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||
|
@ -73,7 +71,7 @@ public class CrumblingRenderer {
|
|||
|
||||
instanceManager.beginFrame(info);
|
||||
|
||||
materials.render(RenderLayer.SOLID, viewProjection, cameraX, cameraY, cameraZ);
|
||||
materials.render(event, null);
|
||||
|
||||
instanceManager.invalidate();
|
||||
}
|
||||
|
@ -126,14 +124,15 @@ public class CrumblingRenderer {
|
|||
}
|
||||
|
||||
private static class State {
|
||||
private final MaterialManagerImpl<CrumblingProgram> materialManager;
|
||||
private final InstancingEngine<CrumblingProgram> materialManager;
|
||||
private final InstanceManager<BlockEntity> instanceManager;
|
||||
|
||||
private State() {
|
||||
materialManager = MaterialManagerImpl.builder(Contexts.CRUMBLING)
|
||||
materialManager = InstancingEngine.builder(Contexts.CRUMBLING)
|
||||
.setGroupFactory(CrumblingGroup::new)
|
||||
.build();
|
||||
instanceManager = new CrumblingInstanceManager(materialManager);
|
||||
materialManager.addListener(instanceManager);
|
||||
}
|
||||
|
||||
private void kill() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue