diff --git a/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala b/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala index b25316e19..edc7ce2dd 100644 --- a/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala +++ b/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala @@ -71,16 +71,40 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI DeviceAttribute.Clock -> clockInfo ) - def capacityInfo = (maxResolution._1 * maxResolution._2).toString + def capacityInfo: String = (maxResolution._1 * maxResolution._2).toString - def widthInfo = Array("1", "4", "8").apply(maxDepth.ordinal()) + def widthInfo: String = Array("1", "4", "8").apply(maxDepth.ordinal()) - def clockInfo = ((2000 / setBackgroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setForegroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setPaletteColorCosts(tier)).toInt / 100).toString + "/" + ((2000 / setCosts(tier)).toInt / 100).toString + "/" + ((2000 / copyCosts(tier)).toInt / 100).toString + "/" + ((2000 / fillCosts(tier)).toInt / 100).toString + def clockInfo: String = ((2000 / setBackgroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setForegroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setPaletteColorCosts(tier)).toInt / 100).toString + "/" + ((2000 / setCosts(tier)).toInt / 100).toString + "/" + ((2000 / copyCosts(tier)).toInt / 100).toString + "/" + ((2000 / fillCosts(tier)).toInt / 100).toString override def getDeviceInfo: util.Map[String, String] = deviceInfo // ----------------------------------------------------------------------- // + private def getViewportOverlapSize(s: api.internal.TextBuffer, x1: Int, y1: Int, x2: Int, y2: Int): Int = { + val width = s.getViewportWidth + val height = s.getViewportHeight + val left = math.min(x1, x2); + val right = math.max(x1, x2); + val top = math.min(y1, y2); + val bottom = math.max(y1, y2); + if (right < 0 || left >= width || top >= height || bottom < 0) + return 0 + val box_left = math.max(0, left) + val box_right = math.min(width - 1, right) + val box_top = math.max(0, top) + val box_bottom = math.min(height - 1, bottom) + (box_right - box_left + 1) * (box_bottom - box_top + 1) + } + + private def consumeViewportPower(overlap: Int, context: Context, budgetCost: Double, callFactor: Double): Boolean = { + if (overlap == 0) true + else { + context.consumeCallBudget(budgetCost) + consumePower(overlap, callFactor) + } + } + @Callback(doc = """function(address:string[, reset:boolean=true]):boolean -- Binds the GPU to the screen with the specified address and resets screen settings if `reset` is true.""") def bind(context: Context, args: Arguments): Array[AnyRef] = { val address = args.checkString(0) @@ -275,14 +299,16 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI @Callback(direct = true, doc = """function(x:number, y:number, value:string[, vertical:boolean]):boolean -- Plots a string value to the screen at the specified position. Optionally writes the string vertically.""") def set(context: Context, args: Arguments): Array[AnyRef] = { - context.consumeCallBudget(setCosts(tier)) val x = args.checkInteger(0) - 1 val y = args.checkInteger(1) - 1 val value = args.checkString(2) val vertical = args.optBoolean(3, false) screen(s => { - if (consumePower(value.length, Settings.get.gpuSetCost)) { + val x2 = if (vertical) x else x + value.length - 1 + val y2 = if (!vertical) y else y + value.length - 1 + val overlap: Int = getViewportOverlapSize(s, x, y, x2, y2) + if (consumeViewportPower(overlap, context, setCosts(tier), Settings.get.gpuSetCost)) { s.set(x, y, value, vertical) result(true) } @@ -292,7 +318,6 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI @Callback(direct = true, doc = """function(x:number, y:number, width:number, height:number, tx:number, ty:number):boolean -- Copies a portion of the screen from the specified location with the specified size by the specified translation.""") def copy(context: Context, args: Arguments): Array[AnyRef] = { - context.consumeCallBudget(copyCosts(tier)) val x = args.checkInteger(0) - 1 val y = args.checkInteger(1) - 1 val w = math.max(0, args.checkInteger(2)) @@ -300,7 +325,8 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI val tx = args.checkInteger(4) val ty = args.checkInteger(5) screen(s => { - if (consumePower(w * h, Settings.get.gpuCopyCost)) { + val overlap: Int = getViewportOverlapSize(s, x + tx, y + ty, x + tx + w - 1, y + ty + h - 1) + if (consumeViewportPower(overlap, context, copyCosts(tier), Settings.get.gpuCopyCost)) { s.copy(x, y, w, h, tx, ty) result(true) } @@ -319,7 +345,8 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI if (value.length == 1) screen(s => { val c = value.charAt(0) val cost = if (c == ' ') Settings.get.gpuClearCost else Settings.get.gpuFillCost - if (consumePower(w * h, cost)) { + val overlap: Int = getViewportOverlapSize(s, x, y, x + w - 1, y + h - 1) + if (consumeViewportPower(overlap, context, fillCosts(tier), cost)) { s.fill(x, y, w, h, value.charAt(0)) result(true) }