Merge branch 'master' into hud

# Conflicts:
#	src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt
#	src/main/java/de/bixilon/minosoft/gui/rendering/Renderer.kt
#	src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt
#	src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt
#	src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/Particle.kt
#	src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/norender/NoRenderParticle.kt
#	src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/TextureParticle.kt
#	src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/advanced/AdvancedTextureParticle.kt
This commit is contained in:
Bixilon 2021-11-01 23:39:04 +01:00
commit 84feeefd9e
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
35 changed files with 600 additions and 222 deletions

View File

@ -27,6 +27,12 @@ class RGBColor(val rgba: Int) : ChatCode, TextFormattable {
constructor(red: Double, green: Double, blue: Double, alpha: Double = 1.0) : this(red.toFloat(), green.toFloat(), blue.toFloat(), alpha.toFloat())
val argb: Int
get() = (alpha shl 24) or (red shl 16) or (green shl 8) or blue
val abgr: Int
get() = (alpha shl 24) or (blue shl 16) or (green shl 8) or red
val alpha: @IntRange(from = 0L, to = 255L) Int
get() = rgba and 0xFF

View File

@ -29,6 +29,7 @@ import de.bixilon.minosoft.terminal.RunConfiguration
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.ShutdownManager
import de.bixilon.minosoft.util.task.pool.DefaultThreadPool
import javafx.application.Platform
import javafx.fxml.FXML
import javafx.scene.control.Label
import javafx.scene.image.ImageView
@ -139,7 +140,7 @@ class MainErosController : JavaFXWindowController() {
try {
account.verify()
} catch (exception: Throwable) {
activity = ErosMainActivities.ACCOUNT
Platform.runLater { activity = ErosMainActivities.ACCOUNT }
// ToDo: Show account window and do account error handling
}
onSuccess(account)

View File

@ -39,6 +39,7 @@ import de.bixilon.minosoft.gui.rendering.stats.AbstractRenderStats
import de.bixilon.minosoft.gui.rendering.system.base.IntegratedBufferTypes
import de.bixilon.minosoft.gui.rendering.system.base.PolygonModes
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.RenderPhases
import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem
import de.bixilon.minosoft.gui.rendering.system.window.BaseWindow
import de.bixilon.minosoft.gui.rendering.system.window.GLFWWindow
@ -309,13 +310,17 @@ class RenderWindow(
val rendererList = rendererMap.values
for (renderer in rendererList) {
renderer.update()
renderer.prepareDraw()
}
for (renderer in rendererList) {
renderer.draw()
}
for (renderer in rendererList) {
renderer.postDraw()
for (phase in RenderPhases.VALUES) {
if (!phase.type.java.isAssignableFrom(renderer::class.java)) {
continue
}
phase.invokeSetup(renderer)
phase.invokeDraw(renderer)
}
}
renderSystem.reset() // Reset to enable depth mask, etc again

View File

@ -13,15 +13,15 @@
package de.bixilon.minosoft.gui.rendering
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
interface Renderer {
val renderWindow: RenderWindow
val renderSystem: RenderSystem
fun init() = Unit
fun postInit() = Unit
fun update() = Unit
fun draw() = Unit
fun postDraw() = Unit
fun prepareDraw() = Unit
}

View File

@ -35,6 +35,10 @@ import de.bixilon.minosoft.gui.rendering.block.renderable.BlockLikeRenderContext
import de.bixilon.minosoft.gui.rendering.input.camera.Frustum
import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.RenderingStateChangeEvent
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable
import de.bixilon.minosoft.gui.rendering.system.base.phases.TranslucentDrawable
import de.bixilon.minosoft.gui.rendering.system.base.phases.TransparentDrawable
import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
@ -59,12 +63,14 @@ import glm_.vec3.Vec3i
class WorldRenderer(
private val connection: PlayConnection,
val renderWindow: RenderWindow,
) : Renderer {
override val renderWindow: RenderWindow,
) : Renderer, OpaqueDrawable, TransparentDrawable, TranslucentDrawable {
override val renderSystem: RenderSystem = renderWindow.renderSystem
private val world: World = connection.world
private val waterBlock = connection.registries.blockRegistry[ResourceLocation("minecraft:water")].nullCast<FluidBlock>()
private val chunkShader: Shader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "world"))
private val chunkShader: Shader = renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "world"))
private val transparentShader: Shader = renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "world"))
private val lightMap = LightMap(connection)
val allChunkSections: SynchronizedMap<Vec2i, SynchronizedMap<Int, ChunkSectionMeshCollection>> = synchronizedMapOf()
@ -121,8 +127,12 @@ class WorldRenderer(
}
}
if (meshCollection.transparentSectionArrayMesh!!.data.isEmpty) {
meshCollection.transparentSectionArrayMesh = null
if (meshCollection.translucentMesh!!.data.isEmpty) {
meshCollection.translucentMesh = null
}
if (meshCollection.transparentMesh!!.data.isEmpty) {
meshCollection.transparentMesh = null
}
return meshCollection
}
@ -187,13 +197,18 @@ class WorldRenderer(
}
override fun postInit() {
chunkShader.load()
lightMap.init()
chunkShader.load()
renderWindow.textureManager.staticTextures.use(chunkShader)
renderWindow.textureManager.staticTextures.animator.use(chunkShader)
lightMap.use(chunkShader)
transparentShader.defines[Shader.TRANSPARENT_DEFINE] = ""
transparentShader.load()
renderWindow.textureManager.staticTextures.use(transparentShader)
renderWindow.textureManager.staticTextures.animator.use(transparentShader)
lightMap.use(transparentShader)
for (blockState in allBlocks!!) {
for (model in blockState.renderers) {
model.postInit()
@ -202,29 +217,46 @@ class WorldRenderer(
allBlocks = null
}
override fun update() {
override fun prepareDraw() {
lastVisibleChunks = visibleChunks.toSynchronizedMap()
lightMap.update()
}
override fun draw() {
renderWindow.renderSystem.reset()
override fun setupOpaque() {
super.setupOpaque()
chunkShader.use()
}
override fun drawOpaque() {
for (map in lastVisibleChunks.values) {
for (mesh in map.values) {
mesh.opaqueSectionArrayMesh.draw()
mesh.opaqueMesh.draw()
}
}
}
override fun postDraw() {
renderWindow.renderSystem.reset(depthMask = false)
chunkShader.use()
override fun setupTransparent() {
super.setupTransparent()
transparentShader.use()
}
override fun drawTransparent() {
for (map in lastVisibleChunks.values) {
for (mesh in map.values) {
mesh.transparentSectionArrayMesh?.draw()
mesh.transparentMesh?.draw()
}
}
}
override fun setupTranslucent() {
super.setupTranslucent()
chunkShader.use()
}
override fun drawTranslucent() {
for (map in lastVisibleChunks.values) {
for (mesh in map.values) {
mesh.translucentMesh?.draw()
}
}
}
@ -337,23 +369,33 @@ class WorldRenderer(
val sectionMap = allChunkSections.getOrPut(chunkPosition) { synchronizedMapOf() }
sectionMap[index]?.let {
it.opaqueSectionArrayMesh.unload()
it.opaqueMesh.unload()
meshes--
triangles -= it.opaqueSectionArrayMesh.vertices
triangles -= it.opaqueMesh.vertices
it.transparentSectionArrayMesh?.let {
it.translucentMesh?.let {
it.unload()
meshes--
triangles -= it.vertices
}
it.transparentMesh?.let {
it.unload()
meshes--
triangles -= it.vertices
}
}
meshCollection.opaqueSectionArrayMesh.let {
meshCollection.opaqueMesh.let {
it.load()
meshes++
triangles += it.vertices
}
meshCollection.transparentSectionArrayMesh?.let {
meshCollection.translucentMesh?.let {
it.load()
meshes++
triangles += it.vertices
}
meshCollection.transparentMesh?.let {
it.load()
meshes++
triangles += it.vertices
@ -418,12 +460,17 @@ class WorldRenderer(
private fun unloadMeshes(meshes: Collection<ChunkSectionMeshCollection>) {
renderWindow.assertOnRenderThread()
for (meshCollection in meshes) {
meshCollection.opaqueSectionArrayMesh.let {
meshCollection.opaqueMesh.let {
it.unload()
this.meshes--
triangles -= it.vertices
}
meshCollection.transparentSectionArrayMesh?.let {
meshCollection.translucentMesh?.let {
it.unload()
this.meshes--
triangles -= it.vertices
}
meshCollection.transparentMesh?.let {
it.unload()
this.meshes--
triangles -= it.vertices

View File

@ -19,6 +19,8 @@ import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable
import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
@ -27,13 +29,14 @@ import glm_.vec3.Vec3
class ChunkBorderRenderer(
val connection: PlayConnection,
val renderWindow: RenderWindow,
) : Renderer {
override val renderWindow: RenderWindow,
) : Renderer, OpaqueDrawable {
override val renderSystem: RenderSystem = renderWindow.renderSystem
private var lastChunkPosition: Vec2i? = null
private var lastMesh: LineMesh? = null
private fun prepare() {
override fun prepareDraw() {
val chunkPosition = renderWindow.connection.player.positionInfo.chunkPosition
if (chunkPosition == lastChunkPosition && lastMesh != null) {
return
@ -109,11 +112,13 @@ class ChunkBorderRenderer(
this.lastChunkPosition = chunkPosition
}
override fun draw() {
prepare()
val mesh = lastMesh ?: return
override fun setupOpaque() {
renderWindow.renderSystem.reset(faceCulling = false)
renderWindow.shaderManager.genericColorShader.use()
}
override fun drawOpaque() {
val mesh = lastMesh ?: return
mesh.draw()
}

View File

@ -17,8 +17,9 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
class ChunkSectionMeshCollection(
renderWindow: RenderWindow,
val opaqueSectionArrayMesh: ChunkSectionArrayMesh = ChunkSectionArrayMesh(renderWindow),
var transparentSectionArrayMesh: ChunkSectionArrayMesh? = ChunkSectionArrayMesh(renderWindow),
val opaqueMesh: ChunkSectionArrayMesh = ChunkSectionArrayMesh(renderWindow),
var translucentMesh: ChunkSectionArrayMesh? = ChunkSectionArrayMesh(renderWindow),
var transparentMesh: ChunkSectionArrayMesh? = ChunkSectionArrayMesh(renderWindow),
) {
var lowestBlockHeight = 0
var highestBlockHeight = 0

View File

@ -23,6 +23,7 @@ import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.system.base.DepthFunctions
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d
import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh
@ -32,13 +33,15 @@ import glm_.vec3.Vec3i
class BlockOutlineRenderer(
val connection: PlayConnection,
val renderWindow: RenderWindow,
override val renderWindow: RenderWindow,
) : Renderer {
override val renderSystem: RenderSystem = renderWindow.renderSystem
private var currentOutlinePosition: Vec3i? = null
private var currentOutlineBlockState: BlockState? = null
private var currentMesh: LineMesh? = null
private fun drawMesh() {
val currentMesh = currentMesh ?: return
renderWindow.renderSystem.reset(faceCulling = false)
@ -47,6 +50,7 @@ class BlockOutlineRenderer(
}
renderWindow.shaderManager.genericColorShader.use()
currentMesh.draw()
draw()
}
private fun unload() {
@ -57,7 +61,8 @@ class BlockOutlineRenderer(
this.currentOutlineBlockState = null
}
override fun draw() {
@Deprecated("TODO")
private fun draw() {
val raycastHit = renderWindow.inputHandler.camera.target.nullCast<BlockRaycastHit>()
var currentMesh = currentMesh

View File

@ -168,11 +168,11 @@ class ElementRenderer(
val DRAW_OFFSET = Vec3(+0.5f, +0.5f, +0.5f)
fun getMesh(meshCollection: ChunkSectionMeshCollection, textureTransparencies: TextureTransparencies): ChunkSectionArrayMesh {
return if (textureTransparencies == TextureTransparencies.TRANSLUCENT) {
meshCollection.transparentSectionArrayMesh!!
} else {
meshCollection.opaqueSectionArrayMesh
fun getMesh(meshCollection: ChunkSectionMeshCollection, transparency: TextureTransparencies): ChunkSectionArrayMesh {
return when (transparency) {
TextureTransparencies.OPAQUE -> meshCollection.opaqueMesh
TextureTransparencies.TRANSPARENT -> meshCollection.transparentMesh!!
TextureTransparencies.TRANSLUCENT -> meshCollection.translucentMesh!!
}
}
}

View File

@ -22,6 +22,8 @@ import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder
import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent
import de.bixilon.minosoft.gui.rendering.system.base.DepthFunctions
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
import de.bixilon.minosoft.modding.event.events.EntityDestroyEvent
import de.bixilon.minosoft.modding.event.events.EntitySpawnEvent
@ -33,8 +35,9 @@ import de.bixilon.minosoft.util.collections.SynchronizedMap
class EntityHitBoxRenderer(
val connection: PlayConnection,
val renderWindow: RenderWindow,
) : Renderer {
override val renderWindow: RenderWindow,
) : Renderer, OpaqueDrawable {
override val renderSystem: RenderSystem = renderWindow.renderSystem
private val meshes: SynchronizedMap<Entity, EntityHitBoxMesh> = synchronizedMapOf()
@ -102,13 +105,15 @@ class EntityHitBoxRenderer(
}
}
override fun draw() {
renderWindow.renderSystem.reset(faceCulling = false)
override fun setupOpaque() {
renderWindow.renderSystem.reset(faceCulling = false) // ToDo?
if (Minosoft.config.config.game.entities.hitBox.disableZBuffer) {
renderWindow.renderSystem.depth = DepthFunctions.ALWAYS
}
renderWindow.shaderManager.genericColorShader.use()
}
override fun drawOpaque() {
fun draw(mesh: EntityHitBoxMesh?) {
mesh ?: return

View File

@ -39,6 +39,8 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.elements.title.TitleHUDElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.system.base.IntegratedBufferTypes
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.OtherDrawable
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
@ -53,8 +55,9 @@ import glm_.vec2.Vec2i
class HUDRenderer(
val connection: PlayConnection,
val renderWindow: RenderWindow,
) : Renderer {
override val renderWindow: RenderWindow,
) : Renderer, OtherDrawable {
override val renderSystem: RenderSystem = renderWindow.renderSystem
val shader = renderWindow.renderSystem.createShader("minosoft:hud".toResourceLocation())
private lateinit var mesh: GUIMesh
var scaledSize: Vec2i = renderWindow.window.size
@ -138,7 +141,9 @@ class HUDRenderer(
}
}
override fun postDraw() {
override fun setupOther() = Unit
override fun drawOther() {
if (!enabled) {
return
}

View File

@ -20,6 +20,9 @@ import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent
import de.bixilon.minosoft.gui.rendering.particle.types.Particle
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.TranslucentDrawable
import de.bixilon.minosoft.gui.rendering.system.base.phases.TransparentDrawable
import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionStateChangeEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
@ -37,11 +40,15 @@ import glm_.vec3.Vec3
class ParticleRenderer(
private val connection: PlayConnection,
val renderWindow: RenderWindow,
) : Renderer {
private val particleShader: Shader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"))
private var particleMesh = ParticleMesh(renderWindow, 0)
private var transparentParticleMesh = ParticleMesh(renderWindow, 0)
override val renderWindow: RenderWindow,
) : Renderer, TransparentDrawable, TranslucentDrawable {
override val renderSystem: RenderSystem = renderWindow.renderSystem
private val transparentShader: Shader = renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"))
private val translucentShader: Shader = renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"))
// There is no opaque mesh because it is simply not needed (every particle has transparency)
private var transparentMesh = ParticleMesh(renderWindow, 0)
private var translucentMesh = ParticleMesh(renderWindow, 0)
private var particles: MutableSet<Particle> = mutableSetOf()
private var particleQueue: MutableSet<Particle> = mutableSetOf()
@ -55,13 +62,22 @@ class ParticleRenderer(
override fun init() {
connection.registerEvent(CallbackEventInvoker.of<CameraMatrixChangeEvent> {
renderWindow.queue += {
particleShader.use().setMat4("uViewProjectionMatrix", Mat4(it.viewProjectionMatrix))
particleShader.use().setVec3("uCameraRight", Vec3(it.viewMatrix[0][0], it.viewMatrix[1][0], it.viewMatrix[2][0]))
particleShader.use().setVec3("uCameraUp", Vec3(it.viewMatrix[0][1], it.viewMatrix[1][1], it.viewMatrix[2][1]))
fun applyToShader(shader: Shader) {
shader.apply {
use()
setMat4("uViewProjectionMatrix", Mat4(it.viewProjectionMatrix))
setVec3("uCameraRight", Vec3(it.viewMatrix[0][0], it.viewMatrix[1][0], it.viewMatrix[2][0]))
setVec3("uCameraUp", Vec3(it.viewMatrix[0][1], it.viewMatrix[1][1], it.viewMatrix[2][1]))
}
}
applyToShader(transparentShader)
applyToShader(translucentShader)
}
})
particleMesh.load()
transparentParticleMesh.load()
transparentMesh.load()
translucentMesh.load()
connection.registries.particleTypeRegistry.forEachItem {
for (resourceLocation in it.textures) {
renderWindow.textureManager.staticTextures.createTexture(resourceLocation)
@ -72,9 +88,15 @@ class ParticleRenderer(
}
override fun postInit() {
particleShader.load()
renderWindow.textureManager.staticTextures.use(particleShader)
renderWindow.textureManager.staticTextures.animator.use(particleShader)
transparentShader.defines[Shader.TRANSPARENT_DEFINE] = ""
transparentShader.load()
renderWindow.textureManager.staticTextures.use(transparentShader)
renderWindow.textureManager.staticTextures.animator.use(transparentShader)
translucentShader.load()
renderWindow.textureManager.staticTextures.use(translucentShader)
renderWindow.textureManager.staticTextures.animator.use(translucentShader)
connection.world.particleRenderer = this
@ -109,15 +131,16 @@ class ParticleRenderer(
add(particle)
}
override fun update() {
particleMesh.unload()
transparentParticleMesh.unload()
override fun prepareDraw() {
transparentMesh.unload()
translucentMesh.unload()
val toRemove: MutableSet<Particle> = mutableSetOf()
particleMesh = ParticleMesh(renderWindow, particles.size + particleQueue.size)
transparentParticleMesh = ParticleMesh(renderWindow, 500)
transparentMesh = ParticleMesh(renderWindow, 500)
translucentMesh = ParticleMesh(renderWindow, particles.size + particleQueue.size)
synchronized(particles) {
synchronized(particleQueue) {
@ -131,27 +154,34 @@ class ParticleRenderer(
toRemove += particle
continue
}
particle.addVertex(transparentParticleMesh, particleMesh, time)
particle.addVertex(transparentMesh, translucentMesh, time)
}
particles -= toRemove
}
particleMesh.load()
transparentParticleMesh.load()
transparentMesh.load()
translucentMesh.load()
}
override fun draw() {
renderWindow.renderSystem.reset()
particleShader.use()
particleMesh.draw()
override fun setupTransparent() {
super.setupTransparent()
transparentShader.use()
}
override fun postDraw() {
renderWindow.renderSystem.reset(depthMask = false)
particleShader.use()
transparentParticleMesh.draw()
override fun drawTransparent() {
transparentMesh.draw()
}
override fun setupTranslucent() {
super.setupTranslucent()
translucentShader.use()
}
override fun drawTranslucent() {
translucentMesh.draw()
}
companion object : RendererBuilder<ParticleRenderer> {
override val RESOURCE_LOCATION = ResourceLocation("minosoft:particle")

View File

@ -190,7 +190,7 @@ abstract class Particle(
}
}
abstract fun addVertex(transparentMesh: ParticleMesh, particleMesh: ParticleMesh, time: Long)
abstract fun addVertex(transparentMesh: ParticleMesh, particleMesh: ParticleMesh, time:Long)
companion object {
private const val MAGIC_VELOCITY_CONSTANT = 0.4

View File

@ -25,13 +25,11 @@ abstract class TextureParticle(connection: PlayConnection, position: Vec3d, velo
abstract val texture: AbstractTexture?
override fun addVertex(transparentMesh: ParticleMesh, particleMesh: ParticleMesh, time: Long) {
texture?.let {
if (it.transparency == TextureTransparencies.TRANSLUCENT || color.alpha != 255) {
transparentMesh
} else {
particleMesh
}.addVertex(getCameraPosition(time), scale, it, color)
}
override fun addVertex(transparentMesh: ParticleMesh, translucentMesh: ParticleMesh, time:Long) {
val texture = texture ?: return
when {
texture.transparency == TextureTransparencies.TRANSLUCENT || color.alpha != 255 -> translucentMesh
else -> transparentMesh
}.addVertex(getCameraPosition(time), scale, texture, color)
}
}

View File

@ -25,13 +25,11 @@ abstract class AdvancedTextureParticle(connection: PlayConnection, position: Vec
var minUV: Vec2 = Vec2(0.0f, 0.0f)
var maxUV: Vec2 = Vec2(1.0f, 1.0f)
override fun addVertex(transparentMesh: ParticleMesh, particleMesh: ParticleMesh, time: Long) {
texture?.let {
if (it.transparency == TextureTransparencies.TRANSLUCENT || color.alpha != 255) {
transparentMesh
} else {
particleMesh
}.addVertex(getCameraPosition(time), scale, it, color, minUV, maxUV)
}
override fun addVertex(transparentMesh: ParticleMesh, translucentMesh: ParticleMesh, time:Long) {
val texture = texture ?: return
when {
texture.transparency == TextureTransparencies.TRANSLUCENT || color.alpha != 255 -> translucentMesh
else -> transparentMesh
}.addVertex(getCameraPosition(time), scale, texture, color, minUV, maxUV)
}
}

View File

@ -24,6 +24,8 @@ import de.bixilon.minosoft.gui.rendering.RendererBuilder
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent
import de.bixilon.minosoft.gui.rendering.system.base.BlendingFunctions
import de.bixilon.minosoft.gui.rendering.system.base.DepthFunctions
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.CustomDrawable
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
import de.bixilon.minosoft.gui.rendering.util.mesh.SimpleTextureMesh
@ -39,10 +41,11 @@ import glm_.vec3.Vec3d
class SkyRenderer(
private val connection: PlayConnection,
val renderWindow: RenderWindow,
) : Renderer {
private val skyboxShader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "sky/skybox"))
private val skySunShader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "sky/sun"))
override val renderWindow: RenderWindow,
) : Renderer, CustomDrawable {
override val renderSystem: RenderSystem = renderWindow.renderSystem
private val skyboxShader = renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "sky/skybox"))
private val skySunShader = renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "sky/sun"))
private val skyboxMesh = SkyboxMesh(renderWindow)
private var skySunMesh = SimpleTextureMesh(renderWindow)
private lateinit var sunTexture: AbstractTexture
@ -140,7 +143,7 @@ class SkyRenderer(
skyboxMesh.draw()
}
override fun draw() {
override fun drawCustom() {
renderWindow.renderSystem.reset(depth = DepthFunctions.LESS_OR_EQUAL)
drawSkybox()
drawSun()

View File

@ -0,0 +1,8 @@
package de.bixilon.minosoft.gui.rendering.system.base.phases
import de.bixilon.minosoft.gui.rendering.Renderer
interface CustomDrawable : Renderer {
fun drawCustom()
}

View File

@ -0,0 +1,12 @@
package de.bixilon.minosoft.gui.rendering.system.base.phases
import de.bixilon.minosoft.gui.rendering.Renderer
interface OpaqueDrawable : Renderer {
fun setupOpaque() {
renderSystem.reset(blending = false)
}
fun drawOpaque()
}

View File

@ -0,0 +1,12 @@
package de.bixilon.minosoft.gui.rendering.system.base.phases
import de.bixilon.minosoft.gui.rendering.Renderer
interface OtherDrawable : Renderer {
fun setupOther() {
renderSystem.reset()
}
fun drawOther()
}

View File

@ -0,0 +1,44 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.system.base.phases
import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.util.KUtil.unsafeCast
import kotlin.reflect.KClass
class RenderPhases<T : Renderer>(
val type: KClass<T>,
val setup: (T) -> Unit,
val draw: (T) -> Unit,
) {
fun invokeSetup(renderer: Renderer) {
setup.invoke(renderer.unsafeCast())
}
fun invokeDraw(renderer: Renderer) {
draw.invoke(renderer.unsafeCast())
}
companion object {
val OTHER = RenderPhases(OtherDrawable::class, { it.setupOther() }, { it.drawOther() })
val CUSTOM = RenderPhases(CustomDrawable::class, { }, { it.drawCustom() })
val OPAQUE = RenderPhases(OpaqueDrawable::class, { it.setupOpaque() }, { it.drawOpaque() })
val TRANSPARENT = RenderPhases(TransparentDrawable::class, { it.setupTransparent() }, { it.drawTransparent() })
val TRANSLUCENT = RenderPhases(TranslucentDrawable::class, { it.setupTranslucent() }, { it.drawTranslucent() })
val VALUES = arrayOf(OTHER, CUSTOM, OPAQUE, TRANSPARENT, TRANSLUCENT)
}
}

View File

@ -0,0 +1,14 @@
package de.bixilon.minosoft.gui.rendering.system.base.phases
import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.system.base.BlendingFunctions
interface TranslucentDrawable : Renderer {
fun setupTranslucent() {
renderSystem.reset(depthMask = false) // ToDo: This is just a translucent workaround
renderSystem.setBlendFunc(BlendingFunctions.SOURCE_ALPHA, BlendingFunctions.ONE_MINUS_SOURCE_ALPHA, BlendingFunctions.ONE, BlendingFunctions.ONE_MINUS_SOURCE_ALPHA)
}
fun drawTranslucent()
}

View File

@ -0,0 +1,12 @@
package de.bixilon.minosoft.gui.rendering.system.base.phases
import de.bixilon.minosoft.gui.rendering.Renderer
interface TransparentDrawable : Renderer {
fun setupTransparent() {
renderSystem.reset(blending = false)
}
fun drawTransparent()
}

View File

@ -30,6 +30,7 @@ interface Shader {
val renderWindow: RenderWindow
val resourceLocation: ResourceLocation
val uniforms: List<String>
val defines: MutableMap<String, Any>
val log: String
@ -74,6 +75,7 @@ interface Shader {
}
companion object {
const val TRANSPARENT_DEFINE = "TRANSPARENT"
val DEFAULT_DEFINES: Map<String, (renderWindow: RenderWindow) -> Any?> = mapOf(
"ANIMATED_TEXTURE_COUNT" to {
max(it.textureManager.staticTextures.animator.size, 1)

View File

@ -23,5 +23,5 @@ interface SpriteAnimator {
fun draw()
fun use(shader: Shader, bufferName: String = "uAnimationBuffer")
fun use(shader: Shader, bufferName: String = "uSpriteBuffer")
}

View File

@ -15,11 +15,11 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.texture
import de.bixilon.minosoft.data.assets.AssetsManager
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureArray
import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties
import example.jonathan2520.SRGBAverager
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
import org.lwjgl.BufferUtils
@ -42,119 +42,54 @@ interface AbstractTexture {
fun load(assetsManager: AssetsManager)
fun generateMipMaps(): Array<Pair<Vec2i, ByteBuffer>> {
val ret: MutableList<Pair<Vec2i, ByteBuffer>> = mutableListOf()
var lastBuffer = data!!
var lastSize = size
for (i in 0 until OpenGLTextureArray.MAX_MIPMAP_LEVELS) {
val size = Vec2i(size.x shr i, size.y shr i)
if (i != 0 && size.x != 0 && size.y != 0) {
lastBuffer = generateMipmap(lastBuffer, lastSize, size)
lastSize = size
fun generateMipMaps(): Array<ByteBuffer> {
val images: MutableList<ByteBuffer> = mutableListOf()
var data = data!!
images += data
for (i in 1 until OpenGLTextureArray.MAX_MIPMAP_LEVELS) {
val mipMapSize = Vec2i(size.x shr i, size.y shr i)
if (mipMapSize.x <= 0 || mipMapSize.y <= 0) {
break
}
ret += Pair(size, lastBuffer)
data = generateMipmap(data, Vec2i(size.x shr (i - 1), size.y shr (i - 1)))
images += data
}
return ret.toTypedArray()
return images.toTypedArray()
}
private fun generateMipmap(origin: ByteBuffer, oldSize: Vec2i): ByteBuffer {
// No Vec2i: performance reasons
val oldSizeX = oldSize.x
val newSizeX = oldSizeX shr 1
private fun ByteBuffer.getRGB(start: Int): RGBColor {
return RGBColor(get(start), get(start + 1), get(start + 2), get(start + 3))
}
private fun ByteBuffer.setRGB(start: Int, color: RGBColor) {
put(start, color.red.toByte())
put(start + 1, color.green.toByte())
put(start + 2, color.blue.toByte())
put(start + 3, color.alpha.toByte())
}
@Deprecated(message = "This is garbage, will be improved soon...")
private fun generateMipmap(biggerBuffer: ByteBuffer, oldSize: Vec2i, newSize: Vec2i): ByteBuffer {
val sizeFactor = oldSize / newSize
val buffer = BufferUtils.createByteBuffer(biggerBuffer.capacity() shr 1)
val buffer = BufferUtils.createByteBuffer(origin.capacity() shr 1)
buffer.limit(buffer.capacity())
fun getRGB(x: Int, y: Int): RGBColor {
return biggerBuffer.getRGB((y * oldSize.x + x) * 4)
fun getRGB(x: Int, y: Int): Int {
return origin.getInt((y * oldSizeX + x) * 4)
}
fun setRGB(x: Int, y: Int, color: RGBColor) {
buffer.setRGB((y * newSize.x + x) * 4, color)
fun setRGB(x: Int, y: Int, color: Int) {
buffer.putInt((y * newSizeX + x) * 4, color)
}
for (y in 0 until newSize.y) {
for (x in 0 until newSize.x) {
for (y in 0 until (oldSize.y shr 1)) {
for (x in 0 until newSizeX) {
val xOffset = x * 2
val yOffset = y * 2
// check what is the most used transparency
val transparencyPixelCount = IntArray(TextureTransparencies.VALUES.size)
for (mixY in 0 until sizeFactor.y) {
for (mixX in 0 until sizeFactor.x) {
val color = getRGB(x * sizeFactor.x + mixX, y * sizeFactor.y + mixY)
when (color.alpha) {
255 -> transparencyPixelCount[TextureTransparencies.OPAQUE.ordinal]++
0 -> transparencyPixelCount[TextureTransparencies.TRANSPARENT.ordinal]++
else -> transparencyPixelCount[TextureTransparencies.TRANSLUCENT.ordinal]++
}
}
}
var largest = 0
for (count in transparencyPixelCount) {
if (count > largest) {
largest = count
}
}
var transparency: TextureTransparencies = TextureTransparencies.OPAQUE
for ((index, count) in transparencyPixelCount.withIndex()) {
if (count >= largest) {
transparency = TextureTransparencies[index]
break
}
}
val output = SRGBAverager.average(
getRGB(xOffset + 0, yOffset + 0),
getRGB(xOffset + 1, yOffset + 0),
getRGB(xOffset + 0, yOffset + 1),
getRGB(xOffset + 1, yOffset + 1),
)
var count = 0
var red = 0
var green = 0
var blue = 0
var alpha = 0
// make magic for the most used transparency
for (mixY in 0 until sizeFactor.y) {
for (mixX in 0 until sizeFactor.x) {
val color = getRGB(x * sizeFactor.x + mixX, y * sizeFactor.y + mixY)
when (transparency) {
TextureTransparencies.OPAQUE -> {
if (color.alpha != 0xFF) {
continue
}
red += color.red
green += color.green
blue += color.blue
alpha += color.alpha
count++
}
TextureTransparencies.TRANSPARENT -> {
}
TextureTransparencies.TRANSLUCENT -> {
red += color.red
green += color.green
blue += color.blue
alpha += color.alpha
count++
}
}
}
}
if (count == 0) {
count++
}
setRGB(x, y, RGBColor(red / count, green / count, blue / count, alpha / count))
setRGB(x, y, output)
}
}

View File

@ -40,7 +40,7 @@ class OpenGLShader(
) : Shader {
override var loaded: Boolean = false
private set
val defines: MutableMap<String, Any> = mutableMapOf()
override val defines: MutableMap<String, Any> = mutableMapOf()
private var shader = -1
override var uniforms: MutableList<String> = mutableListOf()
private set

View File

@ -137,20 +137,21 @@ class OpenGLTextureArray(
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT)
// glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, MAX_MIPMAP_LEVELS - 1)
for (i in 0 until MAX_MIPMAP_LEVELS) {
glTexImage3D(GL_TEXTURE_2D_ARRAY, i, GL_RGBA, resolution shr i, resolution shr i, textures.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?)
for (level in 0 until MAX_MIPMAP_LEVELS) {
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, resolution shr level, resolution shr level, textures.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?)
}
for (texture in textures) {
val mipMaps = texture.generateMipMaps()
val renderData = texture.renderData as OpenGLTextureData
for ((mipMapLevel, data) in mipMaps.withIndex()) {
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, mipMapLevel, 0, 0, renderData.index, data.first.x, data.first.y, mipMapLevel + 1, GL_RGBA, GL_UNSIGNED_BYTE, data.second)
for ((level, data) in mipMaps.withIndex()) {
val size = texture.size shr level
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, renderData.index, size.x, size.y, level + 1, GL_RGBA, GL_UNSIGNED_BYTE, data)
}
texture.data = null
@ -192,7 +193,7 @@ class OpenGLTextureArray(
companion object {
val TEXTURE_RESOLUTION_ID_MAP = arrayOf(16, 32, 64, 128, 256, 512, 1024) // A 12x12 texture will be saved in texture id 0 (in 0 are only 16x16 textures). Animated textures get split
val TEXTURE_RESOLUTION_ID_MAP = intArrayOf(16, 32, 64, 128, 256, 512, 1024) // A 12x12 texture will be saved in texture id 0 (in 0 are only 16x16 textures). Animated textures get split
const val TEXTURE_MAX_RESOLUTION = 1024
const val MAX_MIPMAP_LEVELS = 5
}

View File

@ -12,6 +12,7 @@
*/
package de.bixilon.minosoft.util
@Deprecated("Java only")
data class Pair<K, V>(
val key: K,
val value: V,

View File

@ -0,0 +1,74 @@
// Source: https://bugs.mojang.com/browse/MC-114265
// Averaging of texels for mipmap generation.
package example.jonathan2520;
public class SRGBAverager {
private static final SRGBTable SRGB = new SRGBTable();
public static int average(int c0, int c1, int c2, int c3) {
if ((((c0 | c1 | c2 | c3) ^ (c0 & c1 & c2 & c3)) & 0xff000000) == 0) {
// Alpha values are all equal. Simplifies computation somewhat. It's
// also a reasonable fallback when all alpha values are zero, in
// which case the resulting color would normally be undefined.
// Defining it like this allows code that uses invisible colors for
// whatever reason to work. Note that Minecraft's original code
// would set the color to black; this is added functionality.
float r = SRGB.decode(c0 & 0xff)
+ SRGB.decode(c1 & 0xff)
+ SRGB.decode(c2 & 0xff)
+ SRGB.decode(c3 & 0xff);
float g = SRGB.decode(c0 >> 8 & 0xff)
+ SRGB.decode(c1 >> 8 & 0xff)
+ SRGB.decode(c2 >> 8 & 0xff)
+ SRGB.decode(c3 >> 8 & 0xff);
float b = SRGB.decode(c0 >> 16 & 0xff)
+ SRGB.decode(c1 >> 16 & 0xff)
+ SRGB.decode(c2 >> 16 & 0xff)
+ SRGB.decode(c3 >> 16 & 0xff);
return SRGB.encode(0.25F * r)
| SRGB.encode(0.25F * g) << 8
| SRGB.encode(0.25F * b) << 16
| c0 & 0xff000000;
} else {
// The general case. Well-defined if at least one alpha value is
// not zero. If you do try to process all zeros, you get
// r = g = b = a = 0 which will NaN out in the division and produce
// invisible black. You could remove the other case if you're okay
// with that, but mind that producing or consuming a NaN causes an
// extremely slow exception handler to be run on many CPUs.
float a0 = c0 >>> 24;
float a1 = c1 >>> 24;
float a2 = c2 >>> 24;
float a3 = c3 >>> 24;
float r = a0 * SRGB.decode(c0 & 0xff)
+ a1 * SRGB.decode(c1 & 0xff)
+ a2 * SRGB.decode(c2 & 0xff)
+ a3 * SRGB.decode(c3 & 0xff);
float g = a0 * SRGB.decode(c0 >> 8 & 0xff)
+ a1 * SRGB.decode(c1 >> 8 & 0xff)
+ a2 * SRGB.decode(c2 >> 8 & 0xff)
+ a3 * SRGB.decode(c3 >> 8 & 0xff);
float b = a0 * SRGB.decode(c0 >> 16 & 0xff)
+ a1 * SRGB.decode(c1 >> 16 & 0xff)
+ a2 * SRGB.decode(c2 >> 16 & 0xff)
+ a3 * SRGB.decode(c3 >> 16 & 0xff);
float a = a0 + a1 + a2 + a3;
return SRGB.encode(r / a)
| SRGB.encode(g / a) << 8
| SRGB.encode(b / a) << 16
| (int) (0.25F * a + 0.5F) << 24;
}
}
}

View File

@ -0,0 +1,58 @@
// Source: https://bugs.mojang.com/browse/MC-114265
// Offers very precise sRGB encoding and decoding.
// The actual values defining sRGB are alpha = 0.055 and gamma = 2.4.
// This class works directly from that definition to take advantage of all
// available precision, unlike pre-rounded constants like 12.92 that cause a
// comparatively humongous discontinuity at a point that should be of
// differentiability class C^1.
// Stored values are chosen to speed up bulk conversion somewhat.
package example.jonathan2520;
public class SRGBCalculator {
private final double decode_threshold;
private final double decode_slope;
private final double decode_multiplier;
private final double decode_addend;
private final double decode_exponent;
private final double encode_threshold;
private final double encode_slope;
private final double encode_multiplier;
private final double encode_addend;
private final double encode_exponent;
public SRGBCalculator(double gamma, double alpha) {
encode_multiplier = alpha + 1.0;
decode_multiplier = 1.0 / encode_multiplier;
encode_addend = -alpha;
decode_addend = decode_multiplier * alpha;
encode_exponent = 1.0 / gamma;
decode_exponent = gamma;
decode_threshold = alpha / (gamma - 1.0);
encode_threshold = Math.pow(gamma * decode_threshold * decode_multiplier, gamma);
encode_slope = decode_threshold / encode_threshold;
decode_slope = encode_threshold / decode_threshold;
}
public SRGBCalculator() {
this(2.4, 0.055);
}
public double decode(double x) {
if (x < decode_threshold)
return decode_slope * x;
else
return Math.pow(x * decode_multiplier + decode_addend, decode_exponent);
}
public double encode(double x) {
if (x < encode_threshold)
return encode_slope * x;
else
return Math.pow(x, encode_exponent) * encode_multiplier + encode_addend;
}
}

View File

@ -0,0 +1,73 @@
// Source: https://bugs.mojang.com/browse/MC-114265
// Offers fast sRGB encoding and decoding.
// Decoding is a straightforward table look-up.
// Encoding is a little more sophisticated. It's an exact conversion using about
// 4 kB of look-up tables that's also still quick. It relies on the fact that
// thresholds that would round to the next value have a minimum spacing of about
// 0.0003. That means that any range of 0.0003 contains at most one threshold.
// The to_int table contains the smaller value in the range. The threshold table
// contains the threshold above which the value should be one greater.
// The minimum scale value that maintains proper spacing is 255 * encode_slope
// or about 3295.4. You can get away with a little bit less like 3200, taking
// advantage of the alignment of thresholds, but it's not really worth it.
package example.jonathan2520;
public class SRGBTable {
private final float scale;
private final float[] to_float;
private final float[] threshold;
private final byte[] to_int;
public SRGBTable() {
this(new SRGBCalculator(), 3295.5F);
}
public SRGBTable(SRGBCalculator calculator, float scale) {
this.scale = scale;
to_float = new float[256];
threshold = new float[256];
to_int = new byte[(int) scale + 1];
for (int i = 0; i < 255; ++i) {
to_float[i] = (float) calculator.decode(i / 255.0);
double dthresh = calculator.decode((i + 0.5) / 255.0);
float fthresh = (float) dthresh;
if (fthresh >= dthresh)
fthresh = Math.nextAfter(fthresh, -1);
threshold[i] = fthresh;
}
to_float[255] = 1;
threshold[255] = Float.POSITIVE_INFINITY;
int offset = 0;
for (int i = 0; i < 255; ++i) {
int up_to = (int) (threshold[i] * scale);
build_to_int_table(offset, up_to, (byte) i);
offset = up_to + 1;
}
build_to_int_table(offset, (int) scale, (byte) 255);
}
private void build_to_int_table(int offset, int up_to, byte value) {
if (offset > up_to)
throw new IllegalArgumentException("scale is too small");
while (offset <= up_to)
to_int[offset++] = value;
}
// x in [0, 255]
public float decode(int x) {
return to_float[x];
}
// x in about [-0.0003, 1.00015]: tolerates rounding error on top of [0, 1]
public int encode(float x) {
int index = to_int[(int) (x * scale)] & 0xff;
if (x > threshold[index])
++index;
return index;
}
}

View File

@ -41,7 +41,7 @@ void main() {
float fogFactor = getFogFactor(distance(uCameraPosition, finVertexPosition));
if (fogFactor != 1.0f) {
outColor = vec4(mix(uFogColor.rgb, outColor.rgb, fogFactor), outColor.a);
foutColor = vec4(mix(uFogColor.rgb, foutColor.rgb, fogFactor), foutColor.a);
};
#endif
}

View File

@ -33,14 +33,26 @@ void main() {
if (finInterpolation == 0.0f) {
foutColor = texelColor1 * finTintColor;
#ifdef TRANSPARENT
if (foutColor.a < 0.3f){
discard;
}
#endif
return;
}
vec4 texelColor2 = getTexture(finTextureIndex2, finTextureCoordinates2);
vec4 texelColor2 = getTexture(finTextureIndex2, finTextureCoordinates2);
if (texelColor2.a == 0.0f) {
discard;
}
foutColor = mix(texelColor1, texelColor2, finInterpolation) * finTintColor;
#ifdef TRANSPARENT
if (foutColor.a < 0.3f){
discard;
}
#endif
}

View File

@ -28,6 +28,6 @@ void main() {
if (finTintColor.a == 1.0f && texelColor.a == 0) {
discard;
}
// outColor = vec4(0.0f, 1.0f, 1.0f, 1.0f);
// foutColor = vec4(0.0f, 1.0f, 1.0f, 1.0f);
foutColor = texelColor * finTintColor;
}

View File

@ -13,7 +13,7 @@
#version 330 core
out vec4 outColor;
out vec4 foutColor;
flat in uint finTextureIndex1;
in vec3 finTextureCoordinates1;
@ -34,17 +34,28 @@ void work() {
}
if (finInterpolation == 0.0f) {
outColor = firstTexelColor * finTintColor;
foutColor = firstTexelColor * finTintColor;
#ifdef TRANSPARENT
if (foutColor.a < 0.3f){
discard;
}
#endif
return;
}
vec4 secondTexelColor = getTexture(finTextureIndex2, finTextureCoordinates2);
vec4 secondTexelColor = getTexture(finTextureIndex2, finTextureCoordinates2);
if (secondTexelColor.a == 0.0f) {
discard;
}
outColor = mix(firstTexelColor, secondTexelColor, finInterpolation) * finTintColor;
foutColor = mix(firstTexelColor, secondTexelColor, finInterpolation) * finTintColor;
#ifdef TRANSPARENT
if (foutColor.a < 0.3f) {
discard;
}
#endif
}
#include "minosoft:postprocessing/fragment"
#include "minosoft:postprocessing/fragment"