Skip to content

Commit

Permalink
Update render
Browse files Browse the repository at this point in the history
  • Loading branch information
squid233 committed May 19, 2024
1 parent f75ce85 commit 5d6979f
Show file tree
Hide file tree
Showing 10 changed files with 245 additions and 135 deletions.
48 changes: 25 additions & 23 deletions modules/freeworld.client/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,53 @@ plugins {
}

val jdkEnablePreview: String by rootProject

val overrunglVersion: String by rootProject

val overrunglNatives = Pair(
System.getProperty("os.name")!!,
System.getProperty("os.arch")!!
).let { (name, arch) ->
val overrunglOs = System.getProperty("os.name")!!.let { name ->
when {
arrayOf("Linux", "FreeBSD", "SunOS", "Unit").any { name.startsWith(it) } ->
if (arrayOf("arm", "aarch64").any { arch.startsWith(it) })
"natives-linux${if (arch.contains("64") || arch.startsWith("armv8")) "-arm64" else "-arm32"}"
else "natives-linux"

arrayOf("Mac OS X", "Darwin").any { name.startsWith(it) } ->
"natives-macos${if (arch.startsWith("aarch64")) "-arm64" else ""}"

arrayOf("Windows").any { name.startsWith(it) } ->
if (arch.contains("64"))
"natives-windows${if (arch.startsWith("aarch64")) "-arm64" else ""}"
else throw Error("Unrecognized or unsupported architecture. Please set \"overrunglNatives\" manually")
"FreeBSD" == name -> "freebsd"
arrayOf("Linux", "SunOS", "Unit").any { name.startsWith(it) } -> "linux"
arrayOf("Mac OS X", "Darwin").any { name.startsWith(it) } -> "macos"
arrayOf("Windows").any { name.startsWith(it) } -> "windows"
else -> throw Error("Unrecognized or unsupported platform $name. Please set \"overrunglOs\" manually")
}
}
val overrunglArch = System.getProperty("os.arch")!!.let { arch ->
when (overrunglOs) {
"freebsd" -> "x64"
"linux" -> if (arrayOf("arm", "aarch64").any { arch.startsWith(it) }) {
if (arch.contains("64") || arch.startsWith("armv8")) "arm64" else "arm32"
} else if (arch.startsWith("ppc")) "ppc64le"
else if (arch.startsWith("riscv")) "riscv64"
else "x64"

else -> throw Error("Unrecognized or unsupported platform. Please set \"overrunglNatives\" manually")
"macos" -> if (arch.startsWith("aarch64")) "arm64" else "x64"
"windows" -> if (arch.contains("64") && arch.startsWith("aarch64")) "arm64" else "x64"
else -> throw Error("Unrecognized or unsupported platform $overrunglOs. Please set \"overrunglArch\" manually")
}
}

configurations.runtimeClasspath.get().attributes {
attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(overrunglOs))
attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(overrunglArch))
}

dependencies {
api(project(":freeworld"))
implementation(platform("io.github.over-run:overrungl-bom:$overrunglVersion"))
implementation("io.github.over-run:overrungl")
implementation("io.github.over-run:overrungl-joml")
implementation("io.github.over-run:overrungl-glfw")
runtimeOnly("io.github.over-run:overrungl-glfw::$overrunglNatives")
implementation("io.github.over-run:overrungl-opengl")
implementation("io.github.over-run:overrungl-stb")
runtimeOnly("io.github.over-run:overrungl-stb::$overrunglNatives")
//TODO
implementation("io.github.over-run:marshal:0.1.0-alpha.24-jdk22")
}

