Skip to content

Commit

Permalink
Update ChunkCompileTask
Browse files Browse the repository at this point in the history
  • Loading branch information
squid233 committed Mar 23, 2024
1 parent c8fd48d commit 275765e
Show file tree
Hide file tree
Showing 10 changed files with 310 additions and 57 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jdkEnablePreview=true
# javadoc link of JDK early access build
# https://download.java.net/java/early_access/$jdkEarlyAccessDoc/docs/api/
# Uncomment it if you need to use EA build of JDK.
jdkEarlyAccessDoc=jdk22
#jdkEarlyAccessDoc=jdk22

projVersion=0.1.0-SNAPSHOT
coreVersion=0.1.0-SNAPSHOT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void init(GLStateMgr gl) {
logger.info("Created {}x{}x{} {}", texture.width(), texture.height(), texture.mipmapLevel(), TextureManager.BLOCK_ATLAS);

blockRenderer = new BlockRenderer(this);
worldRenderer = new WorldRenderer(client, this, client.world());
worldRenderer = new WorldRenderer(this, client.world());

tessellator = new Tessellator();
}
Expand Down Expand Up @@ -111,7 +111,8 @@ public void render(GLStateMgr gl, double partialTick) {
positionColorTexProgram.getUniform(GLProgram.UNIFORM_PROJECTION_VIEW_MATRIX).set(projectionView);
positionColorTexProgram.getUniform(GLProgram.UNIFORM_MODEL_MATRIX).set(matrix);
positionColorTexProgram.uploadUniforms(gl);
worldRenderer.render(gl, tessellator);
worldRenderer.compileChunks();
worldRenderer.renderChunks(gl);

renderGui(gl, partialTick);
}
Expand Down Expand Up @@ -151,6 +152,7 @@ public void close(GLStateMgr gl) {
logger.info("Closing game renderer");

if (textureManager != null) textureManager.close(gl);
if (worldRenderer != null) worldRenderer.close(gl);

if (positionColorProgram != null) positionColorProgram.close(gl);
if (positionColorTexProgram != null) positionColorTexProgram.close(gl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,8 @@ public boolean shouldReallocateVertexData() {
public boolean shouldReallocateIndexData() {
return shouldReallocateIndexData;
}

public VertexLayout vertexLayout() {
return vertexLayout;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@

package io.github.xenfork.freeworld.client.render.gl;

import overrungl.opengl.GL;

/**
* @author squid233
* @since 0.1.0
*/
public enum GLDrawMode {
TRIANGLES(GL.TRIANGLES, 3);
TRIANGLES(GLStateMgr.TRIANGLES, 3);

private final int value;
private final int count;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* freeworld - 3D sandbox game
* Copyright (C) 2024 XenFork Union
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*/

package io.github.xenfork.freeworld.client.render.world;

import io.github.xenfork.freeworld.client.render.GameRenderer;
import io.github.xenfork.freeworld.client.render.builder.DefaultVertexBuilder;
import io.github.xenfork.freeworld.util.Direction;
import io.github.xenfork.freeworld.world.chunk.Chunk;
import io.github.xenfork.freeworld.world.chunk.ChunkPos;

import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.util.concurrent.Callable;

/**
* @author squid233
* @since 0.1.0
*/
public final class ChunkCompileTask implements Callable<ChunkVertexData> {
private final GameRenderer gameRenderer;
private final WorldRenderer worldRenderer;
private final Chunk chunk;

public ChunkCompileTask(GameRenderer gameRenderer, WorldRenderer worldRenderer, Chunk chunk) {
this.gameRenderer = gameRenderer;
this.worldRenderer = worldRenderer;
this.chunk = chunk;
}

@Override
public ChunkVertexData call() {
final var pool = worldRenderer.vertexBuilderPool();
final DefaultVertexBuilder builder = pool.acquire();
try {
final int cx = chunk.x();
final int cy = chunk.y();
final int cz = chunk.z();
for (Direction direction : Direction.LIST) {
for (int x = 0; x < Chunk.SIZE; x++) {
for (int y = 0; y < Chunk.SIZE; y++) {
for (int z = 0; z < Chunk.SIZE; z++) {
final int nx = x + direction.axisX();
final int ny = y + direction.axisY();
final int nz = z + direction.axisZ();
if (chunk.isInBound(nx, ny, nz) && chunk.getBlockType(nx, ny, nz).air()) {
gameRenderer.blockRenderer().renderBlockFace(
builder,
chunk.getBlockType(x, y, z),
ChunkPos.relativeToAbsolute(cx, x),
ChunkPos.relativeToAbsolute(cy, y),
ChunkPos.relativeToAbsolute(cz, z),
direction);
}
}
}
}
}

final Arena arena = Arena.ofShared();
final MemorySegment vertexDataSlice = builder.vertexDataSlice();
final MemorySegment indexDataSlice = builder.indexDataSlice();
return new ChunkVertexData(
builder.vertexLayout(),
builder.indexCount(),
arena,
arena.allocateFrom(ValueLayout.JAVA_BYTE, vertexDataSlice, ValueLayout.JAVA_BYTE, 0L, vertexDataSlice.byteSize()),
arena.allocateFrom(ValueLayout.JAVA_BYTE, indexDataSlice, ValueLayout.JAVA_BYTE, 0L, indexDataSlice.byteSize()),
builder.shouldReallocateVertexData(),
builder.shouldReallocateIndexData()
);
} finally {
pool.release(builder);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* freeworld - 3D sandbox game
* Copyright (C) 2024 XenFork Union
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*/

package io.github.xenfork.freeworld.client.render.world;

import io.github.xenfork.freeworld.client.render.model.VertexLayout;

import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;

/**
* @author squid233
* @since 0.1.0
*/
public record ChunkVertexData(
VertexLayout vertexLayout,
int indexCount,
Arena arena,
MemorySegment vertexData,
MemorySegment indexData,
boolean shouldReallocateVertexData,
boolean shouldReallocateIndexData
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* freeworld - 3D sandbox game
* Copyright (C) 2024 XenFork Union
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*/

package io.github.xenfork.freeworld.client.render.world;

import io.github.xenfork.freeworld.client.render.builder.VertexBuilder;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;

/**
* @author squid233
* @since 0.1.0
*/
public final class VertexBuilderPool<T extends VertexBuilder> {
private final Map<Integer, Pair<T>> map = new ConcurrentHashMap<>();
private final Supplier<T> factory;

public VertexBuilderPool(Supplier<T> factory) {
this.factory = factory;
}

private static final class Pair<T extends VertexBuilder> {
final T builder;
final AtomicBoolean acquired;

Pair(T builder, boolean acquired) {
this.builder = builder;
this.acquired = new AtomicBoolean(acquired);
}
}

public T acquire() {
for (var entry : map.entrySet()) {
final Pair<T> value = entry.getValue();
if (!value.acquired.get()) {
value.acquired.set(true);
return value.builder;
}
}
final T t = factory.get();
final int hashCode = System.identityHashCode(t);
map.put(hashCode, new Pair<>(t, true));
return t;
}

public void release(T t) {
Objects.requireNonNull(t);
final int hashCode = System.identityHashCode(t);
if (map.containsKey(hashCode)) {
final Pair<T> pair = map.get(hashCode);
if (pair.acquired.get()) {
pair.acquired.set(false);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,81 +10,81 @@

package io.github.xenfork.freeworld.client.render.world;

import io.github.xenfork.freeworld.client.Freeworld;
import io.github.xenfork.freeworld.client.render.GameRenderer;
import io.github.xenfork.freeworld.client.render.Tessellator;
import io.github.xenfork.freeworld.client.render.gl.GLDrawMode;
import io.github.xenfork.freeworld.client.render.builder.DefaultVertexBuilder;
import io.github.xenfork.freeworld.client.render.gl.GLResource;
import io.github.xenfork.freeworld.client.render.gl.GLStateMgr;
import io.github.xenfork.freeworld.util.Direction;
import io.github.xenfork.freeworld.client.render.model.VertexLayouts;
import io.github.xenfork.freeworld.client.world.chunk.ClientChunk;
import io.github.xenfork.freeworld.world.World;
import io.github.xenfork.freeworld.world.chunk.Chunk;
import io.github.xenfork.freeworld.world.chunk.ChunkPos;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
* @author squid233
* @since 0.1.0
*/
public final class WorldRenderer implements AutoCloseable {
private final Freeworld client;
public final class WorldRenderer implements GLResource {
private final GameRenderer gameRenderer;
private final World world;
private final ExecutorService executor;
private final VertexBuilderPool<DefaultVertexBuilder> vertexBuilderPool = new VertexBuilderPool<>(() -> new DefaultVertexBuilder(VertexLayouts.POSITION_COLOR_TEX, 30000, 60000));
private final ClientChunk[] chunks;

public WorldRenderer(Freeworld client, GameRenderer gameRenderer, World world) {
this.client = client;
public WorldRenderer(GameRenderer gameRenderer, World world) {
this.gameRenderer = gameRenderer;
this.world = world;
final int processors = Runtime.getRuntime().availableProcessors();
this.executor = new ThreadPoolExecutor(processors,
processors,
0L,
TimeUnit.MILLISECONDS,
new PriorityBlockingQueue<>(),
new LinkedBlockingDeque<>(),
new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);

@Override
public Thread newThread(@NotNull Runnable r) {
return new Thread(r, STR."ChunkCompiler-thread-\{threadNumber.getAndIncrement()}");
}
},
new ThreadPoolExecutor.DiscardPolicy());
this.chunks = new ClientChunk[world.xChunks * world.yChunks * world.zChunks];
for (int x = 0; x < world.xChunks; x++) {
for (int y = 0; y < world.yChunks; y++) {
for (int z = 0; z < world.zChunks; z++) {
this.chunks[(y * world.zChunks + z) * world.xChunks + x] = new ClientChunk(world, x, y, z);
}
}
}
}

public void compileChunks() {
for (ClientChunk chunk : chunks) {
if (chunk.shouldRecompile.get() && !chunk.submitted.get()) {
chunk.future.set(executor.submit(new ChunkCompileTask(gameRenderer, this, world.getChunk(chunk.x(), chunk.y(), chunk.z()))));
chunk.submitted.set(true);
}
}
}

public void render(GLStateMgr gl, Tessellator tessellator) {
// final Vector3dc position = client.camera().position();
final BlockRenderer blockRenderer = gameRenderer.blockRenderer();
tessellator.begin(GLDrawMode.TRIANGLES);
for (Chunk chunk : world.chunks) {
final int cx = chunk.x();
final int cy = chunk.y();
final int cz = chunk.z();
for (Direction direction : Direction.LIST) {
for (int x = 0; x < Chunk.SIZE; x++) {
for (int y = 0; y < Chunk.SIZE; y++) {
for (int z = 0; z < Chunk.SIZE; z++) {
final int nx = x + direction.axisX();
final int ny = y + direction.axisY();
final int nz = z + direction.axisZ();
if (chunk.isInBound(nx, ny, nz) && chunk.getBlockType(nx, ny, nz).air()) {
blockRenderer.renderBlockFace(
tessellator,
chunk.getBlockType(x, y, z),
ChunkPos.relativeToAbsolute(cx, x),
ChunkPos.relativeToAbsolute(cy, y),
ChunkPos.relativeToAbsolute(cz, z),
direction);
}
}
}
}
}
public void renderChunks(GLStateMgr gl) {
for (ClientChunk chunk : chunks) {
chunk.render(gl);
}
tessellator.end(gl);
}

public VertexBuilderPool<DefaultVertexBuilder> vertexBuilderPool() {
return vertexBuilderPool;
}

@Override
public void close() {
public void close(GLStateMgr gl) {
executor.close();
for (ClientChunk chunk : chunks) {
chunk.close(gl);
}
}
}
Loading

0 comments on commit 275765e

Please sign in to comment.