-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Upgrade inspector with new capabilities and detached window mode. #86
base: master
Are you sure you want to change the base?
Changes from 1 commit
1fcdef0
7e8301a
02b582c
012beb2
8e27b32
bb8f2ed
893c315
3f64066
0c240f3
7a07184
5690908
310d21c
c0ed8bf
5ec4812
01f154f
a2af9c3
b271326
9f558ad
992bb3c
3251bfc
6e9ed17
4f140c7
e8b3232
e4f59a6
9b43b46
162dca0
b6230d8
c8e7628
1d3a98b
ee8bb8d
6540bc6
8aee863
3738cda
3d82fc9
8d13007
14c9285
6b173f5
35dbd0e
e08ca3a
cb0cf09
84b9714
69a7f19
900ef47
17b05ff
cc0d78d
6bb1042
74273d4
c327dd2
da79f0e
ee2d861
a86df75
65dea1d
dc71b4c
9f18e2b
420031b
84482b0
c499f13
92af06d
7ed0e6e
6706faf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,8 @@ import gg.essential.elementa.constraints.resolution.ConstraintResolverV2 | |
import gg.essential.elementa.effects.ScissorEffect | ||
import gg.essential.elementa.font.FontRenderer | ||
import gg.essential.elementa.impl.Platform.Companion.platform | ||
import gg.essential.elementa.manager.DefaultResolutionManager | ||
import gg.essential.elementa.manager.ResolutionManager | ||
import gg.essential.elementa.utils.elementaDev | ||
import gg.essential.elementa.utils.requireMainThread | ||
import gg.essential.universal.* | ||
|
@@ -37,6 +39,11 @@ class Window @JvmOverloads constructor( | |
|
||
internal var clickInterceptor: ((mouseX: Double, mouseY: Double, button: Int) -> Boolean)? = null | ||
|
||
/** | ||
* State managers to avoid global states | ||
*/ | ||
internal var resolutionManager: ResolutionManager = DefaultResolutionManager | ||
|
||
@Deprecated("Add ElementaVersion as the first argument to opt-in to improved behavior.") | ||
@JvmOverloads | ||
constructor(animationFPS: Int = 244) : this(ElementaVersion.v0, animationFPS) | ||
|
@@ -59,6 +66,7 @@ class Window @JvmOverloads constructor( | |
private fun doDraw(matrixStack: UMatrixStack) { | ||
if (cancelDrawing) | ||
return | ||
currentWindow.set(this) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This must be at the start of the |
||
|
||
requireMainThread() | ||
|
||
|
@@ -137,6 +145,7 @@ class Window @JvmOverloads constructor( | |
} | ||
} | ||
} | ||
currentWindow.set(null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This must be in a |
||
} | ||
|
||
internal fun drawEmbedded(matrixStack: UMatrixStack) { | ||
|
@@ -269,11 +278,11 @@ class Window @JvmOverloads constructor( | |
} | ||
|
||
override fun getWidth(): Float { | ||
return UResolution.scaledWidth.toFloat() | ||
return resolutionManager.scaledWidth.toFloat() | ||
} | ||
|
||
override fun getHeight(): Float { | ||
return UResolution.scaledHeight.toFloat() | ||
return resolutionManager.scaledHeight.toFloat() | ||
} | ||
|
||
override fun getRight() = getWidth() | ||
|
@@ -287,12 +296,12 @@ class Window @JvmOverloads constructor( | |
) return false | ||
|
||
val currentScissor = ScissorEffect.currentScissorState ?: return true | ||
val sf = UResolution.scaleFactor | ||
val sf = resolutionManager.scaleFactor | ||
|
||
val realX = currentScissor.x / sf | ||
val realWidth = currentScissor.width / sf | ||
|
||
val bottomY = ((UResolution.scaledHeight * sf) - currentScissor.y) / sf | ||
val bottomY = ((resolutionManager.scaledHeight * sf) - currentScissor.y) / sf | ||
val realHeight = currentScissor.height / sf | ||
|
||
return right > realX && | ||
|
@@ -368,6 +377,18 @@ class Window @JvmOverloads constructor( | |
companion object { | ||
private val renderOperations = ConcurrentLinkedQueue<() -> Unit>() | ||
|
||
/** | ||
* Instance of the Window currently being rendered | ||
*/ | ||
internal val currentWindow: ThreadLocal<Window?> = ThreadLocal.withInitial { null } | ||
|
||
/** | ||
* Resolution manager of the window currently being rendered or [DefaultResolutionManager] | ||
* if one cannot be resolved. | ||
*/ | ||
internal val resolutionManager: ResolutionManager | ||
get() = currentWindow.get()?.resolutionManager ?: DefaultResolutionManager | ||
|
||
fun enqueueRenderOperation(operation: Runnable) { | ||
renderOperations.add { | ||
operation.run() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
package gg.essential.elementa.effects | ||
|
||
import gg.essential.elementa.UIComponent | ||
import gg.essential.elementa.utils.resolutionManager | ||
import gg.essential.elementa.utils.roundToRealPixels | ||
import gg.essential.universal.UMatrixStack | ||
import gg.essential.universal.UResolution | ||
import org.lwjgl.opengl.GL11.* | ||
import kotlin.math.max | ||
import kotlin.math.min | ||
|
@@ -22,7 +22,8 @@ class ScissorEffect @JvmOverloads constructor( | |
private val scissorIntersection: Boolean = true | ||
) : Effect() { | ||
private var oldState: ScissorState? = null | ||
private var scissorBounds: ScissorBounds? = null | ||
private var unroundedScissorBounds: ScissorBounds? = null | ||
private var roundedScissorBounds: ScissorBounds? = null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. None of these need to be mutable and you don't need to manually handle initialization state tracking. |
||
|
||
/** | ||
* Create a custom bounding box using precise coordinates. | ||
|
@@ -35,17 +36,28 @@ class ScissorEffect @JvmOverloads constructor( | |
y2: Number, | ||
scissorIntersection: Boolean = true | ||
) : this(scissorIntersection = scissorIntersection) { | ||
scissorBounds = ScissorBounds( | ||
x1.toFloat().roundToRealPixels(), | ||
y1.toFloat().roundToRealPixels(), | ||
x2.toFloat().roundToRealPixels(), | ||
y2.toFloat().roundToRealPixels(), | ||
unroundedScissorBounds = ScissorBounds( | ||
x1.toFloat(), | ||
y1.toFloat(), | ||
x2.toFloat(), | ||
y2.toFloat(), | ||
) | ||
} | ||
|
||
override fun beforeDraw(matrixStack: UMatrixStack) { | ||
val bounds = customBoundingBox?.getScissorBounds() ?: scissorBounds ?: boundComponent.getScissorBounds() | ||
val scaleFactor = UResolution.scaleFactor.toInt() | ||
val unroundedScissorBounds = roundedScissorBounds | ||
if (unroundedScissorBounds !=null) { | ||
roundedScissorBounds = ScissorBounds( | ||
unroundedScissorBounds.x1.roundToRealPixels(boundComponent), | ||
unroundedScissorBounds.y1.roundToRealPixels(boundComponent), | ||
unroundedScissorBounds.x2.roundToRealPixels(boundComponent), | ||
unroundedScissorBounds.y2.roundToRealPixels(boundComponent), | ||
) | ||
this.unroundedScissorBounds = null | ||
} | ||
val bounds = customBoundingBox?.getScissorBounds() ?: roundedScissorBounds ?: boundComponent.getScissorBounds() | ||
val resolutionManager = boundComponent.resolutionManager | ||
val scaleFactor = resolutionManager.scaleFactor.toInt() | ||
|
||
if (currentScissorState == null) { | ||
glEnable(GL_SCISSOR_TEST) | ||
|
@@ -57,7 +69,7 @@ class ScissorEffect @JvmOverloads constructor( | |
// TODO ideally we should respect matrixStack offset and maybe scale, though we do not currently care about | ||
// global gl state either, so not really important until someone needs it | ||
var x = (bounds.x1 * scaleFactor).roundToInt() | ||
var y = UResolution.viewportHeight - (bounds.y2 * scaleFactor).roundToInt() | ||
var y = resolutionManager.viewportHeight - (bounds.y2 * scaleFactor).roundToInt() | ||
var width = (bounds.width * scaleFactor).roundToInt() | ||
var height = (bounds.height * scaleFactor).roundToInt() | ||
|
||
|
@@ -96,10 +108,10 @@ class ScissorEffect @JvmOverloads constructor( | |
} | ||
|
||
private fun UIComponent.getScissorBounds(): ScissorBounds = ScissorBounds( | ||
getLeft().roundToRealPixels(), | ||
getTop().roundToRealPixels(), | ||
getRight().roundToRealPixels(), | ||
getBottom().roundToRealPixels(), | ||
getLeft().roundToRealPixels(this), | ||
getTop().roundToRealPixels(this), | ||
getRight().roundToRealPixels(this), | ||
getBottom().roundToRealPixels(this), | ||
) | ||
|
||
data class ScissorState(val x: Int, val y: Int, val width: Int, val height: Int) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package gg.essential.elementa.manager | ||
|
||
import gg.essential.universal.UResolution | ||
|
||
/** | ||
* A resolution manager that provides its values from [UResolution]. | ||
*/ | ||
internal object DefaultResolutionManager : ResolutionManager { | ||
|
||
override val windowWidth: Int | ||
get() = UResolution.windowWidth | ||
|
||
override val windowHeight: Int | ||
get() = UResolution.windowHeight | ||
|
||
override val viewportWidth: Int | ||
get() = UResolution.viewportWidth | ||
|
||
override val viewportHeight: Int | ||
get() = UResolution.viewportHeight | ||
|
||
override val scaledWidth: Int | ||
get() = UResolution.scaledWidth | ||
|
||
override val scaledHeight: Int | ||
get() = UResolution.scaledHeight | ||
|
||
override val scaleFactor: Double | ||
get() = UResolution.scaleFactor | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package gg.essential.elementa.manager | ||
|
||
|
||
/** | ||
* Provides a non-global way to access different aspects about the current resolution | ||
*/ | ||
internal interface ResolutionManager { | ||
|
||
val windowWidth: Int | ||
|
||
val windowHeight: Int | ||
|
||
val viewportWidth: Int | ||
|
||
val viewportHeight: Int | ||
|
||
val scaledWidth: Int | ||
|
||
val scaledHeight: Int | ||
|
||
val scaleFactor: Double | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've said this before but I guess I'll have to repeat myself:
I don't think we should at this point deprecate this method (as well as the
roundToRealPixel
ones) because Kotlin's context receiver feature may make the new methods way more ergonomic to use than they currently are, and therefore I don't think we should at this point lock them into the API (and we don't need to anyway because atm the whole resolution manager thing is only used by the inspector, not by any API user).Don't delete the line though, just comment it out. We will probably need it at some point, and this way it already serves as a hint for internal usages.