application {
applicationName = "freeworld"
mainModule = "freeworld.client"
mainClass = "freeworld.client.main.Main"
applicationDefaultJvmArgs = buildList {
if (jdkEnablePreview.toBoolean())add("--enable-preview")
if (jdkEnablePreview.toBoolean()) add("--enable-preview")
add(
"--enable-native-access=${
listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void start() {
glfw.windowHint(GLFW.CONTEXT_VERSION_MINOR, 3);

// center window
final GLFWVidMode.Value videoMode = glfw.getVideoMode(glfw.getPrimaryMonitor());
final GLFWVidMode videoMode = glfw.getVideoMode(glfw.getPrimaryMonitor());
if (videoMode != null) {
glfw.windowHint(GLFW.POSITION_X, (videoMode.width() - INIT_WINDOW_WIDTH) / 2);
glfw.windowHint(GLFW.POSITION_Y, (videoMode.height() - INIT_WINDOW_HEIGHT) / 2);
Expand Down Expand Up @@ -269,6 +269,10 @@ public GLFlags glFlags() {
return glFlags;
}

public GLStateMgr gl() {
return gl;
}

public MemorySegment window() {
return window;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void render(GLStateMgr gl, double partialTick) {


final List<ClientChunk> chunks = worldRenderer.renderingChunks(player);
worldRenderer.compileChunks(chunks);
worldRenderer.compileChunks(player, chunks);
worldRenderer.renderChunks(gl, chunks);

hitResult = worldRenderer.selectBlock(player);
Expand Down Expand Up @@ -206,6 +206,10 @@ public void close(GLStateMgr gl) {
if (tessellator != null) tessellator.close(gl);
}

public Freeworld client() {
return client;
}

public GLProgram positionColorProgram() {
return positionColorProgram;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@
public record NativeImage(int width, int height, MemorySegment segment, boolean failed) {
private static final Logger logger = Logging.caller();

public static NativeImage load(Arena arena, String path) {
final MemorySegment segment = BuiltinFiles.loadBinary(arena, BuiltinFiles.load(path), path);
public static NativeImage load(Arena arena, MemorySegment segment, String path) {
if (Unmarshal.isNullPointer(segment)) {
return fail();
}
Expand All @@ -57,6 +56,10 @@ public static NativeImage load(Arena arena, String path) {
);
}

public static NativeImage load(Arena arena, String path) {
return load(arena, BuiltinFiles.loadBinary(arena, BuiltinFiles.load(path), path), path);
}

public static NativeImage fail() {
final class Holder {
private static final NativeImage FAILED;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ public static TextureAtlas load(GLStateMgr gl, List<Identifier> identifierList)
final Map<Identifier, NativeImage> imageMap = HashMap.newHashMap(numIds);
identifierList.forEach(identifier -> imageMap.put(identifier, NativeImage.load(arena, identifier.toResourcePath(Identifier.ROOT_ASSETS, null, null))));

final STBRPContext context = new STBRPContext(arena);
final STBRPNode nodes = new STBRPNode(arena, numIds);
final STBRPRect rects = new STBRPRect(arena, numIds);
final STBRPContext context = STBRPContext.OF.of(arena);
final STBRPNode nodes = STBRPNode.OF.of(arena, numIds);
final STBRPRect rects = STBRPRect.OF.of(arena, numIds);
int mipmapLevel = 4;
for (int i = 0; i < numIds; i++) {
final NativeImage image = imageMap.get(identifierList.get(i));
Expand All @@ -57,9 +57,9 @@ public static TextureAtlas load(GLStateMgr gl, List<Identifier> identifierList)
} else if (mipmapLevel > 0) {
mipmapLevel = Math.min(Integer.numberOfTrailingZeros(width), Integer.numberOfTrailingZeros(height));
}
STBRPRect.id.set(rects, i, i);
STBRPRect.w.set(rects, i, width);
STBRPRect.h.set(rects, i, height);
rects.slice(i).id(i)
.w(width)
.h(height);
}

int packerSize = 256;
Expand All @@ -86,12 +86,13 @@ public static TextureAtlas load(GLStateMgr gl, List<Identifier> identifierList)
GL10C.UNSIGNED_BYTE,
MemorySegment.NULL);
for (int i = 0; i < numIds; i++) {
if (STBRPRect.wasPacked.get(rects, i) != 0) {
final Identifier identifier = identifierList.get(STBRPRect.id.get(rects, i));
final int xo = STBRPRect.x.get(rects, i);
final int yo = STBRPRect.y.get(rects, i);
final int width = STBRPRect.w.get(rects, i);
final int height = STBRPRect.h.get(rects, i);
final STBRPRect slice = rects.slice(i);
if (slice.was_packed() != 0) {
final Identifier identifier = identifierList.get(slice.id());
final int xo = slice.x();
final int yo = slice.y();
final int width = slice.w();
final int height = slice.h();
regionMap.put(identifier, new TextureRegion(xo, yo, width, height));
gl.texSubImage2D(GL10C.TEXTURE_2D,
0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,86 +10,42 @@

package freeworld.client.render.world;

import freeworld.client.render.GameRenderer;
import freeworld.client.render.builder.DefaultVertexBuilder;
import freeworld.client.world.chunk.ClientChunk;
import freeworld.util.Direction;
import freeworld.world.chunk.Chunk;
import freeworld.world.chunk.ChunkPos;
import freeworld.world.entity.Entity;
import freeworld.world.entity.component.PositionComponent;
import org.jetbrains.annotations.NotNull;
import org.joml.Vector3d;

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

/**
* @author squid233
* @since 0.1.0
*/
public final class ChunkCompileTask implements Callable<ChunkVertexData> {
private final GameRenderer gameRenderer;
private final WorldRenderer worldRenderer;
private final ClientChunk chunk;
public final class ChunkCompileTask extends FutureTask<ChunkVertexData> implements Comparable<ChunkCompileTask> {
private final Entity player;
private final int x;
private final int y;
private final int z;

public ChunkCompileTask(GameRenderer gameRenderer, WorldRenderer worldRenderer, ClientChunk chunk) {
this.gameRenderer = gameRenderer;
this.worldRenderer = worldRenderer;
this.chunk = chunk;
public ChunkCompileTask(@NotNull Callable<ChunkVertexData> callable, Entity player, int x, int y, int z) {
super(callable);
this.player = player;
this.x = x;
this.y = y;
this.z = z;
}

@Override
public ChunkVertexData call() throws Exception {
final var pool = worldRenderer.vertexBuilderPool();
final DefaultVertexBuilder builder = pool.borrowObject();
try {
builder.reset();
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();
final int absNx = ChunkPos.relativeToAbsolute(cx, nx);
final int absNy = ChunkPos.relativeToAbsolute(cy, ny);
final int absNz = ChunkPos.relativeToAbsolute(cz, nz);
if ((chunk.isInBound(nx, ny, nz) &&
chunk.getBlockType(nx, ny, nz).air()) ||
(chunk.world().isBlockLoaded(absNx, absNy, absNz) &&
chunk.world().getBlockType(absNx, absNy, absNz).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.ofAuto();
final MemorySegment vertexDataSlice = builder.vertexDataSlice();
final MemorySegment indexDataSlice = builder.indexDataSlice();
final ChunkVertexData data = new ChunkVertexData(
builder.vertexLayout(),
builder.indexCount(),
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()
);
pool.returnObject(builder);
return data;
} catch (Exception e) {
pool.invalidateObject(builder);
throw e;
public int compareTo(@NotNull ChunkCompileTask o) {
if (player.hasComponent(PositionComponent.ID)) {
return Double.compare(distanceSquared(), o.distanceSquared());
}
return 0;
}

private double distanceSquared() {
final Vector3d value = player.position().value();
return value.distanceSquared(x, y, z);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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 freeworld.client.render.world;

import freeworld.client.render.GameRenderer;
import freeworld.client.render.builder.DefaultVertexBuilder;
import freeworld.client.world.chunk.ClientChunk;
import freeworld.util.Direction;
import freeworld.world.chunk.Chunk;
import 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 ChunkCompiler implements Callable<ChunkVertexData> {
private final GameRenderer gameRenderer;
private final WorldRenderer worldRenderer;
private final ClientChunk chunk;

public ChunkCompiler(GameRenderer gameRenderer, WorldRenderer worldRenderer, ClientChunk chunk) {
this.gameRenderer = gameRenderer;
this.worldRenderer = worldRenderer;
this.chunk = chunk;
}

@Override
public ChunkVertexData call() throws Exception {
final var pool = worldRenderer.vertexBuilderPool();
final DefaultVertexBuilder builder = pool.borrowObject();
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();
final int absNx = ChunkPos.relativeToAbsolute(cx, nx);
final int absNy = ChunkPos.relativeToAbsolute(cy, ny);
final int absNz = ChunkPos.relativeToAbsolute(cz, nz);
if ((chunk.isInBound(nx, ny, nz) &&
chunk.getBlockType(nx, ny, nz).air()) ||
(chunk.world().isBlockLoaded(absNx, absNy, absNz) &&
chunk.world().getBlockType(absNx, absNy, absNz).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.ofAuto();
final MemorySegment vertexDataSlice = builder.vertexDataSlice();
final MemorySegment indexDataSlice = builder.indexDataSlice();
final ChunkVertexData data = new ChunkVertexData(
builder.vertexLayout(),
builder.indexCount(),
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()
);
pool.returnObject(builder);
return data;
} catch (Exception e) {
pool.invalidateObject(builder);
throw e;
}
}
}
Loading

0 comments on commit 5d6979f

Please sign in to comment.