Display object can return ndc coordinates from a pixel coordinate box

This commit is contained in:
frank 2021-11-13 14:49:56 -05:00
parent 03d179eed4
commit 54cf01246b
7 changed files with 91 additions and 46 deletions

View File

@ -1,6 +1,6 @@
/* /\ +--------------------------------------------------------------+
____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
\ / / | copy, and modify without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - originally created at [http://nugget.fun] |
| ~~~~~~~~~~~~ | +--------------------------------------------------------------+
@ -10,33 +10,37 @@
#include "Box.hpp"
/* Construct a Box by giving a corner coordinate (top left in SDL coordinates, bottom left in GL coordinates)
* and size (as width, height). The gl argument indicates that the Y-coordinate increases from the bottom of
/* Construct a Box by giving a corner coordinate (top left if Y-axis is not inverted, bottom left otherwise) and
* size (as width, height). The invert_y argument indicates that the Y-coordinate increases from the bottom of
* the screen to the top rather than the default case where it increases from the top to the bottom. */
Box::Box(const glm::vec2& corner, const glm::vec2& size, bool use_gl_coordinates)
Box::Box(const glm::vec2& corner, const glm::vec2& size, bool invert_y)
{
x = corner.x;
y = corner.y;
w = size.x;
h = size.y;
gl(use_gl_coordinates);
this->invert_y(invert_y);
}
/* Construct a Box by passing an SDL_Rect struct, which is of the form {x, y, w, h} and limited to int arguments */
Box::Box(const SDL_Rect& rect, bool use_gl_coordinates) : Box({rect.x, rect.y}, {rect.w, rect.h}, use_gl_coordinates) {}
/* Construct a Box from float arguments: x, y, width, height. If invert_y is set, the Y-axis increases from bottom to
* top instead of top to bottom. */
Box::Box(float x, float y, float width, float height, bool invert_y) : Box({x, y}, {width, height}, invert_y) {}
/* Set GL mode to true, meaning the Y-coordinate increases from the bottom of the screen to the top, or false,
* meaning SDL mode where the Y-coordinate increases from the top of the screen to the bottom. */
void Box::gl(bool use_gl_coordinates)
/* Construct a Box by passing an SDL_Rect struct, which is of the form {x, y, w, h} and limited to int arguments. */
Box::Box(const SDL_Rect& rect, bool invert_y) : Box({rect.x, rect.y}, {rect.w, rect.h}, invert_y) {}
/* Set inverted Y mode to true, meaning the Y-coordinate increases from the bottom to the top, or false, meaning the
* Y-coordinate increases from the top to the bottom. */
void Box::invert_y(bool invert)
{
this->use_gl_coordinates = use_gl_coordinates;
invert_y_state = invert;
}
/* Returns true if GL coordinate mode was set, meaning the Y-coordinate increases from the bottom of the screen to
* the top, or false, meaning SDL mode where the Y-coordinate increases from the top of the screen to the bottom. */
bool Box::gl() const
/* Returns true if Y-axis was set to inverted, meaning the Y-coordinate increases from the bottom to the top, or false,
* meaning Y-coordinate increases from the top to the bottom. */
bool Box::inverted_y() const
{
return use_gl_coordinates;
return invert_y_state;
}
/* Return the width */
@ -98,7 +102,7 @@ float Box::area() const
float Box::top() const
{
/* if Y-coordinate increases from bottom to top, use the bottom to determine this value */
if (gl())
if (inverted_y())
{
return bottom() + height();
}
@ -119,7 +123,7 @@ float Box::right() const
float Box::bottom() const
{
/* if Y-coordinate increases from bottom to top, use the stored Y-coordinate */
if (gl())
if (inverted_y())
{
return y;
}
@ -146,7 +150,7 @@ float Box::cx() const
float Box::cy() const
{
/* if Y-coordinate increases from bottom to top, add from the bottom */
if (gl())
if (inverted_y())
{
return bottom() + height() / 2.0f;
}
@ -179,7 +183,7 @@ void Box::drag_top(float delta)
{
float new_location = top() + delta;
height(std::abs(bottom() - new_location));
if ((gl() && new_location < bottom()) || (!gl() && new_location > bottom()))
if ((inverted_y() && new_location < bottom()) || (!inverted_y() && new_location > bottom()))
{
bottom(new_location);
}
@ -239,7 +243,7 @@ void Box::drag_bottom(float delta)
{
float new_location = bottom() + delta;
height(std::abs(top() - new_location));
if ((gl() && new_location > top()) || (!gl() && new_location < bottom()))
if ((inverted_y() && new_location > top()) || (!inverted_y() && new_location < bottom()))
{
top(new_location);
}
@ -477,9 +481,9 @@ bool Box::fits(const Box& container) const
{
return
!(
((gl() && top() > container.top()) || (!gl() && top() < container.top())) ||
((inverted_y() && top() > container.top()) || (!inverted_y() && top() < container.top())) ||
right() > container.right() ||
((gl() && bottom() < container.bottom()) || (!gl() && bottom() > container.bottom())) ||
((inverted_y() && bottom() < container.bottom()) || (!inverted_y() && bottom() > container.bottom())) ||
left() < container.left()
);
}
@ -487,7 +491,7 @@ bool Box::fits(const Box& container) const
/* Removes any part of the box that is not inside the passed crop area box */
void Box::crop(const Box& area)
{
if ((gl() && top() > area.top()) || (!gl() && top() < area.top()))
if ((inverted_y() && top() > area.top()) || (!inverted_y() && top() < area.top()))
{
top(area.top(), true);
}
@ -495,7 +499,7 @@ void Box::crop(const Box& area)
{
right(area.right(), true);
}
if ((gl() && bottom() < area.bottom()) || (!gl() && bottom() > area.bottom()))
if ((inverted_y() && bottom() < area.bottom()) || (!inverted_y() && bottom() > area.bottom()))
{
bottom(area.bottom(), true);
}
@ -509,7 +513,7 @@ void Box::crop(const Box& area)
* will return true. */
bool Box::collide(const glm::vec2& point) const
{
return point.x >= left() && point.x <= right() && point.y >= (gl() ? bottom() : top()) && point.y <= (gl() ? top() : bottom());
return point.x >= left() && point.x <= right() && point.y >= (inverted_y() ? bottom() : top()) && point.y <= (inverted_y() ? top() : bottom());
}
/* Returns true if the line segment intersects the box, false otherwise. If intersection is passed and there is a
@ -557,7 +561,7 @@ bool Box::collide(const Segment& segment, glm::vec2& intersection) const
bool Box::collide(const Box& box, Box* overlap) const
{
float top, bottom, h;
if (gl())
if (inverted_y())
{
top = std::min(this->top(), box.top());
bottom = std::max(this->bottom(), box.bottom());

View File

@ -28,14 +28,15 @@ class Box : public SDL_FRect
private:
bool use_gl_coordinates;
bool invert_y_state = false;
public:
Box(const glm::vec2& = {0, 0}, const glm::vec2& = {0, 0}, bool = false);
Box(float, float, float, float, bool = false);
Box(const SDL_Rect&, bool = false);
void gl(bool);
bool gl() const;
void invert_y(bool);
bool inverted_y() const;
float width() const;
void width(float);
float height() const;

View File

@ -14,11 +14,23 @@ glm::ivec2 Display::window_size() const
return size;
}
/* Return the window dimensions as a Box object. If use_gl_coordinates is set, the lower left will be (0, 0).
* Otherwise, the top left will be (0, 0). */
Box Display::window_box(bool use_gl_coordinates) const
/* Return the window dimensions in pixels as a Box object. If invert_y is set, the lower left will be (0, 0).
* Otherwise, the top left will be (0, 0). Setting invert will cause the values to be compatible with
* glViewport. */
Box Display::window_box(bool invert_y) const
{
return Box(glm::vec2(0, 0), window_size(), use_gl_coordinates);
return Box(glm::vec2(0, 0), window_size(), invert_y);
}
/* Return a box object with NDC coordinates of the window subsection. The subsection should be specified in
* pixel coordinates. */
Box Display::ndc_subsection(const Box& subsection) const
{
Box ndc_subsection = ndc;
Box window = window_box(subsection.inverted_y());
ndc_subsection.move({(subsection.x - window.x) / window.width() * 2.0f, (subsection.y - window.y) / window.height() * 2.0f});
ndc_subsection.size({subsection.width() / window.width() * 2.0f, subsection.height() / window.height() * 2.0f});
return ndc_subsection;
}
/* Get the pixel format of display at specified index (defaults to index 0) */
@ -45,18 +57,22 @@ void Display::screen_pixels(unsigned char* pixels, int w, int h, int x, int y) c
if (get_root()->is_gl_context)
{
GLenum format;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
format = GL_BGRA;
#else
format = GL_RGBA;
#endif
if constexpr (SDL_BYTEORDER == SDL_BIG_ENDIAN)
{
format = GL_BGRA;
}
else
{
format = GL_RGBA;
}
glReadBuffer(GL_FRONT);
glReadPixels(x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
// SDL_Log("(%i, %i, %i) (%i, %i, %i, %i)",
// glCheckFramebufferStatus(GL_FRAMEBUFFER),
// glCheckFramebufferStatus(GL_READ_FRAMEBUFFER),
// glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER),
// pixels[0], pixels[1], pixels[2], pixels[3]);
/* Debug statement showing the framebuffer status and first pixel read */
std::ostringstream message;
message << "read framebuffer status: " << glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) <<
", draw framebuffer status: " << glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) <<
", upper left screen pixel value read: " << pixels[0] << " " << pixels[1] << " " << pixels[2] << " " << pixels[3];
sb::Log::log(message, sb::Log::DEBUG);
}
else
{

View File

@ -17,11 +17,13 @@ class Display : public Node
public:
const static int bpp = 32;
inline const static Box ndc {-1.0f, -1.0f, 2.0f, 2.0f, true};
Display(Node*);
glm::ivec2 window_size() const;
Uint32 pixel_format(int = 0) const;
Box window_box(bool = false) const;
Box ndc_subsection(const Box&) const;
void screen_pixels(unsigned char*, int, int, int = 0, int = 0) const;
SDL_Surface* screen_surface() const;
SDL_Surface* screen_surface_from_pixels(unsigned char*, bool) const;

View File

@ -1,6 +1,6 @@
/* /\ +--------------------------------------------------------------+
____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
\ / / | copy, and modify without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - originally created at [http://nugget.fun] |
| ~~~~~~~~~~~~ | +--------------------------------------------------------------+

View File

@ -1,3 +1,13 @@
/* /\ +--------------------------------------------------------------+
____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, |
\ / / | copy, and modify without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - originally created at [http://nugget.fun] |
| ~~~~~~~~~~~~ | +--------------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#include "Configuration.hpp"
#include "Delegate.hpp"
#include "Display.hpp"
@ -99,9 +109,11 @@ const Game* Node::get_root() const
return dynamic_cast<const Game*>(r);
}
Box Node::window_box(bool use_gl_coordinates)
/* Get the window dimensions in pixels as a box object. If invert_y is set, the bottom left will be (0, 0).
* Otherwise, it the top left will be (0, 0). */
Box Node::window_box(bool invert_y)
{
return get_display().window_box(use_gl_coordinates);
return get_display().window_box(invert_y);
}
void Node::suppress_input()

View File

@ -1,3 +1,13 @@
/* /\ +--------------------------------------------------------------+
____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, |
\ / / | copy, and modify without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - originally created at [http://nugget.fun] |
| ~~~~~~~~~~~~ | +--------------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#ifndef SB_NODE_H_
#define SB_NODE_H_