mirror of
https://gitlab.com/cc-ru/ocelot/ocelot-desktop.git
synced 2025-12-20 11:09:20 +01:00
Add nice frame to the screen
This commit is contained in:
parent
96e29edbf6
commit
d7c084c0dd
@ -8,5 +8,5 @@ out vec4 outColor;
|
|||||||
uniform sampler2D uTexture;
|
uniform sampler2D uTexture;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = fColor;
|
outColor = texture(uTexture, fUV) * fColor;
|
||||||
}
|
}
|
||||||
BIN
src/main/resources/ocelot/desktop/spritesheet.png
Normal file
BIN
src/main/resources/ocelot/desktop/spritesheet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
27
src/main/resources/ocelot/desktop/spritesheet.txt
Normal file
27
src/main/resources/ocelot/desktop/spritesheet.txt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
APU0 0 0 16 16
|
||||||
|
APU1 16 0 16 16
|
||||||
|
APU2 32 0 16 16
|
||||||
|
BorderH 96 32 2 8
|
||||||
|
BorderV 98 32 8 2
|
||||||
|
CPU0 48 0 16 16
|
||||||
|
CPU1 64 0 16 16
|
||||||
|
CPU2 80 0 16 16
|
||||||
|
CornerBL 64 32 8 8
|
||||||
|
CornerBR 72 32 8 8
|
||||||
|
CornerTL 80 32 8 8
|
||||||
|
CornerTR 88 32 8 8
|
||||||
|
EEPROM 96 0 16 16
|
||||||
|
Empty 106 32 1 1
|
||||||
|
GraphicsCard0 112 0 16 16
|
||||||
|
GraphicsCard1 0 16 16 16
|
||||||
|
GraphicsCard2 16 16 16 16
|
||||||
|
HardDiskDrive0 32 16 16 16
|
||||||
|
HardDiskDrive1 48 16 16 16
|
||||||
|
HardDiskDrive2 64 16 16 16
|
||||||
|
InternetCard 80 16 16 16
|
||||||
|
Memory0 96 16 16 16
|
||||||
|
Memory1 112 16 16 16
|
||||||
|
Memory2 0 32 16 16
|
||||||
|
Memory3 16 32 16 16
|
||||||
|
Memory4 32 32 16 16
|
||||||
|
Memory5 48 32 16 16
|
||||||
@ -1,10 +1,10 @@
|
|||||||
package ocelot.desktop.graphics
|
package ocelot.desktop.graphics
|
||||||
|
|
||||||
import ocelot.desktop.color.{Color, RGBAColorNorm}
|
import ocelot.desktop.color.{Color, IntColor, RGBAColorNorm}
|
||||||
import ocelot.desktop.geometry.Transform2D
|
import ocelot.desktop.geometry.Transform2D
|
||||||
import ocelot.desktop.graphics.mesh.{Mesh, MeshInstance}
|
import ocelot.desktop.graphics.mesh.{Mesh, MeshInstance}
|
||||||
import ocelot.desktop.graphics.render.InstanceRenderer
|
import ocelot.desktop.graphics.render.InstanceRenderer
|
||||||
import ocelot.desktop.util.FontLoader
|
import ocelot.desktop.util.{FontLoader, Spritesheet}
|
||||||
import org.apache.logging.log4j.scala.Logging
|
import org.apache.logging.log4j.scala.Logging
|
||||||
import org.lwjgl.opengl.GL11
|
import org.lwjgl.opengl.GL11
|
||||||
|
|
||||||
@ -24,6 +24,10 @@ class Graphics extends Logging {
|
|||||||
private var _background = RGBAColorNorm(0f, 0f, 0f, 1f)
|
private var _background = RGBAColorNorm(0f, 0f, 0f, 1f)
|
||||||
private var _fontSize: Float = 16f
|
private var _fontSize: Float = 16f
|
||||||
|
|
||||||
|
private var _sprite: String = "Empty"
|
||||||
|
private var spriteRect = Spritesheet.sprites(_sprite)
|
||||||
|
private val emptySpriteTrans = Transform2D.translate(spriteRect.x, spriteRect.y) >> Transform2D.scale(spriteRect.w, spriteRect.h)
|
||||||
|
|
||||||
GL11.glEnable(GL11.GL_DEPTH_TEST)
|
GL11.glEnable(GL11.GL_DEPTH_TEST)
|
||||||
GL11.glDepthFunc(GL11.GL_LEQUAL)
|
GL11.glDepthFunc(GL11.GL_LEQUAL)
|
||||||
GL11.glEnable(GL11.GL_BLEND)
|
GL11.glEnable(GL11.GL_BLEND)
|
||||||
@ -74,6 +78,13 @@ class Graphics extends Logging {
|
|||||||
_fontSize = value
|
_fontSize = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def sprite: String = _sprite
|
||||||
|
|
||||||
|
def sprite_=(value: String): Unit = {
|
||||||
|
_sprite = value
|
||||||
|
spriteRect = Spritesheet.sprites(_sprite)
|
||||||
|
}
|
||||||
|
|
||||||
def text(x: Float, y: Float, text: String): Unit = {
|
def text(x: Float, y: Float, text: String): Unit = {
|
||||||
var ox = x
|
var ox = x
|
||||||
|
|
||||||
@ -105,24 +116,34 @@ class Graphics extends Logging {
|
|||||||
// ^ dirty hack to avoid edge bleeding, somehow works
|
// ^ dirty hack to avoid edge bleeding, somehow works
|
||||||
)
|
)
|
||||||
|
|
||||||
rectRenderer.schedule(MeshInstance(_background, z, Transform2D.translate(x, y) >> Transform2D.scale(width, height)))
|
rectRenderer.schedule(MeshInstance(_background, z, Transform2D.translate(x, y) >> Transform2D.scale(width, height), emptySpriteTrans))
|
||||||
textRenderer.schedule(MeshInstance(_foreground, z + 1, Transform2D.translate(x, y) >> Transform2D.scale(width, height), uvTransform))
|
textRenderer.schedule(MeshInstance(_foreground, z + 1, Transform2D.translate(x, y) >> Transform2D.scale(width, height), uvTransform))
|
||||||
|
|
||||||
z += 2
|
z += 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def sprite(name: String, x: Float, y: Float, width: Float, height: Float): Unit = {
|
||||||
|
flush()
|
||||||
|
sprite = name
|
||||||
|
background = RGBAColorNorm(1f, 1f, 1f, 1f)
|
||||||
|
rect(x, y, width, height)
|
||||||
|
}
|
||||||
|
|
||||||
def rect(x: Float, y: Float, width: Float, height: Float): Unit = {
|
def rect(x: Float, y: Float, width: Float, height: Float): Unit = {
|
||||||
rectRenderer.schedule(MeshInstance(_background, z, Transform2D.translate(x, y) >> Transform2D.scale(width, height)))
|
val uvTransform = Transform2D.translate(spriteRect.x, spriteRect.y) >> Transform2D.scale(spriteRect.w, spriteRect.h)
|
||||||
|
rectRenderer.schedule(MeshInstance(_background, z, Transform2D.translate(x, y) >> Transform2D.scale(width, height), uvTransform))
|
||||||
z += 1
|
z += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
def flush(): Unit = {
|
def flush(): Unit = {
|
||||||
|
Spritesheet.texture.bind()
|
||||||
rectRenderer.flush()
|
rectRenderer.flush()
|
||||||
fontAtlas.bind()
|
fontAtlas.bind()
|
||||||
textRenderer.flush()
|
textRenderer.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
def commit(): Unit = {
|
def commit(): Unit = {
|
||||||
|
Spritesheet.texture.bind()
|
||||||
rectRenderer.commit()
|
rectRenderer.commit()
|
||||||
fontAtlas.bind()
|
fontAtlas.bind()
|
||||||
textRenderer.commit()
|
textRenderer.commit()
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package ocelot.desktop.graphics
|
package ocelot.desktop.graphics
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
import ocelot.desktop.util.{Resource, ResourceManager}
|
import ocelot.desktop.util.{Resource, ResourceManager}
|
||||||
import org.apache.logging.log4j.scala.Logging
|
import org.apache.logging.log4j.scala.Logging
|
||||||
|
import org.lwjgl.BufferUtils
|
||||||
import org.lwjgl.opengl._
|
import org.lwjgl.opengl._
|
||||||
import org.lwjgl.system.MemoryUtil.NULL
|
import org.lwjgl.system.MemoryUtil.NULL
|
||||||
|
|
||||||
@ -21,6 +23,31 @@ class Texture extends Logging with Resource {
|
|||||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST)
|
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST)
|
||||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST)
|
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST)
|
||||||
|
|
||||||
|
def this(image: BufferedImage) {
|
||||||
|
this()
|
||||||
|
|
||||||
|
val pixels = new Array[Int](image.getWidth * image.getHeight)
|
||||||
|
image.getRGB(0, 0, image.getWidth, image.getHeight, pixels, 0, image.getWidth)
|
||||||
|
|
||||||
|
val buf = BufferUtils.createByteBuffer(image.getWidth * image.getHeight * 4)
|
||||||
|
|
||||||
|
for (y <- 0 until image.getHeight) {
|
||||||
|
for (x <- 0 until image.getWidth) {
|
||||||
|
val pixel = pixels(y * image.getWidth + x)
|
||||||
|
buf.put(((pixel >> 16) & 0xFF).toByte)
|
||||||
|
buf.put(((pixel >> 8) & 0xFF).toByte)
|
||||||
|
buf.put((pixel & 0xFF).toByte)
|
||||||
|
buf.put(((pixel >> 24) & 0xFF).toByte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.flip()
|
||||||
|
|
||||||
|
bind()
|
||||||
|
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, image.getWidth, image.getHeight, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf)
|
||||||
|
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D)
|
||||||
|
}
|
||||||
|
|
||||||
def this(width: Int, height: Int, format: Int, dataType: Int) = {
|
def this(width: Int, height: Int, format: Int, dataType: Int) = {
|
||||||
this()
|
this()
|
||||||
bind()
|
bind()
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import java.nio.{ByteBuffer, IntBuffer}
|
|||||||
import ocelot.desktop.geometry.{Size2D, Vector2D}
|
import ocelot.desktop.geometry.{Size2D, Vector2D}
|
||||||
import ocelot.desktop.graphics.Graphics
|
import ocelot.desktop.graphics.Graphics
|
||||||
import ocelot.desktop.ui.widget.RootWidget
|
import ocelot.desktop.ui.widget.RootWidget
|
||||||
import ocelot.desktop.util.{Audio, FPSCalculator, FontLoader}
|
import ocelot.desktop.util.{Audio, FPSCalculator, FontLoader, Spritesheet}
|
||||||
import org.apache.logging.log4j.scala.Logging
|
import org.apache.logging.log4j.scala.Logging
|
||||||
import org.lwjgl.glfw.{GLFW, GLFWErrorCallback}
|
import org.lwjgl.glfw.{GLFW, GLFWErrorCallback}
|
||||||
import org.lwjgl.openal._
|
import org.lwjgl.openal._
|
||||||
@ -75,6 +75,7 @@ class UiHandler(val root: RootWidget) extends Logging {
|
|||||||
logger.info(s"OpenGL renderer: ${GL11.glGetString(GL11.GL_RENDERER)}")
|
logger.info(s"OpenGL renderer: ${GL11.glGetString(GL11.GL_RENDERER)}")
|
||||||
|
|
||||||
FontLoader.init()
|
FontLoader.init()
|
||||||
|
Spritesheet.load()
|
||||||
graphics = new Graphics
|
graphics = new Graphics
|
||||||
|
|
||||||
soundDevice = ALC10.alcOpenDevice(null.asInstanceOf[ByteBuffer])
|
soundDevice = ALC10.alcOpenDevice(null.asInstanceOf[ByteBuffer])
|
||||||
|
|||||||
@ -14,17 +14,17 @@ import scala.collection.mutable
|
|||||||
class ScreenWidget(screen: Screen) extends RootWidget with Logging {
|
class ScreenWidget(screen: Screen) extends RootWidget with Logging {
|
||||||
private val fontSize = 16f
|
private val fontSize = 16f
|
||||||
|
|
||||||
var width = 80
|
var width = screen.getWidth
|
||||||
var height = 25
|
var height = screen.getHeight
|
||||||
|
|
||||||
var background: Int = 0x000000
|
var background: Int = 0x000000
|
||||||
var foreground: Int = 0xFFFFFF
|
var foreground: Int = 0xFFFFFF
|
||||||
|
|
||||||
private var data: Array[Cell] = Array.fill(width * height)(Cell(' ', background, foreground))
|
private var data: Array[Cell] = Array.fill(width * height)(Cell(' ', background, foreground))
|
||||||
|
|
||||||
override def minimumSize: Option[Size2D] = Some(Size2D(width * fontSize / 2f, height * fontSize))
|
override def minimumSize: Option[Size2D] = Some(Size2D(width * fontSize / 2f + 32, height * fontSize + 32))
|
||||||
|
|
||||||
override def maximumSize: Option[Size2D] = Some(Size2D(width * fontSize, height * fontSize * 2f))
|
override def maximumSize: Option[Size2D] = minimumSize
|
||||||
|
|
||||||
private var lastMousePos = Vector2D(0, 0)
|
private var lastMousePos = Vector2D(0, 0)
|
||||||
private var pressedMouseButtons = new mutable.HashSet[MouseEvent.Button.Value]()
|
private var pressedMouseButtons = new mutable.HashSet[MouseEvent.Button.Value]()
|
||||||
@ -63,7 +63,7 @@ class ScreenWidget(screen: Screen) extends RootWidget with Logging {
|
|||||||
screen.mouseScroll(lastMousePos.x, lastMousePos.y, event.offset, User("myself"))
|
screen.mouseScroll(lastMousePos.x, lastMousePos.y, event.offset, User("myself"))
|
||||||
}
|
}
|
||||||
|
|
||||||
def convertMousePos(p: Vector2D): Vector2D = Vector2D(p.x / fontSize * 2f, p.y / fontSize)
|
def convertMousePos(p: Vector2D): Vector2D = Vector2D((p.x - 16) / fontSize * 2f, (p.y - 16) / fontSize)
|
||||||
|
|
||||||
override def update(): Unit = {
|
override def update(): Unit = {
|
||||||
val currentMousePos = convertMousePos(uiHandler.mousePosition)
|
val currentMousePos = convertMousePos(uiHandler.mousePosition)
|
||||||
@ -79,10 +79,14 @@ class ScreenWidget(screen: Screen) extends RootWidget with Logging {
|
|||||||
override def windowTitle: String = f"Ocelot Desktop [FPS: ${uiHandler.fps}%2.3f]"
|
override def windowTitle: String = f"Ocelot Desktop [FPS: ${uiHandler.fps}%2.3f]"
|
||||||
|
|
||||||
override def draw(g: Graphics): Unit = {
|
override def draw(g: Graphics): Unit = {
|
||||||
val tx = size.width / 2 - fontSize * width / 4
|
val w = math.round(fontSize * width / 2f) + 32
|
||||||
val ty = size.height / 2 - fontSize * height / 2
|
val h = math.round(fontSize * height) + 32
|
||||||
|
|
||||||
|
g.clear(0, 0, w, h)
|
||||||
|
g.background = IntColor(0x333333)
|
||||||
|
g.sprite = "Empty"
|
||||||
|
g.rect(0, 0, w, h)
|
||||||
|
|
||||||
g.clear(0, 0, math.round(fontSize * width / 2f), math.round(fontSize * height))
|
|
||||||
g.fontSize = fontSize
|
g.fontSize = fontSize
|
||||||
|
|
||||||
for (y <- 0 until height) {
|
for (y <- 0 until height) {
|
||||||
@ -91,10 +95,19 @@ class ScreenWidget(screen: Screen) extends RootWidget with Logging {
|
|||||||
val Cell(char, bg, fg) = data(y * width + x)
|
val Cell(char, bg, fg) = data(y * width + x)
|
||||||
g.background = IntColor(bg)
|
g.background = IntColor(bg)
|
||||||
g.foreground = IntColor(fg)
|
g.foreground = IntColor(fg)
|
||||||
g.char(tx + x * fontSize / 2f, ty + y * fontSize, char)
|
g.char(x * fontSize / 2f + 16, y * fontSize + 16, char)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g.sprite("CornerTL", 0, 0, 16,16)
|
||||||
|
g.sprite("CornerTR", w - 16, 0, 16,16)
|
||||||
|
g.sprite("CornerBL", 0, h - 16, 16,16)
|
||||||
|
g.sprite("CornerBR", w - 16, h - 16, 16,16)
|
||||||
|
g.sprite("BorderH", 16, 0, w - 32, 16)
|
||||||
|
g.sprite("BorderH", 16, h - 16, w - 32, 16)
|
||||||
|
g.sprite("BorderV", 0, 16, 16, h - 32)
|
||||||
|
g.sprite("BorderV", w - 16, 16, 16, h - 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
def set(x: Int, y: Int, text: String, vertical: Boolean): Unit = {
|
def set(x: Int, y: Int, text: String, vertical: Boolean): Unit = {
|
||||||
|
|||||||
38
src/main/scala/ocelot/desktop/util/Spritesheet.scala
Normal file
38
src/main/scala/ocelot/desktop/util/Spritesheet.scala
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package ocelot.desktop.util
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
import ocelot.desktop.graphics.Texture
|
||||||
|
import org.apache.logging.log4j.scala.Logging
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
import scala.io.Source
|
||||||
|
|
||||||
|
object Spritesheet extends Logging {
|
||||||
|
val sprites = new mutable.HashMap[String, Rect]()
|
||||||
|
var texture: Texture = _
|
||||||
|
|
||||||
|
def load(): Unit = {
|
||||||
|
logger.info("Loading sprites")
|
||||||
|
|
||||||
|
val imageURL = getClass.getResource("/ocelot/desktop/spritesheet.png")
|
||||||
|
val image = ImageIO.read(imageURL)
|
||||||
|
texture = new Texture(image)
|
||||||
|
|
||||||
|
val txt = Source.fromURL(getClass.getResource("/ocelot/desktop/spritesheet.txt"))
|
||||||
|
|
||||||
|
for (line <- txt.getLines) {
|
||||||
|
val split = line.split("\\s+")
|
||||||
|
sprites += (split.head -> Rect(
|
||||||
|
split(1).toFloat / image.getWidth.toFloat,
|
||||||
|
split(2).toFloat / image.getHeight.toFloat,
|
||||||
|
split(3).toFloat / image.getWidth.toFloat,
|
||||||
|
split(4).toFloat / image.getHeight.toFloat
|
||||||
|
))
|
||||||
|
logger.info(s"${split.head} -> ${sprites(split.head)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
txt.close()
|
||||||
|
|
||||||
|
logger.info(s"Loaded ${sprites.size} sprites")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user