Generate and use mipmaps for screen textures

This commit is contained in:
Fingercomp 2024-08-28 02:49:20 +07:00
parent acb1374140
commit 5e7777bd4c
No known key found for this signature in database
GPG Key ID: BBC71CEE45D86E37
9 changed files with 103 additions and 23 deletions

View File

@ -53,4 +53,9 @@ ocelot {
# Otherwise, content will be shown only in windows
renderScreenDataOnNodes: true
}
render {
# Whether mipmap scaling is enabled for screen windows (when shrinking).
screenWindowMipmap: true
}
}

View File

@ -50,6 +50,8 @@ class Settings(val config: Config) extends SettingsData {
saveOnExit = config.getBooleanOrElse("ocelot.workspace.saveOnExit", default = true)
openLastWorkspace = config.getBooleanOrElse("ocelot.workspace.openLastWorkspace", default = true)
renderScreenDataOnNodes = config.getBooleanOrElse("ocelot.workspace.renderScreenDataOnNodes", default = true)
screenWindowMipmap = config.getBooleanOrElse("ocelot.render.screenWindowMipmap", default = true)
}
object Settings extends Logging {

View File

@ -3,6 +3,7 @@ package ocelot.desktop.graphics
import ocelot.desktop.color.{Color, RGBAColorNorm}
import ocelot.desktop.geometry.{Rect2D, Size2D, Transform2D, Vector2D}
import ocelot.desktop.graphics.IconSource.Animation
import ocelot.desktop.graphics.Texture.MinFilteringMode
import ocelot.desktop.graphics.mesh.{Mesh2D, MeshInstance2D, MeshVertex2D}
import ocelot.desktop.graphics.render.InstanceRenderer
import ocelot.desktop.ui.UiHandler
@ -145,11 +146,19 @@ class Graphics(private var width: Int, private var height: Int, private var scal
flush(mainTexture = viewport.textureColor)
}
def blitScreenViewport(viewport: ScreenViewport, bounds: Rect2D, alpha: Float = 1.0f): Unit = {
def blitScreenViewport(
viewport: ScreenViewport,
bounds: Rect2D,
filteringMode: MinFilteringMode = MinFilteringMode.Nearest,
alpha: Float = 1.0f
): Unit = {
flush()
foreground = RGBAColorNorm(1, 1, 1, alpha)
spriteRect = Rect2D(0, 1f, 1f, -1f)
_rect(bounds.x, bounds.y, bounds.w, bounds.h, fixUV = false)
viewport.texture.setMinFilter(filteringMode)
flush(mainTexture = viewport.texture)
}

View File

@ -27,6 +27,8 @@ class ScreenViewport(graphics: Graphics, private var _width: Int, private var _h
private var _foreground: RGBAColorNorm = RGBAColorNorm(0f, 0f, 0f)
private var _background: RGBAColorNorm = RGBAColorNorm(1f, 1f, 1f)
private var mipmapDirty = false
override def freeResource(): Unit = {
super.freeResource()
@ -110,6 +112,8 @@ class ScreenViewport(graphics: Graphics, private var _width: Int, private var _h
Spritesheet.texture.bind()
_font.texture.bind(1)
renderer.flush()
mipmapDirty = true
}
def renderWith(f: => Unit): Unit = {
@ -121,4 +125,11 @@ class ScreenViewport(graphics: Graphics, private var _width: Int, private var _h
flush()
}
}
def generateMipmap(): Unit = {
if (mipmapDirty) {
texture.generateMipmap()
mipmapDirty = false
}
}
}

View File

@ -1,5 +1,6 @@
package ocelot.desktop.graphics
import ocelot.desktop.graphics.Texture.MinFilteringMode
import ocelot.desktop.util.{Logging, Resource}
import org.lwjgl.BufferUtils
import org.lwjgl.opengl._
@ -7,7 +8,7 @@ import org.lwjgl.opengl._
import java.awt.image.BufferedImage
import java.nio.ByteBuffer
class Texture extends Logging with Resource {
class Texture() extends Logging with Resource {
val texture: Int = GL11.glGenTextures()
bind()
@ -70,8 +71,30 @@ class Texture extends Logging with Resource {
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture)
}
def setMinFilter(filter: MinFilteringMode): Unit = {
bind()
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter.glValue)
}
def generateMipmap(): Unit = {
bind()
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D)
}
override def freeResource(): Unit = {
super.freeResource()
GL11.glDeleteTextures(texture)
}
}
object Texture {
class MinFilteringMode private(private[Texture] val glValue: Int, val needsMipmap: Boolean)
object MinFilteringMode {
val Nearest = new MinFilteringMode(GL11.GL_NEAREST, false)
val NearestMipmapNearest = new MinFilteringMode(GL11.GL_NEAREST_MIPMAP_NEAREST, true)
val NearestMipmapLinear = new MinFilteringMode(GL11.GL_NEAREST_MIPMAP_LINEAR, true)
val LinearMipmapNearest = new MinFilteringMode(GL11.GL_LINEAR_MIPMAP_NEAREST, true)
val LinearMipmapLinear = new MinFilteringMode(GL11.GL_LINEAR_MIPMAP_LINEAR, true)
}
}

View File

@ -2,6 +2,7 @@ package ocelot.desktop.node.nodes
import ocelot.desktop.color.{Color, IntColor}
import ocelot.desktop.geometry.{Rect2D, Size2D}
import ocelot.desktop.graphics.Texture.MinFilteringMode
import ocelot.desktop.graphics.{Graphics, IconSource, ScreenViewport}
import ocelot.desktop.node.Node.{HighlightThickness, NoHighlightSize, Size}
import ocelot.desktop.node.nodes.ScreenNode.{FontHeight, FontWidth, Margin}
@ -116,9 +117,8 @@ class ScreenNode(val screen: Screen)
super.setupContextMenu(menu, event)
}
private def drawScreenTexture(): Unit = {
if (bufferRendered) return
private def drawScreenTexture(needsMipmap: Boolean): Unit = {
if (!bufferRendered) {
viewport.renderWith {
val width = (screen.getWidth * FontWidth).toInt
val height = (screen.getHeight * FontHeight).toInt
@ -139,21 +139,33 @@ class ScreenNode(val screen: Screen)
}
}
}
}
bufferRendered = true
}
if (needsMipmap) {
viewport.generateMipmap()
}
}
def drawScreenData(g: Graphics, startX: Float, startY: Float, scaleX: Float, scaleY: Float): Unit = {
def drawScreenData(
g: Graphics,
startX: Float,
startY: Float,
scaleX: Float,
scaleY: Float,
filteringMode: MinFilteringMode
): Unit = {
g.save()
g.scale(scaleX, scaleY)
val startXScaled = startX / scaleX
val startYScaled = startY / scaleY
drawScreenTexture()
drawScreenTexture(filteringMode.needsMipmap)
val bounds = Rect2D(startXScaled, startYScaled, viewport.width, viewport.height)
g.blitScreenViewport(viewport, bounds)
g.blitScreenViewport(viewport, bounds, filteringMode = filteringMode)
g.restore()
}
@ -351,7 +363,8 @@ class ScreenNode(val screen: Screen)
virtualScreenBounds.x + virtualScreenBounds.w / 2 - (pixelDataSize.width * scale) / 2,
virtualScreenBounds.y + virtualScreenBounds.h / 2 - (pixelDataSize.height * scale) / 2,
scale,
scale
scale,
MinFilteringMode.NearestMipmapNearest
)
}
// Drawing simple overlay otherwise

