From 400add2d73cbf345a6de2550e888213dcd7aee4e Mon Sep 17 00:00:00 2001 From: Denis Bernard Date: Fri, 9 Mar 2018 10:02:41 +0100 Subject: [PATCH] Fix coordinate mapping in ScreenToGLCoords and GLToScreenCoords Fixes #64. --- mgl32/shapes.go | 21 +++++++++-------- mgl32/shapes_test.go | 54 ++++++++++++++++++++++++++++++++++++++++++ mgl64/shapes.go | 21 +++++++++-------- mgl64/shapes_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 20 deletions(-) create mode 100644 mgl32/shapes_test.go create mode 100644 mgl64/shapes_test.go diff --git a/mgl32/shapes.go b/mgl32/shapes.go index 65d0a94..5456872 100644 --- a/mgl32/shapes.go +++ b/mgl32/shapes.go @@ -263,29 +263,30 @@ func ReticulateSplines(ranges [][][2]float32, cPoints [][][]Vec2, withLlamas boo // Transform from pixel coordinates to GL coordinates. // // This assumes that your pixel coordinate system considers its origin to be in the top left corner (GL's is in the bottom left). -// The coordinates x and y may be out of the range [0,screenWidth] and [0,screeneHeight]. +// The coordinates x and y may be out of the range [0,screenWidth-1] and [0,screeneHeight-1]. // -// GL's coordinate system maps [screenWidth,0] to [1.0,1.0] and [0,screenHeight] to [-1.0,-1.0]. If x and y are out of the range, they'll still -// be mapped correctly, just off the screen. (e.g. if y = 2*screenHeight you'll get -2.0 for yOut) +// GL's coordinate system maps [screenWidth-1,0] to [1.0,1.0] and [0,screenHeight-1] to [-1.0,-1.0]. If x and y are out of the range, they'll still +// be mapped correctly, just off the screen. (e.g. if y = 2*(screenHeight-1) you'll get -3.0 for yOut) // // This is similar to Unproject, except for 2D cases and much simpler (especially since an inverse may always be found) func ScreenToGLCoords(x, y int, screenWidth, screenHeight int) (xOut, yOut float32) { - xOut = 2.0*float32(x)/float32(screenWidth) - 1.0 - yOut = -2.0*float32(y)/float32(screenHeight) + 1.0 + xOut = 2.0*float32(x)/float32(screenWidth-1) - 1.0 + yOut = -2.0*float32(y)/float32(screenHeight-1) + 1.0 return } -// Transform from GL's proportional system to pixel coordinates +// Transform from GL's proportional system to pixel coordinates. +// // Assumes the pixel coordinate system has its origin in the top left corner. (GL's is in the bottom left) // -// GL's coordinate system maps [screenWidth,0] to [1.0,1.0] and [0,screenHeight] to [-1.0,-1.0]. If x and y are out of the range, they'll still -// be mapped correctly, just off the screen. (e.g. if y=-2.0, you'll get 2*screenHeight for yOut) +// GL's coordinate system maps [screenWidth-1,0] to [1.0,1.0] and [0,screenHeight-1] to [-1.0,-1.0]. If x and y are out of the range, they'll still +// be mapped correctly, just off the screen. (e.g. if y=-3.0, you'll get 2*(screenHeight-1) for yOut) // // This is similar to Project, except for 2D cases and much simpler func GLToScreenCoords(x, y float32, screenWidth, screenHeight int) (xOut, yOut int) { - xOut = int((x + 1.0) * float32(screenWidth) / 2.0) - yOut = int((y - 1.0) * float32(screenHeight) / 2.0) + xOut = int((x + 1.0) * float32(screenWidth-1) / 2.0) + yOut = int((1.0 - y) * float32(screenHeight-1) / 2.0) return } diff --git a/mgl32/shapes_test.go b/mgl32/shapes_test.go new file mode 100644 index 0000000..8d43db9 --- /dev/null +++ b/mgl32/shapes_test.go @@ -0,0 +1,54 @@ +// Copyright 2018 The go-gl Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file.package mgl64_test + +package mgl32 + +import ( + "testing" +) + +func TestScreenToGLCoords(t *testing.T) { + // use a small screen size in order to minimize errors due to fp rounding. + const ( + sw = 100 + sh = 100 + ) + x, y := ScreenToGLCoords(0, sh-1, sw, sh) + if x != -1 { + t.Errorf("x = %f, expected -1.0", x) + } + if y != -1 { + t.Errorf("y = %f, expected -1.0", y) + } + + x, y = ScreenToGLCoords(sw-1, 0, sw, sh) + if x != 1 { + t.Errorf("x = %f, expected 1.0", x) + } + if y != 1 { + t.Errorf("y = %f, expected 1.0", y) + } +} + +func TestGLToScreenCoords(t *testing.T) { + const ( + sw = 100 + sh = 100 + ) + x, y := GLToScreenCoords(-1, -1, sw, sh) + if x != 0 { + t.Errorf("x = %d, expected 0", x) + } + if y != sh-1 { + t.Errorf("y = %d, expected %d", y, sh-1) + } + + x, y = GLToScreenCoords(1, 1, sw, sh) + if x != sw-1 { + t.Errorf("x = %d, expected %d", x, sw-1) + } + if y != 0 { + t.Errorf("y = %d, expected 0", y) + } +} diff --git a/mgl64/shapes.go b/mgl64/shapes.go index 07d8266..825746b 100644 --- a/mgl64/shapes.go +++ b/mgl64/shapes.go @@ -265,29 +265,30 @@ func ReticulateSplines(ranges [][][2]float64, cPoints [][][]Vec2, withLlamas boo // Transform from pixel coordinates to GL coordinates. // // This assumes that your pixel coordinate system considers its origin to be in the top left corner (GL's is in the bottom left). -// The coordinates x and y may be out of the range [0,screenWidth] and [0,screeneHeight]. +// The coordinates x and y may be out of the range [0,screenWidth-1] and [0,screeneHeight-1]. // -// GL's coordinate system maps [screenWidth,0] to [1.0,1.0] and [0,screenHeight] to [-1.0,-1.0]. If x and y are out of the range, they'll still -// be mapped correctly, just off the screen. (e.g. if y = 2*screenHeight you'll get -2.0 for yOut) +// GL's coordinate system maps [screenWidth-1,0] to [1.0,1.0] and [0,screenHeight-1] to [-1.0,-1.0]. If x and y are out of the range, they'll still +// be mapped correctly, just off the screen. (e.g. if y = 2*(screenHeight-1) you'll get -3.0 for yOut) // // This is similar to Unproject, except for 2D cases and much simpler (especially since an inverse may always be found) func ScreenToGLCoords(x, y int, screenWidth, screenHeight int) (xOut, yOut float64) { - xOut = 2.0*float64(x)/float64(screenWidth) - 1.0 - yOut = -2.0*float64(y)/float64(screenHeight) + 1.0 + xOut = 2.0*float64(x)/float64(screenWidth-1) - 1.0 + yOut = -2.0*float64(y)/float64(screenHeight-1) + 1.0 return } -// Transform from GL's proportional system to pixel coordinates +// Transform from GL's proportional system to pixel coordinates. +// // Assumes the pixel coordinate system has its origin in the top left corner. (GL's is in the bottom left) // -// GL's coordinate system maps [screenWidth,0] to [1.0,1.0] and [0,screenHeight] to [-1.0,-1.0]. If x and y are out of the range, they'll still -// be mapped correctly, just off the screen. (e.g. if y=-2.0, you'll get 2*screenHeight for yOut) +// GL's coordinate system maps [screenWidth-1,0] to [1.0,1.0] and [0,screenHeight-1] to [-1.0,-1.0]. If x and y are out of the range, they'll still +// be mapped correctly, just off the screen. (e.g. if y=-3.0, you'll get 2*(screenHeight-1) for yOut) // // This is similar to Project, except for 2D cases and much simpler func GLToScreenCoords(x, y float64, screenWidth, screenHeight int) (xOut, yOut int) { - xOut = int((x + 1.0) * float64(screenWidth) / 2.0) - yOut = int((y - 1.0) * float64(screenHeight) / 2.0) + xOut = int((x + 1.0) * float64(screenWidth-1) / 2.0) + yOut = int((1.0 - y) * float64(screenHeight-1) / 2.0) return } diff --git a/mgl64/shapes_test.go b/mgl64/shapes_test.go new file mode 100644 index 0000000..052b72f --- /dev/null +++ b/mgl64/shapes_test.go @@ -0,0 +1,56 @@ +// This file is generated from mgl32/shapes_test.go; DO NOT EDIT + +// Copyright 2018 The go-gl Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file.package mgl64_test + +package mgl64 + +import ( + "testing" +) + +func TestScreenToGLCoords(t *testing.T) { + // use a small screen size in order to minimize errors due to fp rounding. + const ( + sw = 100 + sh = 100 + ) + x, y := ScreenToGLCoords(0, sh-1, sw, sh) + if x != -1 { + t.Errorf("x = %f, expected -1.0", x) + } + if y != -1 { + t.Errorf("y = %f, expected -1.0", y) + } + + x, y = ScreenToGLCoords(sw-1, 0, sw, sh) + if x != 1 { + t.Errorf("x = %f, expected 1.0", x) + } + if y != 1 { + t.Errorf("y = %f, expected 1.0", y) + } +} + +func TestGLToScreenCoords(t *testing.T) { + const ( + sw = 100 + sh = 100 + ) + x, y := GLToScreenCoords(-1, -1, sw, sh) + if x != 0 { + t.Errorf("x = %d, expected 0", x) + } + if y != sh-1 { + t.Errorf("y = %d, expected %d", y, sh-1) + } + + x, y = GLToScreenCoords(1, 1, sw, sh) + if x != sw-1 { + t.Errorf("x = %d, expected %d", x, sw-1) + } + if y != 0 { + t.Errorf("y = %d, expected 0", y) + } +}