package ru.dbotthepony.kstarbound.client import org.lwjgl.opengl.GL46.* import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers import ru.dbotthepony.kstarbound.client.gl.vertex.quadZ import ru.dbotthepony.kstarbound.client.render.ILayeredRenderer import ru.dbotthepony.kstarbound.client.render.renderLayeredList import ru.dbotthepony.kstarbound.defs.parallax.ParallaxPrototype import ru.dbotthepony.kstarbound.math.encasingChunkPosAABB import ru.dbotthepony.kstarbound.util.DoubleEdgeProgression import ru.dbotthepony.kstarbound.world.* import ru.dbotthepony.kstarbound.world.entities.Entity import ru.dbotthepony.kvector.util2d.AABB class ClientWorld( val client: StarboundClient, seed: Long, widthInChunks: Int, ) : World(seed, widthInChunks) { init { physics.debugDraw = client.gl.box2dRenderer } override fun chunkFactory(pos: ChunkPos): ClientChunk { return ClientChunk( world = this, pos = pos, ) } var parallax: ParallaxPrototype? = null /** * Отрисовывает этот с обрезкой невидимой геометрии с точки зрения [size] в Starbound Units * * Все координаты "местности" сохраняются, поэтому, если отрисовывать слишком далеко от 0, 0 * то геометрия может начать искажаться из-за погрешности плавающей запятой */ fun render( size: AABB, isScreenspaceRender: Boolean = true ) { val parallax = parallax if (parallax != null) { client.gl.matrixStack.push() client.gl.matrixStack.translateWithMultiplication(y = parallax.verticalOrigin.toFloat() - 20f) client.gl.shaderVertexTexture.use() val builder = client.gl.flat2DTexturedQuads.small client.gl.activeTexture = 0 client.gl.shaderVertexTexture["_texture"] = 0 val centre = size.centre for (layer in parallax.layers) { client.gl.matrixStack.push() client.gl.matrixStack.translateWithMultiplication(x = layer.offset.x.toFloat() / PIXELS_IN_STARBOUND_UNITf, y = layer.offset.y.toFloat() / PIXELS_IN_STARBOUND_UNITf) client.gl.shaderVertexTexture.transform.set(client.gl.matrixStack.last) val texture = client.gl.loadNamedTextureSafe("/parallax/images/${layer.kind}/base/1.png") texture.bind() texture.textureMagFilter = GL_NEAREST texture.textureMinFilter = GL_NEAREST builder.begin() for (xPos in DoubleEdgeProgression()) { var x0 = xPos.toFloat() * texture.width / PIXELS_IN_STARBOUND_UNITf var x1 = (xPos + 1f) * texture.width / PIXELS_IN_STARBOUND_UNITf val diffx = layer.parallax.x * centre.x - centre.x val diffy = (layer.parallax.y * (centre.y + 20.0) - centre.y - 20.0).toFloat() / PIXELS_IN_STARBOUND_UNITf x0 += diffx.toFloat() / PIXELS_IN_STARBOUND_UNITf x1 += diffx.toFloat() / PIXELS_IN_STARBOUND_UNITf builder.quadZ(x0, diffy, x1, diffy + texture.height.toFloat() / PIXELS_IN_STARBOUND_UNITf, 1f, QuadTransformers.uv(0f, 1f, 1f, 0f)) /*if (x1 < size.mins.x) { break }*/ if (xPos < -40) { break } } builder.upload() builder.draw() client.gl.matrixStack.pop() } client.gl.matrixStack.pop() } val determineRenderers = ArrayList() client.lightRenderer.begin() for (chunk in collectPositionAware(size.encasingChunkPosAABB())) { val renderer = chunk.second.OneShotRenderer(chunk.first) determineRenderers.add(renderer) chunk.second.bake() //client.lightRenderer.addShadowGeometry(renderer) } renderLayeredList(client.gl.matrixStack, determineRenderers) /* for ((lightPosition, color) in listOf( (client.screenToWorld(client.mouseCoordinatesF)) to Color.RED, (client.screenToWorld(client.mouseCoordinatesF) + Vector2f(0.1f)) to Color.GREEN, (client.screenToWorld(client.mouseCoordinatesF) + Vector2f(-0.1f)) to Color.BLUE, )) { if (isScreenspaceRender) { val (x, y) = client.worldToScreen(lightPosition.x - 64f, lightPosition.y - 64f) val (x2, y2) = client.worldToScreen(lightPosition.x + 64f, lightPosition.y + 64f) client.pushScissorRect(x, client.viewportHeight - y, x2 - x, y - y2) } client.lightRenderer.renderSoftLight(lightPosition, color, radius = 64f, innerRadius = 2f) if (isScreenspaceRender) { client.popScissorRect() } } val old = client.gl.blendFunc client.gl.blendFunc = BlendFunc.MULTIPLY_BY_SRC client.gl.activeTexture = 0 client.gl.texture2D = client.lightRenderer.outputTexture client.gl.programs.viewTextureQuad.run() client.gl.blendFunc = old */ val pos = client.screenToWorld(client.mouseCoordinatesF).toDoubleVector() /*val lightsize = 16 val lightmap = floodLight( Vector2i(pos.x.roundToInt(), pos.y.roundToInt()), lightsize ) client.gl.quadWireframe { for (column in 0 until lightmap.columns) { for (row in 0 until lightmap.rows) { if (lightmap[column, row] > 0) { it.quad(pos.x.roundToInt() + column.toFloat() - lightsize, pos.y.roundToInt() + row.toFloat() - lightsize, pos.x.roundToInt() + column + 1f - lightsize, pos.y.roundToInt() + row + 1f - lightsize) } } } }*/ /* val rayFan = ArrayList() for (i in 0 .. 359) { rayFan.add(Vector2d(cos(i / 180.0 * PI), sin(i / 180.0 * PI))) } for (ray in rayFan) { val trace = castRayNaive(pos, ray, 16.0) client.gl.quadWireframe { for ((tpos, tile) in trace.traversedTiles) { if (tile.material != null) it.quad( tpos.x.toFloat(), tpos.y.toFloat(), tpos.x + 1f, tpos.y + 1f ) } } } */ //rayLightCircleNaive(pos, 48.0, falloffByTravel = 1.0, falloffByTile = 3.0) /* val result = rayLightCircleNaive(pos, 48.0, falloffByTravel = 1.0, falloffByTile = 3.0) val result2 = rayLightCircleNaive(pos + Vector2d(-8.0), 24.0, falloffByTravel = 1.0, falloffByTile = 3.0) val frame = GLFrameBuffer(client.gl) frame.attachTexture(client.viewportWidth, client.viewportHeight) frame.bind() client.gl.clearColor = Color.BLACK glClear(GL_COLOR_BUFFER_BIT) client.gl.blendFunc = BlendFunc.ADDITIVE*/ /*client.gl.quadColor { for (row in 0 until result.rows) { for (column in 0 until result.columns) { if (result[column, row] > 0.05) { val color = result[column, row].toFloat() * 1.5f it.quad( pos.x.roundToInt() - result.rows.toFloat() / 2f + row.toFloat(), pos.y.roundToInt() - result.columns.toFloat() / 2f + column.toFloat(), pos.x.roundToInt() - result.rows.toFloat() / 2f + row + 1f, pos.y.roundToInt() - result.columns.toFloat() / 2f + column + 1f ) { a, b -> a.pushVec4f(color, color, color, 1f) } } } } } client.gl.quadColor { for (row in 0 until result2.rows) { for (column in 0 until result2.columns) { if (result2[column, row] > 0.05) { val color = result2[column, row].toFloat() * 1.5f it.quad( pos.x.roundToInt() - 8f - result2.rows.toFloat() / 2f + row.toFloat(), pos.y.roundToInt() - result2.columns.toFloat() / 2f + column.toFloat(), pos.x.roundToInt() - 8f - result2.rows.toFloat() / 2f + row + 1f, pos.y.roundToInt() - result2.columns.toFloat() / 2f + column + 1f ) { a, b -> a.pushVec4f(color, 0f, 0f, 1f) } } } } }*/ /*val lightTextureWidth = (client.viewportWidth / PIXELS_IN_STARBOUND_UNIT).roundToInt() val lightTextureHeight = (client.viewportHeight / PIXELS_IN_STARBOUND_UNIT).roundToInt() val textureBuffer = ByteBuffer.allocateDirect(lightTextureWidth * lightTextureHeight * 3) textureBuffer.order(ByteOrder.LITTLE_ENDIAN) for (x in 0 until result.columns.coerceAtMost(lightTextureWidth)) { for (y in 0 until result.rows.coerceAtMost(lightTextureHeight)) { textureBuffer.position(x * 3 + y * lightTextureWidth * 3) if (result[x, y] > 0.05) { val color = result[x, y].toFloat() * 1.5f textureBuffer.put((color * 255).toInt().coerceAtMost(255).toByte()) textureBuffer.put((color * 255).toInt().coerceAtMost(255).toByte()) textureBuffer.put((color * 255).toInt().coerceAtMost(255).toByte()) } } }*/ //frame.unbind() // val texture = GLTexture2D(client.gl) // textureBuffer.position(0) // texture.upload(GL_RGB, lightTextureWidth, lightTextureHeight, GL_RGB, GL_UNSIGNED_BYTE, textureBuffer) // texture.textureMinFilter = GL_LINEAR // texture.textureMagFilter = GL_LINEAR // client.gl.blendFunc = BlendFunc.MULTIPLY_BY_SRC // client.gl.activeTexture = 0 // client.gl.texture2D = texture // client.gl.programs.viewTextureQuad.run() // client.gl.blendFunc = old //frame.close() //texture.close() physics.debugDraw() /*for (renderer in determineRenderers) { renderer.renderDebug() }*/ } override fun thinkInner(delta: Double) { val copy = arrayOfNulls(entities.size) var i = 0 for (ent in entities) { copy[i++] = ent } for (ent in copy) { ent!!.think(delta) } } }