use of io.xol.chunkstories.api.rendering.world.chunk.ChunkRenderable in project chunkstories by Hugobros3.
the class DebugInfoRenderer method getLoadedChunksVramFootprint.
@SuppressWarnings("unused")
private String getLoadedChunksVramFootprint() {
int nbChunks = 0;
long octelsTotal = 0;
ChunksIterator i = world.getAllLoadedChunks();
Chunk c;
while (i.hasNext()) {
c = i.next();
if (c == null)
continue;
if (c instanceof ChunkRenderable) {
ChunkRenderDataHolder chunkRenderData = ((ClientChunk) c).getChunkRenderData();
if (chunkRenderData != null) {
nbChunks++;
// octelsTotal += chunkRenderData.getVramUsage();
}
}
}
// , storing " + octelsTotal / 1024 / 1024 + "Mb of vertex data.";
return nbChunks + " chunks";
}
use of io.xol.chunkstories.api.rendering.world.chunk.ChunkRenderable in project chunkstories by Hugobros3.
the class DebugInfoRenderer method drawF3debugMenu.
public void drawF3debugMenu(RenderingInterface renderingInterface) {
CameraInterface camera = renderingInterface.getCamera();
Entity playerEntity = client.getPlayer().getControlledEntity();
/*int timeTook = Client.profiler.timeTook();
String debugInfo = Client.profiler.reset("gui").toString();
if (timeTook > 400)
System.out.println("Lengty frame, printing debug information : \n" + debugInfo);*/
// Memory usage
long total = Runtime.getRuntime().totalMemory();
long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
// By default use the camera position
int bx = ((int) camera.getCameraPosition().x());
int by = ((int) camera.getCameraPosition().y());
int bz = ((int) camera.getCameraPosition().z());
int lx = bx, ly = by, lz = bz;
// If the player can look use that
if (playerEntity != null && playerEntity instanceof EntityControllable) {
Location loc = ((EntityControllable) playerEntity).getBlockLookingAt(true);
if (loc != null) {
lx = (int) loc.x();
ly = (int) loc.y();
lz = (int) loc.z();
}
}
int raw_data = world.peekRaw(lx, ly, lz);
CellData cell = world.peekSafely(lx, ly, lz);
// System.out.println(VoxelFormat.id(raw_data));
int cx = bx / 32;
int cy = by / 32;
int cz = bz / 32;
int csh = world.getRegionsSummariesHolder().getHeightAtWorldCoordinates(bx, bz);
// Obtain the angle the player is facing
VoxelSide side = VoxelSide.TOP;
float angleX = -1;
if (playerEntity != null && playerEntity instanceof EntityLiving)
angleX = Math.round(((EntityLiving) playerEntity).getEntityRotationComponent().getHorizontalRotation());
double dx = Math.sin(angleX / 360 * 2.0 * Math.PI);
double dz = Math.cos(angleX / 360 * 2.0 * Math.PI);
if (Math.abs(dx) > Math.abs(dz)) {
if (dx > 0)
side = VoxelSide.RIGHT;
else
side = VoxelSide.LEFT;
} else {
if (dz > 0)
side = VoxelSide.FRONT;
else
side = VoxelSide.BACK;
}
// Count all the entities
int ec = 0;
IterableIterator<Entity> i = world.getAllLoadedEntities();
while (i.hasNext()) {
i.next();
ec++;
}
Chunk current = world.getChunk(cx, cy, cz);
int x_top = renderingInterface.getWindow().getHeight() - 16;
Font font = null;
font = renderingInterface.getFontRenderer().getFont("LiberationSans-Regular", 12);
if (font == null)
font = renderingInterface.getFontRenderer().getFont("LiberationSans-Regular", 12);
int lineHeight = font.getLineHeight();
int posx, posy;
String text;
posx = 8;
posy = x_top - posx;
text = GLCalls.getStatistics() + " Chunks in view : " + world.getWorldRenderer().getChunksRenderer().getChunksVisible() + " Entities " + ec + " Particles :" + ((ClientParticlesRenderer) world.getParticlesManager()).count() + " #FF0000Render FPS: " + Client.getInstance().getGameWindow().getFPS() + " avg: " + Math.floor(10000.0 / Client.getInstance().getGameWindow().getFPS()) / 10.0 + " #00FFFFSimulation FPS: " + world.getWorldRenderer().getWorld().getGameLogic().getSimulationFps();
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
posy -= lineHeight;
text = "RAM usage : " + used / 1024 / 1024 + " / " + total / 1024 / 1024 + " MB used, chunks loaded in ram: " + world.getRegionsHolder().countChunksWithData() + "/" + world.getRegionsHolder().countChunks() + " " + Math.floor(world.getRegionsHolder().countChunksWithData() * 4 * 32 * 32 * 32 / (1024L * 1024 / 100f)) / 100f + "MB used by chunks";
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
long totalVram = (renderingInterface.getTotalVramUsage()) / 1024 / 1024;
posy -= lineHeight;
text = "VRAM usage : " + totalVram + "MB as " + Texture2DGL.getTotalNumberOfTextureObjects() + " textures using " + Texture2DGL.getTotalVramUsage() / 1024 / 1024 + "MB + " + VertexBufferGL.getTotalNumberOfVerticesObjects() + " vbos using " + renderingInterface.getVertexDataVramUsage() / 1024 / 1024 + " MB";
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
posy -= lineHeight;
text = "Worker threads: " + world.getGameContext().tasks() + " - " + world.ioHandler.toString();
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
posy -= lineHeight;
text = "Position : x:" + bx + " y:" + by + " z:" + bz + " dir: " + angleX + " side: " + side + " #FF0000Block looking at#FFFFFF : pos: " + lx + ": " + ly + ": " + lz + " data: " + raw_data + " voxel_type: " + cell.getVoxel().getName() + " sl:" + cell.getSunlight() + " bl: " + cell.getBlocklight() + " meta:" + cell.getMetaData() + " csh:" + csh;
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
posy -= lineHeight;
text = "Current Summary : " + world.getRegionsSummariesHolder().getHeightmapChunkCoordinates(cx, cz);
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
posy -= lineHeight;
text = "Current Region : " + world.getRegionChunkCoordinates(cx, cy, cz);
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
if (current == null) {
posy -= lineHeight;
text = "Current chunk null";
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
} else if (current instanceof ChunkRenderable) {
ChunkRenderDataHolder chunkRenderData = ((ClientChunk) current).getChunkRenderData();
if (chunkRenderData != null) {
posy -= lineHeight;
text = "Current Chunk : " + current + " - " + chunkRenderData.toString();
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
} else {
posy -= lineHeight;
text = "Current Chunk : " + current + " - No rendering data";
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
}
}
if (playerEntity != null && playerEntity instanceof Entity) {
posy -= lineHeight;
text = "Controlled Entity : " + playerEntity;
renderingInterface.getFontRenderer().drawStringWithShadow(font, posx, posy, text, 1, 1, new Vector4f(1));
}
}
use of io.xol.chunkstories.api.rendering.world.chunk.ChunkRenderable in project chunkstories by Hugobros3.
the class WorldImplementation method redrawEverything.
@Override
public synchronized // TODO move to client
void redrawEverything() {
ChunksIterator i = this.getAllLoadedChunks();
Chunk c;
while (i.hasNext()) {
c = i.next();
if (c instanceof ChunkRenderable) {
ChunkRenderable c2 = (ChunkRenderable) c;
c2.lightBaker().requestLightningUpdate();
c2.meshUpdater().requestMeshUpdate();
}
}
}
use of io.xol.chunkstories.api.rendering.world.chunk.ChunkRenderable in project chunkstories by Hugobros3.
the class TaskBakeChunk method task.
@Override
protected boolean task(TaskExecutor taskExecutor) {
if (!(taskExecutor instanceof BakeChunkTaskExecutor))
throw new UnexecutableTaskException(this, "This class requires to be executed by a BakeChunkTaskExecutor");
this.cmd = ((BakeChunkTaskExecutor) taskExecutor).getBuffers();
if (chunk == null) {
throw new RuntimeException("Fuck off no");
}
Vector3dc camera = ((WorldClient) chunk.getWorld()).getWorldRenderer().getRenderingInterface().getCamera().getCameraPosition();
// Check we aren't too far from the camera, and thus that our request hasn't been yet cancelled
int vx = Math2.floor(camera.x() / 32);
int vy = Math2.floor(camera.y() / 32);
int vz = Math2.floor(camera.z() / 32);
int dx = LoopingMathHelper.moduloDistance(chunk.getChunkX(), vx, chunk.getWorld().getSizeInChunks());
int dz = LoopingMathHelper.moduloDistance(chunk.getChunkZ(), vz, chunk.getWorld().getSizeInChunks());
int dy = Math.abs(chunk.getChunkY() - vy);
int chunksViewDistance = (int) (world.getClient().getConfiguration().getIntOption("client.rendering.viewDistance") / 32);
if (dx > chunksViewDistance || dz > chunksViewDistance || dy > 2) {
// logger.info("unscheduled chunk mesh render task for it being too far to be rendered anyway");
return true;
}
// Require the chunk and nearby ones to be already loaded in the world
ChunkRenderable chunkWithinWorld = (ChunkRenderable) world.getChunk(chunk.getChunkX(), chunk.getChunkY(), chunk.getChunkZ());
if (chunkWithinWorld != null) {
// Require the chunks ARROUND it to be already loaded in the world
int nearChunks = 0;
if (world.isChunkLoaded(chunk.getChunkX() + 1, chunk.getChunkY(), chunk.getChunkZ()))
nearChunks++;
if (world.isChunkLoaded(chunk.getChunkX() - 1, chunk.getChunkY(), chunk.getChunkZ()))
nearChunks++;
if (world.isChunkLoaded(chunk.getChunkX(), chunk.getChunkY(), chunk.getChunkZ() + 1))
nearChunks++;
if (world.isChunkLoaded(chunk.getChunkX(), chunk.getChunkY(), chunk.getChunkZ() - 1))
nearChunks++;
if (world.isChunkLoaded(chunk.getChunkX(), chunk.getChunkY() + 1, chunk.getChunkZ()) || chunk.getChunkY() == world.getWorldInfo().getSize().heightInChunks - 1)
nearChunks++;
if (world.isChunkLoaded(chunk.getChunkX(), chunk.getChunkY() - 1, chunk.getChunkZ()) || chunk.getChunkY() == 0)
nearChunks++;
if (nearChunks != 6) {
// We wait until that's the case
return false;
}
} else {
// We wait until the chunk is loaded in the world ( or destroyed, then the task is cancelled )
return false;
}
// If the chunk has pending light updates, wait until THOSE are done
if (chunk.lightBaker.pendingUpdates() > 0) {
chunk.lightBaker.spawnUpdateTaskIfNeeded();
return false;
}
int updatesToConsider = chunk.chunkRenderData.unbakedUpdates.get();
// Don't waste time rendering void chunks m8
if (chunk.isAirChunk())
i = 32;
int cx = chunk.getChunkX();
int cy = chunk.getChunkY();
int cz = chunk.getChunkZ();
// Fill chunk caches ( saves much time avoiding slow-ass world->regions hashmap->chunk holder access for each vert )
for (int relx = -1; relx <= 1; relx++) for (int rely = -1; rely <= 1; rely++) for (int relz = -1; relz <= 1; relz++) {
CubicChunk chunk2 = (CubicChunk) world.getChunk(cx + relx, cy + rely, cz + relz);
if (chunk2 != null)
cmd.cache[((relx + 1) * 3 + (rely + 1)) * 3 + (relz + 1)] = chunk2.chunkVoxelData;
else
cmd.cache[((relx + 1) * 3 + (rely + 1)) * 3 + (relz + 1)] = null;
}
// Make sure we clear each sub-buffer type.
for (int i = 0; i < ChunkMeshDataSubtypes.VertexLayout.values().length; i++) {
for (int j = 0; j < ChunkMeshDataSubtypes.LodLevel.values().length; j++) {
for (int k = 0; k < ChunkMeshDataSubtypes.ShadingType.values().length; k++) {
cmd.byteBuffers[i][j][k].clear();
}
}
}
// Creates wrapper/interfaces for all the elements
ChunkRenderer chunkRendererOutput = new ChunkRenderer() {
@Override
public VoxelBakerHighPoly getHighpolyBakerFor(LodLevel lodLevel, ShadingType renderPass) {
return (VoxelBakerHighPoly) cmd.byteBuffersWrappers[VertexLayout.INTRICATE.ordinal()][lodLevel.ordinal()][renderPass.ordinal()];
}
@Override
public VoxelBakerCubic getLowpolyBakerFor(LodLevel lodLevel, ShadingType renderPass) {
return (VoxelBakerCubic) cmd.byteBuffersWrappers[VertexLayout.WHOLE_BLOCKS.ordinal()][lodLevel.ordinal()][renderPass.ordinal()];
}
};
ChunkBakerRenderContext chunkRenderingContext = new ChunkBakerRenderContext(chunk, cx, cy, cz);
bakedBlockId = -1;
Map<Voxel, DynamicallyRenderedVoxelType> dynamicVoxels = new HashMap<>();
BakeChunkScratchCell cell = new BakeChunkScratchCell(world);
// Render the fucking thing!
for (i = 0; i < 32; i++) {
for (j = 0; j < 32; j++) {
for (k = 0; k < 32; k++) {
peek(i, k, j, cell);
if (cell.voxel.isAir())
continue;
// Fill near-blocks info
// chunkRenderingContext.prepareVoxelLight(); // lol nope
VoxelRenderer voxelRenderer = cell.getVoxelRenderer();
if (voxelRenderer == null)
voxelRenderer = world.getContent().voxels().getDefaultVoxelRenderer();
// Run the VoxelRenderer
voxelRenderer.bakeInto(chunkRendererOutput, chunkRenderingContext, chunk, cell);
// We handle voxels with a dynamic renderer here too - we just add them to a list !
if (voxelRenderer instanceof VoxelDynamicRenderer) {
DynamicallyRenderedVoxelType drvt = dynamicVoxels.get(cell.voxel);
if (drvt == null) {
drvt = new DynamicallyRenderedVoxelType((VoxelDynamicRenderer) voxelRenderer, cell.voxel);
dynamicVoxels.put(cell.voxel, drvt);
}
drvt.indexes.add(i * 1024 + k * 32 + j);
}
bakedBlockId++;
}
}
}
// Parse output neatly
int[][][] sizes = new int[ChunkMeshDataSubtypes.VertexLayout.values().length][ChunkMeshDataSubtypes.LodLevel.values().length][ChunkMeshDataSubtypes.ShadingType.values().length];
;
int[][][] offsets = new int[ChunkMeshDataSubtypes.VertexLayout.values().length][ChunkMeshDataSubtypes.LodLevel.values().length][ChunkMeshDataSubtypes.ShadingType.values().length];
;
int currentOffset = 0;
// Compute total size to create final bytebuffer
int sizeInBytes = 0;
for (VertexLayout vertexLayout : VertexLayout.values()) for (LodLevel lodLevel : LodLevel.values()) for (ShadingType renderPass : ShadingType.values()) {
int vertexLayoutIndex = vertexLayout.ordinal();
int lodLevelIndex = lodLevel.ordinal();
int renderPassIndex = renderPass.ordinal();
final ByteBuffer relevantByteBuffer = cmd.byteBuffers[vertexLayoutIndex][lodLevelIndex][renderPassIndex];
// / vertexLayout.bytesPerVertex;
sizeInBytes += relevantByteBuffer.position();
}
ByteBuffer finalData = MemoryUtil.memAlloc(sizeInBytes);
MemFreeByteBuffer wrappedBuffer = new MemFreeByteBuffer(finalData);
// For EACH section, make offset and shite
for (VertexLayout vertexLayout : VertexLayout.values()) for (LodLevel lodLevel : LodLevel.values()) for (ShadingType renderPass : ShadingType.values()) {
int vertexLayoutIndex = vertexLayout.ordinal();
int lodLevelIndex = lodLevel.ordinal();
int renderPassIndex = renderPass.ordinal();
// Else it gets really long for no reason
final ByteBuffer relevantByteBuffer = cmd.byteBuffers[vertexLayoutIndex][lodLevelIndex][renderPassIndex];
offsets[vertexLayoutIndex][lodLevelIndex][renderPassIndex] = currentOffset;
sizes[vertexLayoutIndex][lodLevelIndex][renderPassIndex] = relevantByteBuffer.position() / vertexLayout.bytesPerVertex;
// Move the offset accordingly
currentOffset += relevantByteBuffer.position();
// Limit the temporary byte buffer and fill the main buffer with it
relevantByteBuffer.limit(relevantByteBuffer.position());
relevantByteBuffer.position(0);
finalData.put(relevantByteBuffer);
}
finalData.flip();
ChunkMeshDataSections newRenderData = new ChunkMeshDataSections(wrappedBuffer, sizes, offsets);
DynamicallyRenderedVoxelType[] bakedDrvt = new DynamicallyRenderedVoxelType[dynamicVoxels.size()];
Iterator<DynamicallyRenderedVoxelType> i = dynamicVoxels.values().iterator();
for (int j = 0; j < dynamicVoxels.size(); j++) {
if (i.hasNext())
bakedDrvt[j] = i.next();
else {
logger.error("while baking dynamicVoxelTypes array the iterator returned less than dynamicVoxels.size() elements");
logger.error("cancelling");
bakedDrvt = null;
break;
}
}
newRenderData.dynamicVoxelTypes = bakedDrvt;
chunk.getChunkRenderData().setData(newRenderData);
chunk.chunkRenderData.unbakedUpdates.addAndGet(-updatesToConsider);
return true;
}
use of io.xol.chunkstories.api.rendering.world.chunk.ChunkRenderable in project chunkstories by Hugobros3.
the class CubicChunk method pokeInternal.
/**
* The 'core' of the core, this private function is responsible for placing and
* keeping everyone up to snuff on block modifications. It all comes back to this really.
*/
private ActualChunkVoxelContext pokeInternal(final int worldX, final int worldY, final int worldZ, Voxel newVoxel, final int sunlight, final int blocklight, final int metadata, int raw_data, final boolean use_raw_data, final boolean update, final boolean return_context, final WorldModificationCause cause) {
int x = sanitizeCoordinate(worldX);
int y = sanitizeCoordinate(worldY);
int z = sanitizeCoordinate(worldZ);
ActualChunkVoxelContext cell_pre = peek(x, y, z);
Voxel formerVoxel = cell_pre.getVoxel();
assert formerVoxel != null;
FreshFutureCell future = new FreshFutureCell(cell_pre);
if (use_raw_data) {
// We need this for voxel placement logic
newVoxel = world.getContentTranslator().getVoxelForId(VoxelFormat.id(raw_data));
// Build the future from parsing the raw data
future.setVoxel(newVoxel);
future.setSunlight(VoxelFormat.sunlight(raw_data));
future.setBlocklight(VoxelFormat.blocklight(raw_data));
future.setMetaData(VoxelFormat.meta(raw_data));
} else {
// Build the raw data from the set parameters by editing the in-place data
// (because we allow only editing some aspects of the cell data)
raw_data = cell_pre.getData();
if (newVoxel != null) {
raw_data = VoxelFormat.changeId(raw_data, world.getContentTranslator().getIdForVoxel(newVoxel));
future.setVoxel(newVoxel);
}
if (sunlight >= 0) {
raw_data = VoxelFormat.changeSunlight(raw_data, sunlight);
future.setSunlight(sunlight);
}
if (blocklight >= 0) {
raw_data = VoxelFormat.changeBlocklight(raw_data, blocklight);
future.setBlocklight(blocklight);
}
if (metadata >= 0) {
raw_data = VoxelFormat.changeMeta(raw_data, metadata);
future.setMetaData(metadata);
}
}
try {
if (newVoxel == null || formerVoxel.equals(newVoxel)) {
formerVoxel.onModification(cell_pre, future, cause);
} else {
formerVoxel.onRemove(cell_pre, cause);
newVoxel.onPlace(future, cause);
}
} catch (WorldException e) {
// Abort !
if (return_context)
return cell_pre;
else
return null;
}
// Allocate if it makes sense
if (chunkVoxelData == null)
chunkVoxelData = atomicalyCreateInternalData();
chunkVoxelData[x * 32 * 32 + y * 32 + z] = raw_data;
if (newVoxel != null && !formerVoxel.equals(newVoxel))
newVoxel.whenPlaced(future);
// Update lightning
if (update)
lightBaker.computeLightSpread(x, y, z, cell_pre.raw_data, raw_data);
// Increment the modifications counter
compr_uncomittedBlockModifications.incrementAndGet();
// Don't spam the thread creation spawn
occlusion.unbakedUpdates.incrementAndGet();
// Update related summary
if (update)
world.getRegionsSummariesHolder().updateOnBlockPlaced(x, y, z, future);
// Mark the nearby chunks to be re-rendered
if (update) {
int sx = chunkX;
int ex = sx;
int sy = chunkY;
int ey = sy;
int sz = chunkZ;
int ez = sz;
if (x == 0)
sx--;
else if (x == 31)
ex++;
if (y == 0)
sy--;
else if (y == 31)
ey++;
if (z == 0)
sz--;
else if (z == 31)
ez++;
for (int ix = sx; ix <= ex; ix++) for (int iy = sy; iy <= ey; iy++) for (int iz = sz; iz <= ez; iz++) {
Chunk chunk = world.getChunk(ix, iy, iz);
if (chunk != null && chunk instanceof ChunkRenderable)
((ChunkRenderable) chunk).meshUpdater().requestMeshUpdate();
}
}
// If this is a 'master' world, notify remote users of the change !
if (update && world instanceof WorldMaster && !(world instanceof WorldTool)) {
PacketVoxelUpdate packet = new PacketVoxelUpdate(new ActualChunkVoxelContext(chunkX * 32 + x, chunkY * 32 + y, chunkZ * 32 + z, raw_data));
Iterator<WorldUser> pi = this.chunkHolder.users.iterator();
while (pi.hasNext()) {
WorldUser user = pi.next();
if (!(user instanceof RemotePlayer))
continue;
RemotePlayer player = (RemotePlayer) user;
Entity clientEntity = player.getControlledEntity();
if (clientEntity == null)
// Ignore clients that aren't playing
continue;
player.pushPacket(packet);
}
}
if (return_context)
return new ActualChunkVoxelContext(chunkX * 32 + x, chunkY * 32 + y, chunkZ * 32 + z, raw_data);
else
return null;
}
Aggregations