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

View File

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

View File

@ -14,11 +14,23 @@ glm::ivec2 Display::window_size() const
return size; return size;
} }
/* Return the window dimensions as a Box object. If use_gl_coordinates is set, the lower left will be (0, 0). /* 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). */ * Otherwise, the top left will be (0, 0). Setting invert will cause the values to be compatible with
Box Display::window_box(bool use_gl_coordinates) const * 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) */ /* 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) if (get_root()->is_gl_context)
{ {
GLenum format; GLenum format;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN if constexpr (SDL_BYTEORDER == SDL_BIG_ENDIAN)
format = GL_BGRA; {
#else format = GL_BGRA;
format = GL_RGBA; }
#endif else
{
format = GL_RGBA;
}
glReadBuffer(GL_FRONT); glReadBuffer(GL_FRONT);
glReadPixels(x, y, w, h, format, GL_UNSIGNED_BYTE, pixels); glReadPixels(x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
// SDL_Log("(%i, %i, %i) (%i, %i, %i, %i)", /* Debug statement showing the framebuffer status and first pixel read */
// glCheckFramebufferStatus(GL_FRAMEBUFFER), std::ostringstream message;
// glCheckFramebufferStatus(GL_READ_FRAMEBUFFER), message << "read framebuffer status: " << glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) <<
// glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER), ", draw framebuffer status: " << glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) <<
// pixels[0], pixels[1], pixels[2], pixels[3]); ", upper left screen pixel value read: " << pixels[0] << " " << pixels[1] << " " << pixels[2] << " " << pixels[3];
sb::Log::log(message, sb::Log::DEBUG);
} }
else else
{ {

View File

@ -17,11 +17,13 @@ class Display : public Node
public: public:
const static int bpp = 32; const static int bpp = 32;
inline const static Box ndc {-1.0f, -1.0f, 2.0f, 2.0f, true};
Display(Node*); Display(Node*);
glm::ivec2 window_size() const; glm::ivec2 window_size() const;
Uint32 pixel_format(int = 0) const; Uint32 pixel_format(int = 0) const;
Box window_box(bool = false) 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; void screen_pixels(unsigned char*, int, int, int = 0, int = 0) const;
SDL_Surface* screen_surface() const; SDL_Surface* screen_surface() const;
SDL_Surface* screen_surface_from_pixels(unsigned char*, bool) 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, | ____/ \____ /| - 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] | | ~/ \~ | | - 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 "Configuration.hpp"
#include "Delegate.hpp" #include "Delegate.hpp"
#include "Display.hpp" #include "Display.hpp"
@ -99,9 +109,11 @@ const Game* Node::get_root() const
return dynamic_cast<const Game*>(r); 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() 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_ #ifndef SB_NODE_H_
#define SB_NODE_H_ #define SB_NODE_H_