mirror of
https://gitlab.com/cc-ru/ocelot/ocelot-desktop.git
synced 2025-12-20 02:59:19 +01:00
Refactor and unify particle system
This commit is contained in:
parent
b248c4beeb
commit
c510cbb834
@ -1,9 +1,7 @@
|
|||||||
package ocelot.desktop.node
|
package ocelot.desktop.node
|
||||||
|
|
||||||
import ocelot.desktop.OcelotDesktop
|
import ocelot.desktop.{ColorScheme, OcelotDesktop, Settings => DesktopSettings}
|
||||||
import ocelot.desktop.{Settings => DesktopSettings}
|
|
||||||
import ocelot.desktop.audio._
|
import ocelot.desktop.audio._
|
||||||
import ocelot.desktop.geometry.Vector2D
|
|
||||||
import ocelot.desktop.graphics.{Graphics, IconSource}
|
import ocelot.desktop.graphics.{Graphics, IconSource}
|
||||||
import ocelot.desktop.inventory.SyncedInventory
|
import ocelot.desktop.inventory.SyncedInventory
|
||||||
import ocelot.desktop.node.ComputerAwareNode._
|
import ocelot.desktop.node.ComputerAwareNode._
|
||||||
@ -11,14 +9,13 @@ import ocelot.desktop.node.Node.Size
|
|||||||
import ocelot.desktop.ui.UiHandler
|
import ocelot.desktop.ui.UiHandler
|
||||||
import ocelot.desktop.ui.event.BrainEvent
|
import ocelot.desktop.ui.event.BrainEvent
|
||||||
import ocelot.desktop.ui.event.handlers.DiskActivityHandler
|
import ocelot.desktop.ui.event.handlers.DiskActivityHandler
|
||||||
import ocelot.desktop.ui.widget.ComputerErrorMessageLabel
|
import ocelot.desktop.ui.particle.Particle
|
||||||
import ocelot.desktop.util.Messages
|
import ocelot.desktop.util.Messages
|
||||||
import totoro.ocelot.brain.Settings
|
import totoro.ocelot.brain.Settings
|
||||||
import totoro.ocelot.brain.entity.traits.{Entity, Environment, WorkspaceAware}
|
import totoro.ocelot.brain.entity.traits.{Entity, Environment, WorkspaceAware}
|
||||||
import totoro.ocelot.brain.event._
|
import totoro.ocelot.brain.event._
|
||||||
|
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import scala.collection.mutable.ArrayBuffer
|
|
||||||
|
|
||||||
abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceAware)
|
abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceAware)
|
||||||
extends EntityNode(entity)
|
extends EntityNode(entity)
|
||||||
@ -27,13 +24,6 @@ abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceA
|
|||||||
with OcelotLogParticleNode
|
with OcelotLogParticleNode
|
||||||
with ShiftClickNode {
|
with ShiftClickNode {
|
||||||
|
|
||||||
// access should be synchronized because messages are added in the update thread
|
|
||||||
private val messages = ArrayBuffer.empty[(Float, ComputerErrorMessageLabel)]
|
|
||||||
|
|
||||||
private def addErrorMessage(message: ComputerErrorMessageLabel): Unit = messages.synchronized {
|
|
||||||
messages += ((0f, message))
|
|
||||||
}
|
|
||||||
|
|
||||||
private lazy val soundCardSounds: (SoundStream, SoundSource) = Audio.newStream(SoundCategory.Records)
|
private lazy val soundCardSounds: (SoundStream, SoundSource) = Audio.newStream(SoundCategory.Records)
|
||||||
private def soundCardStream: SoundStream = soundCardSounds._1
|
private def soundCardStream: SoundStream = soundCardSounds._1
|
||||||
private def soundCardSource: SoundSource = soundCardSounds._2
|
private def soundCardSource: SoundSource = soundCardSounds._2
|
||||||
@ -44,13 +34,11 @@ abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceA
|
|||||||
case Some(message) =>
|
case Some(message) =>
|
||||||
logger.info(s"[EVENT] Machine crash (address = ${event.address})! Message code ${event.message}: $message")
|
logger.info(s"[EVENT] Machine crash (address = ${event.address})! Message code ${event.message}: $message")
|
||||||
message
|
message
|
||||||
|
|
||||||
case None =>
|
case None =>
|
||||||
logger.info(s"[EVENT] Machine crash (address = ${event.address})! Message: ${event.message}")
|
logger.info(s"[EVENT] Machine crash (address = ${event.address})! Message: ${event.message}")
|
||||||
event.message
|
event.message
|
||||||
}
|
}
|
||||||
|
UiHandler.root.workspaceView.particleSystem.add(new ErrorMessageParticle(message))
|
||||||
addErrorMessage(new ComputerErrorMessageLabel(this, message))
|
|
||||||
|
|
||||||
case BrainEvent(event: BeepEvent) if !Audio.isDisabled =>
|
case BrainEvent(event: BeepEvent) if !Audio.isDisabled =>
|
||||||
BeepGenerator.newBeep(".", event.frequency, event.duration).play()
|
BeepGenerator.newBeep(".", event.frequency, event.duration).play()
|
||||||
@ -70,28 +58,6 @@ abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceA
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override def update(): Unit = {
|
|
||||||
messages.synchronized {
|
|
||||||
messages.mapInPlace { case (t, message) => (t + ErrorMessageMoveSpeed * UiHandler.dt, message) }
|
|
||||||
messages.filterInPlace(_._1 <= 1f)
|
|
||||||
}
|
|
||||||
|
|
||||||
super.update()
|
|
||||||
}
|
|
||||||
|
|
||||||
private def drawMessageParticles(g: Graphics): Unit = messages.synchronized {
|
|
||||||
for ((time, message) <- messages.reverseIterator) {
|
|
||||||
message.position = message.initialPosition + Vector2D(0, -MaxErrorMessageDistance * time)
|
|
||||||
message.alpha = 1 - time
|
|
||||||
message.draw(g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override def drawParticles(g: Graphics): Unit = {
|
|
||||||
super.drawParticles(g)
|
|
||||||
drawMessageParticles(g)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def drawOverlay(g: Graphics): Unit = HolidayIcon match {
|
protected def drawOverlay(g: Graphics): Unit = HolidayIcon match {
|
||||||
case Some(icon) if DesktopSettings.get.enableFestiveDecorations =>
|
case Some(icon) if DesktopSettings.get.enableFestiveDecorations =>
|
||||||
val holidayOverlaySize = Size * 1.6f
|
val holidayOverlaySize = Size * 1.6f
|
||||||
@ -110,9 +76,22 @@ abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceA
|
|||||||
|
|
||||||
override def draw(g: Graphics): Unit = {
|
override def draw(g: Graphics): Unit = {
|
||||||
super.draw(g)
|
super.draw(g)
|
||||||
|
|
||||||
drawOverlay(g)
|
drawOverlay(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ErrorMessageParticle(message: String) extends Particle {
|
||||||
|
private val offsetX = size.width / 2 - message.length * 4
|
||||||
|
private val offsetY = -8
|
||||||
|
override def update(dt: Float): Unit = {
|
||||||
|
time += ErrorMessageMoveSpeed * dt
|
||||||
|
}
|
||||||
|
override def draw(g: Graphics): Unit = {
|
||||||
|
g.setSmallFont()
|
||||||
|
g.foreground = ColorScheme("ErrorMessage").withAlpha(1 - (2 * time - 1).min(1).max(0))
|
||||||
|
g.text(position.x + offsetX, position.y + offsetY - MaxErrorMessageDistance * time, message)
|
||||||
|
g.setNormalFont()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ComputerAwareNode {
|
object ComputerAwareNode {
|
||||||
|
|||||||
@ -297,8 +297,6 @@ abstract class Node extends Widget with MouseHandler with HoverHandler with Pers
|
|||||||
drawPortLegend(g)
|
drawPortLegend(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
def drawParticles(g: Graphics): Unit = {}
|
|
||||||
|
|
||||||
def drawPorts(g: Graphics): Unit = {
|
def drawPorts(g: Graphics): Unit = {
|
||||||
for ((port, rects) <- portsBounds) {
|
for ((port, rects) <- portsBounds) {
|
||||||
val color = port.getColor
|
val color = port.getColor
|
||||||
|
|||||||
@ -8,62 +8,41 @@ import ocelot.desktop.graphics.Graphics
|
|||||||
import ocelot.desktop.node.OcelotLogParticleNode._
|
import ocelot.desktop.node.OcelotLogParticleNode._
|
||||||
import ocelot.desktop.ui.UiHandler
|
import ocelot.desktop.ui.UiHandler
|
||||||
import ocelot.desktop.ui.event.BrainEvent
|
import ocelot.desktop.ui.event.BrainEvent
|
||||||
|
import ocelot.desktop.ui.particle.Particle
|
||||||
|
|
||||||
import scala.collection.mutable
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
trait OcelotLogParticleNode extends Node {
|
trait OcelotLogParticleNode extends Node {
|
||||||
private case class LogParticle(
|
|
||||||
var time: Float = -LogParticleGrow,
|
|
||||||
angle: Float = Random.between(0f, 2 * math.Pi.toFloat * LogParticleMaxAngle),
|
|
||||||
)
|
|
||||||
|
|
||||||
// access should be synchronized because log particles are added in the update thread
|
|
||||||
private val logParticles = mutable.ArrayDeque.empty[LogParticle]
|
|
||||||
|
|
||||||
private def addLogParticle(): Unit = logParticles.synchronized {
|
|
||||||
if (logParticles.length < MaxLogParticles) {
|
|
||||||
logParticles += LogParticle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case BrainEvent(OcelotInterface.LogEvent.CardToUser(_, _)) =>
|
case BrainEvent(OcelotInterface.LogEvent.CardToUser(_, _)) =>
|
||||||
addLogParticle()
|
val system = UiHandler.root.workspaceView.particleSystem
|
||||||
|
if (system.count[LogParticle](Some(this)) < MaxLogParticles) {
|
||||||
|
system.add(new LogParticle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def update(): Unit = {
|
private class LogParticle extends Particle(-LogParticleGrow, origin = Some(this)) {
|
||||||
super.update()
|
private val angle: Float = Random.between(0f, 2 * math.Pi.toFloat * LogParticleMaxAngle)
|
||||||
|
override def update(dt: Float): Unit = {
|
||||||
logParticles.synchronized {
|
time += LogParticleMoveSpeed * dt
|
||||||
logParticles.foreach(particle => particle.time += LogParticleMoveSpeed * UiHandler.dt)
|
|
||||||
logParticles.filterInPlace(_.time <= 1f)
|
|
||||||
}
|
}
|
||||||
}
|
override def draw(g: Graphics): Unit = {
|
||||||
|
val size = (1 + time / LogParticleGrow).clamp() * LogParticleSize
|
||||||
private def drawLogParticles(g: Graphics): Unit = logParticles.synchronized {
|
val offset = time.clamp() * LogParticleMoveDistance
|
||||||
for (particle <- logParticles) {
|
val alpha = 1 - time.clamp()
|
||||||
val size = (1 + particle.time / LogParticleGrow).clamp() * LogParticleSize
|
|
||||||
val offset = particle.time.clamp() * LogParticleMoveDistance
|
|
||||||
val alpha = 1 - particle.time.clamp()
|
|
||||||
|
|
||||||
val r1 = (bounds.w max bounds.h) / math.sqrt(2) + offset + LogParticlePadding
|
val r1 = (bounds.w max bounds.h) / math.sqrt(2) + offset + LogParticlePadding
|
||||||
val r2 = r1 + size
|
val r2 = r1 + size
|
||||||
|
|
||||||
for (i <- 0 until LogParticleCount) {
|
for (i <- 0 until LogParticleCount) {
|
||||||
val angle = particle.angle + (2 * math.Pi).toFloat * i / LogParticleCount
|
val a = angle + (2 * math.Pi).toFloat * i / LogParticleCount
|
||||||
val v = Vector2D.unit(angle)
|
val v = Vector2D.unit(a)
|
||||||
val p1 = v * r1 + bounds.center
|
val p1 = v * r1 + bounds.center
|
||||||
val p2 = v * r2 + bounds.center
|
val p2 = v * r2 + bounds.center
|
||||||
g.line(p1, p2, 1f, ColorScheme("LogParticle").mapA(_ => alpha))
|
g.line(p1, p2, 1f, ColorScheme("LogParticle").mapA(_ => alpha))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def drawParticles(g: Graphics): Unit = {
|
|
||||||
super.drawParticles(g)
|
|
||||||
drawLogParticles(g)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object OcelotLogParticleNode {
|
object OcelotLogParticleNode {
|
||||||
|
|||||||
@ -7,11 +7,10 @@ import ocelot.desktop.graphics.Graphics
|
|||||||
import ocelot.desktop.node.{EntityNode, LabeledEntityNode}
|
import ocelot.desktop.node.{EntityNode, LabeledEntityNode}
|
||||||
import ocelot.desktop.ui.UiHandler
|
import ocelot.desktop.ui.UiHandler
|
||||||
import ocelot.desktop.ui.event.BrainEvent
|
import ocelot.desktop.ui.event.BrainEvent
|
||||||
|
import ocelot.desktop.ui.particle.Particle
|
||||||
import totoro.ocelot.brain.entity.traits.{Entity, Environment}
|
import totoro.ocelot.brain.entity.traits.{Entity, Environment}
|
||||||
import totoro.ocelot.brain.event.NoteBlockTriggerEvent
|
import totoro.ocelot.brain.event.NoteBlockTriggerEvent
|
||||||
|
|
||||||
import scala.collection.mutable
|
|
||||||
|
|
||||||
abstract class NoteBlockNodeBase(entity: Entity with Environment) extends EntityNode(entity) with LabeledEntityNode {
|
abstract class NoteBlockNodeBase(entity: Entity with Environment) extends EntityNode(entity) with LabeledEntityNode {
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case BrainEvent(event: NoteBlockTriggerEvent) =>
|
case BrainEvent(event: NoteBlockTriggerEvent) =>
|
||||||
@ -22,31 +21,24 @@ abstract class NoteBlockNodeBase(entity: Entity with Environment) extends Entity
|
|||||||
volume = event.volume.toFloat.min(1f).max(0f),
|
volume = event.volume.toFloat.min(1f).max(0f),
|
||||||
).play()
|
).play()
|
||||||
|
|
||||||
addParticle(event.pitch)
|
UiHandler.root.workspaceView.particleSystem.add(new NoteParticle(event.pitch))
|
||||||
}
|
|
||||||
|
|
||||||
private val particles = mutable.ArrayBuffer[(Float, Int)]()
|
|
||||||
|
|
||||||
private def addParticle(pitch: Int): Unit = {
|
|
||||||
synchronized {
|
|
||||||
particles += ((0f, pitch))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override def drawParticles(g: Graphics): Unit = synchronized {
|
|
||||||
for ((time, pitch) <- particles.reverseIterator) {
|
|
||||||
val col = ColorScheme("Note" + pitch.min(24).max(0)).withAlpha(1 - (2 * time - 1).min(1).max(0))
|
|
||||||
g.sprite("particles/Note", position + Vector2D(pitch / 24f * 40f + 5, height / 2 - 10 - 100 * time),
|
|
||||||
Size2D(14, 20), col)
|
|
||||||
}
|
|
||||||
particles.mapInPlace { case (t, p) => (t + 1.2f * UiHandler.dt, p) }
|
|
||||||
particles.filterInPlace(_._1 <= 1f)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override def update(): Unit = {
|
override def update(): Unit = {
|
||||||
super.update()
|
super.update()
|
||||||
|
if (isHovered || isMoving) {
|
||||||
if (isHovered || isMoving)
|
|
||||||
root.get.statusBar.addMouseEntry("icons/LMB", "Play sample")
|
root.get.statusBar.addMouseEntry("icons/LMB", "Play sample")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NoteParticle(pitch: Int) extends Particle {
|
||||||
|
override def update(dt: Float): Unit = {
|
||||||
|
time += 1.2f * UiHandler.dt
|
||||||
|
}
|
||||||
|
override def draw(g: Graphics): Unit = {
|
||||||
|
val col = ColorScheme("Note" + pitch.min(24).max(0)).withAlpha(1 - (2 * time - 1).min(1).max(0))
|
||||||
|
g.sprite("particles/Note", position + Vector2D(pitch / 24f * 40f + 5, height / 2 - 10 - 100 * time),
|
||||||
|
Size2D(14, 20), col)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/main/scala/ocelot/desktop/ui/particle/Particle.scala
Normal file
25
src/main/scala/ocelot/desktop/ui/particle/Particle.scala
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package ocelot.desktop.ui.particle
|
||||||
|
|
||||||
|
import ocelot.desktop.graphics.Graphics
|
||||||
|
import ocelot.desktop.ui.widget.Widget
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Everything a single particle needs to live and thrive.
|
||||||
|
* @param time current lifetime of the particle
|
||||||
|
* @param ttl when the `time` will reach this value - the particle is going to be discarded
|
||||||
|
* @param origin optional, marks the widget that "spawned" this particle
|
||||||
|
*/
|
||||||
|
|
||||||
|
case class Particle(
|
||||||
|
var time: Float = 0.0f,
|
||||||
|
var ttl: Float = 1.0f,
|
||||||
|
origin: Option[Widget] = None,
|
||||||
|
) {
|
||||||
|
def expired: Boolean = time >= ttl
|
||||||
|
|
||||||
|
def update(dt: Float): Unit = {
|
||||||
|
time += dt
|
||||||
|
}
|
||||||
|
|
||||||
|
def draw(g: Graphics): Unit = {}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package ocelot.desktop.ui.particle
|
||||||
|
|
||||||
|
import ocelot.desktop.graphics.Graphics
|
||||||
|
import ocelot.desktop.ui.widget.Widget
|
||||||
|
|
||||||
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
|
class ParticleSystem {
|
||||||
|
private val particles: ListBuffer[Particle] = ListBuffer.empty
|
||||||
|
|
||||||
|
def add(particle: Particle): Unit = particles.addOne(particle)
|
||||||
|
|
||||||
|
def count[A](origin: Option[Widget]): Int = particles.count(p => p.isInstanceOf[A] && p.origin == origin)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls `update` method on all particles, advances time.
|
||||||
|
* Removes expired particles.
|
||||||
|
* @param dt delta time
|
||||||
|
*/
|
||||||
|
def update(dt: Float): Unit = {
|
||||||
|
particles.foreach(_.update(dt))
|
||||||
|
particles.filterInPlace(!_.expired)
|
||||||
|
}
|
||||||
|
|
||||||
|
def draw(g: Graphics): Unit = {
|
||||||
|
particles.foreach(_.draw(g))
|
||||||
|
}
|
||||||
|
|
||||||
|
def clear(): Unit = {
|
||||||
|
particles.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,23 +0,0 @@
|
|||||||
package ocelot.desktop.ui.widget
|
|
||||||
|
|
||||||
import ocelot.desktop.ColorScheme
|
|
||||||
import ocelot.desktop.color.Color
|
|
||||||
import ocelot.desktop.geometry.Vector2D
|
|
||||||
import ocelot.desktop.node.Node
|
|
||||||
|
|
||||||
class ComputerErrorMessageLabel(node: Node, override val text: String) extends Label {
|
|
||||||
override def isSmall: Boolean = true
|
|
||||||
|
|
||||||
var alpha: Float = 1f
|
|
||||||
|
|
||||||
override def color: Color = ColorScheme("ErrorMessage").toRGBANorm.mapA(_ * alpha)
|
|
||||||
|
|
||||||
val initialPosition: Vector2D = {
|
|
||||||
val position = node.position
|
|
||||||
val size = node.size
|
|
||||||
|
|
||||||
position + Vector2D(size.width / 2 - minimumSize.width / 2, -minimumSize.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
position = initialPosition
|
|
||||||
}
|
|
||||||
@ -6,10 +6,12 @@ import ocelot.desktop.graphics.{Graphics, IconSource}
|
|||||||
import ocelot.desktop.node.Node.Size
|
import ocelot.desktop.node.Node.Size
|
||||||
import ocelot.desktop.node.nodes.{ComputerNode, ScreenNode}
|
import ocelot.desktop.node.nodes.{ComputerNode, ScreenNode}
|
||||||
import ocelot.desktop.node.{EntityNode, Node, NodePort}
|
import ocelot.desktop.node.{EntityNode, Node, NodePort}
|
||||||
|
import ocelot.desktop.ui.UiHandler
|
||||||
import ocelot.desktop.ui.event._
|
import ocelot.desktop.ui.event._
|
||||||
import ocelot.desktop.ui.event.handlers.{HoverHandler, MouseHandler}
|
import ocelot.desktop.ui.event.handlers.{HoverHandler, MouseHandler}
|
||||||
import ocelot.desktop.ui.event.sources.KeyEvents
|
import ocelot.desktop.ui.event.sources.KeyEvents
|
||||||
import ocelot.desktop.ui.layout.{CopyLayout, Layout}
|
import ocelot.desktop.ui.layout.{CopyLayout, Layout}
|
||||||
|
import ocelot.desktop.ui.particle.ParticleSystem
|
||||||
import ocelot.desktop.ui.widget.WorkspaceView.NodeLoadException
|
import ocelot.desktop.ui.widget.WorkspaceView.NodeLoadException
|
||||||
import ocelot.desktop.ui.widget.window.{NodeSelector, ProfilerWindow, WindowPool}
|
import ocelot.desktop.ui.widget.window.{NodeSelector, ProfilerWindow, WindowPool}
|
||||||
import ocelot.desktop.util.Keybind.{Center, Profiler}
|
import ocelot.desktop.util.Keybind.{Center, Profiler}
|
||||||
@ -34,6 +36,7 @@ class WorkspaceView extends Widget with Persistable with MouseHandler with Hover
|
|||||||
@volatile
|
@volatile
|
||||||
var nodes: immutable.Seq[Node] = immutable.ArraySeq[Node]()
|
var nodes: immutable.Seq[Node] = immutable.ArraySeq[Node]()
|
||||||
|
|
||||||
|
var particleSystem = new ParticleSystem
|
||||||
var windowPool = new WindowPool
|
var windowPool = new WindowPool
|
||||||
var nodeSelector = new NodeSelector
|
var nodeSelector = new NodeSelector
|
||||||
var profilerWindow = new ProfilerWindow
|
var profilerWindow = new ProfilerWindow
|
||||||
@ -65,6 +68,7 @@ class WorkspaceView extends Widget with Persistable with MouseHandler with Hover
|
|||||||
def reset(): Unit = {
|
def reset(): Unit = {
|
||||||
nodes.foreach(_.dispose())
|
nodes.foreach(_.dispose())
|
||||||
nodes = nodes.empty
|
nodes = nodes.empty
|
||||||
|
particleSystem.clear()
|
||||||
windowPool.deleteAllWindows()
|
windowPool.deleteAllWindows()
|
||||||
nodeSelector = new NodeSelector
|
nodeSelector = new NodeSelector
|
||||||
profilerWindow = new ProfilerWindow
|
profilerWindow = new ProfilerWindow
|
||||||
@ -458,7 +462,7 @@ class WorkspaceView extends Widget with Persistable with MouseHandler with Hover
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def newConnectionTarget: Option[(Node, NodePort)] = newConnection flatMap { case (node, _, endpoint) =>
|
private def newConnectionTarget: Option[(Node, NodePort)] = newConnection flatMap { case (node, _, endpoint) =>
|
||||||
val validTargets = {
|
val validTargets = {
|
||||||
nodes.iterator
|
nodes.iterator
|
||||||
.filter(_ != node)
|
.filter(_ != node)
|
||||||
@ -607,7 +611,6 @@ class WorkspaceView extends Widget with Persistable with MouseHandler with Hover
|
|||||||
nodes.foreach(_.draw(g))
|
nodes.foreach(_.draw(g))
|
||||||
nodes.foreach(_.drawLight(g))
|
nodes.foreach(_.drawLight(g))
|
||||||
nodes.foreach(_.drawLabel(g))
|
nodes.foreach(_.drawLabel(g))
|
||||||
nodes.foreach(_.drawParticles(g))
|
|
||||||
|
|
||||||
portsAlpha.update()
|
portsAlpha.update()
|
||||||
portsAlpha.goto(if (newConnection.isDefined) 1 else 0)
|
portsAlpha.goto(if (newConnection.isDefined) 1 else 0)
|
||||||
@ -637,12 +640,15 @@ class WorkspaceView extends Widget with Persistable with MouseHandler with Hover
|
|||||||
drawSelectorConnection(g, Rect2D(newNodePos.x + cameraOffset.x, newNodePos.y + cameraOffset.y, 64, 64),
|
drawSelectorConnection(g, Rect2D(newNodePos.x + cameraOffset.x, newNodePos.y + cameraOffset.y, 64, 64),
|
||||||
nodeSelector.bounds, color = color)
|
nodeSelector.bounds, color = color)
|
||||||
|
|
||||||
|
particleSystem.draw(g)
|
||||||
|
|
||||||
drawChildren(g)
|
drawChildren(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def update(): Unit = {
|
override def update(): Unit = {
|
||||||
super.update()
|
super.update()
|
||||||
nodes.foreach(_.update())
|
nodes.foreach(_.update())
|
||||||
|
particleSystem.update(UiHandler.dt)
|
||||||
|
|
||||||
if (isHovered) {
|
if (isHovered) {
|
||||||
root.get.statusBar.addKeyEntry(Settings.get.keymap.name(Center), "Reset camera")
|
root.get.statusBar.addKeyEntry(Settings.get.keymap.name(Center), "Reset camera")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user