118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
package world
|
|
|
|
// ClampCameraNoWrapViewport clamps camera center so that the VIEWPORT world-rect
|
|
// stays within the bounded world [0..worldW) x [0..worldH), when possible.
|
|
//
|
|
// This is the correct clamp for user panning when wrap is disabled.
|
|
// Margins (expanded canvas) are intentionally ignored here; they may extend outside the world.
|
|
func ClampCameraNoWrapViewport(
|
|
cameraXWorldFp, cameraYWorldFp int,
|
|
viewportW, viewportH int,
|
|
zoomFp int,
|
|
worldW, worldH int,
|
|
) (int, int) {
|
|
if zoomFp <= 0 {
|
|
panic("ClampCameraNoWrapViewport: invalid zoom")
|
|
}
|
|
if viewportW < 0 || viewportH < 0 {
|
|
panic("ClampCameraNoWrapViewport: negative viewport")
|
|
}
|
|
if worldW <= 0 || worldH <= 0 {
|
|
panic("ClampCameraNoWrapViewport: invalid world size")
|
|
}
|
|
|
|
spanW := PixelSpanToWorldFixed(viewportW, zoomFp)
|
|
spanH := PixelSpanToWorldFixed(viewportH, zoomFp)
|
|
|
|
halfW := spanW / 2
|
|
halfH := spanH / 2
|
|
|
|
cameraXWorldFp = clampCameraAxis(cameraXWorldFp, worldW, halfW)
|
|
cameraYWorldFp = clampCameraAxis(cameraYWorldFp, worldH, halfH)
|
|
|
|
return cameraXWorldFp, cameraYWorldFp
|
|
}
|
|
|
|
// ClampCameraNoWrapExpanded clamps camera center so that the EXPANDED CANVAS world-rect
|
|
// (viewport + margins) stays within the bounded world, when possible.
|
|
//
|
|
// This is stricter than viewport-based clamp and can prevent panning when margins are large.
|
|
func ClampCameraNoWrapExpanded(
|
|
cameraXWorldFp, cameraYWorldFp int,
|
|
viewportW, viewportH int,
|
|
marginX, marginY int,
|
|
zoomFp int,
|
|
worldW, worldH int,
|
|
) (int, int) {
|
|
if zoomFp <= 0 {
|
|
panic("ClampCameraNoWrapExpanded: invalid zoom")
|
|
}
|
|
if viewportW < 0 || viewportH < 0 || marginX < 0 || marginY < 0 {
|
|
panic("ClampCameraNoWrapExpanded: negative sizes")
|
|
}
|
|
if worldW <= 0 || worldH <= 0 {
|
|
panic("ClampCameraNoWrapExpanded: invalid world size")
|
|
}
|
|
|
|
canvasW := viewportW + 2*marginX
|
|
canvasH := viewportH + 2*marginY
|
|
|
|
spanW := PixelSpanToWorldFixed(canvasW, zoomFp)
|
|
spanH := PixelSpanToWorldFixed(canvasH, zoomFp)
|
|
|
|
halfW := spanW / 2
|
|
halfH := spanH / 2
|
|
|
|
cameraXWorldFp = clampCameraAxis(cameraXWorldFp, worldW, halfW)
|
|
cameraYWorldFp = clampCameraAxis(cameraYWorldFp, worldH, halfH)
|
|
|
|
return cameraXWorldFp, cameraYWorldFp
|
|
}
|
|
|
|
func clampCameraAxis(cam, worldSize, halfSpan int) int {
|
|
// If viewport/span does not fit: force center.
|
|
if 2*halfSpan > worldSize {
|
|
return worldSize / 2
|
|
}
|
|
|
|
minCam := halfSpan
|
|
maxCam := worldSize - halfSpan
|
|
|
|
if cam < minCam {
|
|
return minCam
|
|
}
|
|
if cam > maxCam {
|
|
return maxCam
|
|
}
|
|
return cam
|
|
}
|
|
|
|
// ClampRenderParamsNoWrap clamps camera center in-place when wrap is disabled.
|
|
// It uses viewport-based clamp (NOT expanded) so panning remains possible even with margins.
|
|
func (w *World) ClampRenderParamsNoWrap(p *RenderParams) {
|
|
if p == nil {
|
|
return
|
|
}
|
|
allowWrap := true
|
|
if p.Options != nil && p.Options.DisableWrapScroll {
|
|
allowWrap = false
|
|
}
|
|
if allowWrap {
|
|
return
|
|
}
|
|
|
|
zoomFp, err := p.CameraZoomFp()
|
|
if err != nil || zoomFp <= 0 {
|
|
return
|
|
}
|
|
|
|
cx, cy := ClampCameraNoWrapViewport(
|
|
p.CameraXWorldFp, p.CameraYWorldFp,
|
|
p.ViewportWidthPx, p.ViewportHeightPx,
|
|
zoomFp,
|
|
w.W, w.H,
|
|
)
|
|
p.CameraXWorldFp = cx
|
|
p.CameraYWorldFp = cy
|
|
}
|