View File

@ -68,6 +68,15 @@ class UISettingsTab extends SettingsTab {
}
}, Padding2D(bottom = 8))
children :+= new PaddingBox(new Checkbox("Enable mipmaps for screen windows",
initialValue = Settings.get.screenWindowMipmap) {
override def minimumSize: Size2D = Size2D(512, 24)
override def onValueChanged(value: Boolean): Unit = {
Settings.get.screenWindowMipmap = value
}
}, Padding2D(bottom = 8))
children :+= new PaddingBox(new Slider((Settings.get.scaleFactor - 1) / 2, "Interface scale", 5) {
override def minimumSize: Size2D = Size2D(512, 24)

View File

@ -42,6 +42,8 @@ class SettingsData {
var openLastWorkspace: Boolean = true
var renderScreenDataOnNodes: Boolean = true
var screenWindowMipmap: Boolean = true
private val mirror = universe.runtimeMirror(getClass.getClassLoader).reflect(this)
def updateWith(data: SettingsData): Unit = {

View File

@ -4,6 +4,7 @@ import ocelot.desktop.audio.SoundSource
import ocelot.desktop.color.RGBAColor
import ocelot.desktop.geometry.{Rect2D, Size2D, Vector2D}
import ocelot.desktop.graphics.Graphics
import ocelot.desktop.graphics.Texture.MinFilteringMode
import ocelot.desktop.node.nodes.ScreenNode
import ocelot.desktop.node.nodes.ScreenNode.{FontHeight, FontWidth}
import ocelot.desktop.ui.UiHandler
@ -12,7 +13,7 @@ import ocelot.desktop.ui.event.{DragEvent, KeyEvent, MouseEvent, ScrollEvent}
import ocelot.desktop.ui.widget.window.BasicWindow
import ocelot.desktop.util.{DrawUtils, Logging}
import ocelot.desktop.windows.ScreenWindow._
import ocelot.desktop.{ColorScheme, OcelotDesktop}
import ocelot.desktop.{ColorScheme, OcelotDesktop, Settings}
import org.apache.commons.lang3.StringUtils
import org.lwjgl.input.Keyboard
import totoro.ocelot.brain.entity.Screen
@ -254,7 +255,12 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
startX,
startY,
scaleX,
scaleY
scaleY,
if (Settings.get.screenWindowMipmap) {
MinFilteringMode.LinearMipmapLinear
} else {
MinFilteringMode.Nearest
}
)
}