mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:27:35 +00:00
LibGL: Implement glReadPixels()
This commit is contained in:
parent
d6c84ca4df
commit
e54d96d53e
3 changed files with 249 additions and 0 deletions
|
@ -1113,10 +1113,239 @@ void SoftwareGLContext::gl_read_pixels(GLint x, GLint y, GLsizei width, GLsizei
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some helper functions for converting float values to integer types
|
||||||
|
auto float_to_i8 = [](float f) -> GLchar {
|
||||||
|
return static_cast<GLchar>((0x7f * min(max(f, 0.0f), 1.0f) - 1) / 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto float_to_i16 = [](float f) -> GLshort {
|
||||||
|
return static_cast<GLshort>((0x7fff * min(max(f, 0.0f), 1.0f) - 1) / 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto float_to_i32 = [](float f) -> GLint {
|
||||||
|
return static_cast<GLint>((0x7fffffff * min(max(f, 0.0f), 1.0f) - 1) / 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto float_to_u8 = [](float f) -> GLubyte {
|
||||||
|
return static_cast<GLubyte>(0xff * min(max(f, 0.0f), 1.0f));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto float_to_u16 = [](float f) -> GLushort {
|
||||||
|
return static_cast<GLushort>(0xffff * min(max(f, 0.0f), 1.0f));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto float_to_u32 = [](float f) -> GLuint {
|
||||||
|
return static_cast<GLuint>(0xffffffff * min(max(f, 0.0f), 1.0f));
|
||||||
|
};
|
||||||
|
|
||||||
if (format == GL_DEPTH_COMPONENT) {
|
if (format == GL_DEPTH_COMPONENT) {
|
||||||
// Read from depth buffer
|
// Read from depth buffer
|
||||||
|
for (size_t i = 0; i < height; ++i) {
|
||||||
|
for (size_t j = 0; j < width; ++j) {
|
||||||
|
float depth = m_rasterizer.get_depthbuffer_value(x + j, y + i);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case GL_BYTE:
|
||||||
|
reinterpret_cast<GLchar*>(pixels)[i * width + j] = float_to_i8(depth);
|
||||||
|
break;
|
||||||
|
case GL_SHORT:
|
||||||
|
reinterpret_cast<GLshort*>(pixels)[i * width + j] = float_to_i16(depth);
|
||||||
|
break;
|
||||||
|
case GL_INT:
|
||||||
|
reinterpret_cast<GLint*>(pixels)[i * width + j] = float_to_i32(depth);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_BYTE:
|
||||||
|
reinterpret_cast<GLubyte*>(pixels)[i * width + j] = float_to_u8(depth);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
reinterpret_cast<GLushort*>(pixels)[i * width + j] = float_to_u16(depth);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
reinterpret_cast<GLuint*>(pixels)[i * width + j] = float_to_u32(depth);
|
||||||
|
break;
|
||||||
|
case GL_FLOAT:
|
||||||
|
reinterpret_cast<GLfloat*>(pixels)[i * width + j] = min(max(depth, 0.0f), 1.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool write_red = false;
|
||||||
|
bool write_green = false;
|
||||||
|
bool write_blue = false;
|
||||||
|
bool write_alpha = false;
|
||||||
|
size_t component_count = 0;
|
||||||
|
size_t component_size = 0;
|
||||||
|
size_t red_offset = 0;
|
||||||
|
size_t green_offset = 0;
|
||||||
|
size_t blue_offset = 0;
|
||||||
|
size_t alpha_offset = 0;
|
||||||
|
char* red_ptr = nullptr;
|
||||||
|
char* green_ptr = nullptr;
|
||||||
|
char* blue_ptr = nullptr;
|
||||||
|
char* alpha_ptr = nullptr;
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case GL_RGB:
|
||||||
|
write_red = true;
|
||||||
|
write_green = true;
|
||||||
|
write_blue = true;
|
||||||
|
component_count = 3;
|
||||||
|
red_offset = 2;
|
||||||
|
green_offset = 1;
|
||||||
|
blue_offset = 0;
|
||||||
|
break;
|
||||||
|
case GL_RGBA:
|
||||||
|
write_red = true;
|
||||||
|
write_green = true;
|
||||||
|
write_blue = true;
|
||||||
|
write_alpha = true;
|
||||||
|
component_count = 4;
|
||||||
|
red_offset = 3;
|
||||||
|
green_offset = 2;
|
||||||
|
blue_offset = 1;
|
||||||
|
alpha_offset = 0;
|
||||||
|
break;
|
||||||
|
case GL_RED:
|
||||||
|
write_red = true;
|
||||||
|
component_count = 1;
|
||||||
|
red_offset = 0;
|
||||||
|
break;
|
||||||
|
case GL_GREEN:
|
||||||
|
write_green = true;
|
||||||
|
component_count = 1;
|
||||||
|
green_offset = 0;
|
||||||
|
break;
|
||||||
|
case GL_BLUE:
|
||||||
|
write_blue = true;
|
||||||
|
component_count = 1;
|
||||||
|
blue_offset = 0;
|
||||||
|
break;
|
||||||
|
case GL_ALPHA:
|
||||||
|
write_alpha = true;
|
||||||
|
component_count = 1;
|
||||||
|
alpha_offset = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case GL_BYTE:
|
||||||
|
case GL_UNSIGNED_BYTE:
|
||||||
|
component_size = 1;
|
||||||
|
break;
|
||||||
|
case GL_SHORT:
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
component_size = 2;
|
||||||
|
break;
|
||||||
|
case GL_INT:
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
case GL_FLOAT:
|
||||||
|
component_size = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* out_ptr = reinterpret_cast<char*>(pixels);
|
||||||
|
for (int i = 0; i < (int)height; ++i) {
|
||||||
|
for (int j = 0; j < (int)width; ++j) {
|
||||||
|
Gfx::RGBA32 color {};
|
||||||
|
if (m_current_read_buffer == GL_FRONT || m_current_read_buffer == GL_LEFT || m_current_read_buffer == GL_FRONT_LEFT) {
|
||||||
|
if (y + i >= m_frontbuffer->width() || x + j >= m_frontbuffer->height())
|
||||||
|
color = 0;
|
||||||
|
else
|
||||||
|
color = m_frontbuffer->scanline(y + i)[x + j];
|
||||||
|
} else {
|
||||||
|
color = m_rasterizer.get_backbuffer_pixel(x + j, y + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
float red = ((color >> 24) & 0xff) / 255.0f;
|
||||||
|
float green = ((color >> 16) & 0xff) / 255.0f;
|
||||||
|
float blue = ((color >> 8) & 0xff) / 255.0f;
|
||||||
|
float alpha = (color & 0xff) / 255.0f;
|
||||||
|
|
||||||
|
// FIXME: Set up write pointers based on selected endianness (glPixelStore)
|
||||||
|
red_ptr = out_ptr + (component_size * red_offset);
|
||||||
|
green_ptr = out_ptr + (component_size * green_offset);
|
||||||
|
blue_ptr = out_ptr + (component_size * blue_offset);
|
||||||
|
alpha_ptr = out_ptr + (component_size * alpha_offset);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case GL_BYTE:
|
||||||
|
if (write_red)
|
||||||
|
*reinterpret_cast<GLchar*>(red_ptr) = float_to_i8(red);
|
||||||
|
if (write_green)
|
||||||
|
*reinterpret_cast<GLchar*>(green_ptr) = float_to_i8(green);
|
||||||
|
if (write_blue)
|
||||||
|
*reinterpret_cast<GLchar*>(blue_ptr) = float_to_i8(blue);
|
||||||
|
if (write_alpha)
|
||||||
|
*reinterpret_cast<GLchar*>(alpha_ptr) = float_to_i8(alpha);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_BYTE:
|
||||||
|
if (write_red)
|
||||||
|
*reinterpret_cast<GLubyte*>(red_ptr) = float_to_u8(red);
|
||||||
|
if (write_green)
|
||||||
|
*reinterpret_cast<GLubyte*>(green_ptr) = float_to_u8(green);
|
||||||
|
if (write_blue)
|
||||||
|
*reinterpret_cast<GLubyte*>(blue_ptr) = float_to_u8(blue);
|
||||||
|
if (write_alpha)
|
||||||
|
*reinterpret_cast<GLubyte*>(alpha_ptr) = float_to_u8(alpha);
|
||||||
|
break;
|
||||||
|
case GL_SHORT:
|
||||||
|
if (write_red)
|
||||||
|
*reinterpret_cast<GLshort*>(red_ptr) = float_to_i16(red);
|
||||||
|
if (write_green)
|
||||||
|
*reinterpret_cast<GLshort*>(green_ptr) = float_to_i16(green);
|
||||||
|
if (write_blue)
|
||||||
|
*reinterpret_cast<GLshort*>(blue_ptr) = float_to_i16(blue);
|
||||||
|
if (write_alpha)
|
||||||
|
*reinterpret_cast<GLshort*>(alpha_ptr) = float_to_i16(alpha);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
if (write_red)
|
||||||
|
*reinterpret_cast<GLushort*>(red_ptr) = float_to_u16(red);
|
||||||
|
if (write_green)
|
||||||
|
*reinterpret_cast<GLushort*>(green_ptr) = float_to_u16(green);
|
||||||
|
if (write_blue)
|
||||||
|
*reinterpret_cast<GLushort*>(blue_ptr) = float_to_u16(blue);
|
||||||
|
if (write_alpha)
|
||||||
|
*reinterpret_cast<GLushort*>(alpha_ptr) = float_to_u16(alpha);
|
||||||
|
break;
|
||||||
|
case GL_INT:
|
||||||
|
if (write_red)
|
||||||
|
*reinterpret_cast<GLint*>(red_ptr) = float_to_i32(red);
|
||||||
|
if (write_green)
|
||||||
|
*reinterpret_cast<GLint*>(green_ptr) = float_to_i32(green);
|
||||||
|
if (write_blue)
|
||||||
|
*reinterpret_cast<GLint*>(blue_ptr) = float_to_i32(blue);
|
||||||
|
if (write_alpha)
|
||||||
|
*reinterpret_cast<GLint*>(alpha_ptr) = float_to_i32(alpha);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
if (write_red)
|
||||||
|
*reinterpret_cast<GLuint*>(red_ptr) = float_to_u32(red);
|
||||||
|
if (write_green)
|
||||||
|
*reinterpret_cast<GLuint*>(green_ptr) = float_to_u32(green);
|
||||||
|
if (write_blue)
|
||||||
|
*reinterpret_cast<GLuint*>(blue_ptr) = float_to_u32(blue);
|
||||||
|
if (write_alpha)
|
||||||
|
*reinterpret_cast<GLuint*>(alpha_ptr) = float_to_u32(alpha);
|
||||||
|
break;
|
||||||
|
case GL_FLOAT:
|
||||||
|
if (write_red)
|
||||||
|
*reinterpret_cast<GLfloat*>(red_ptr) = min(max(red, 0.0f), 1.0f);
|
||||||
|
if (write_green)
|
||||||
|
*reinterpret_cast<GLfloat*>(green_ptr) = min(max(green, 0.0f), 1.0f);
|
||||||
|
if (write_blue)
|
||||||
|
*reinterpret_cast<GLfloat*>(blue_ptr) = min(max(blue, 0.0f), 1.0f);
|
||||||
|
if (write_alpha)
|
||||||
|
*reinterpret_cast<GLfloat*>(alpha_ptr) = min(max(alpha, 0.0f), 1.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_ptr += component_size * component_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareGLContext::present()
|
void SoftwareGLContext::present()
|
||||||
|
|
|
@ -470,4 +470,22 @@ void SoftwareRasterizer::set_options(const RasterizerOptions& options)
|
||||||
// FIXME: Recreate or reinitialize render threads here when multithreading is being implemented
|
// FIXME: Recreate or reinitialize render threads here when multithreading is being implemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Gfx::RGBA32 SoftwareRasterizer::get_backbuffer_pixel(int x, int y)
|
||||||
|
{
|
||||||
|
// FIXME: Reading individual pixels is very slow, rewrite this to transfer whole blocks
|
||||||
|
if (x < 0 || y < 0 || x >= m_render_target->width() || y >= m_render_target->height())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return m_render_target->scanline(y)[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
float SoftwareRasterizer::get_depthbuffer_value(int x, int y)
|
||||||
|
{
|
||||||
|
// FIXME: Reading individual pixels is very slow, rewrite this to transfer whole blocks
|
||||||
|
if (x < 0 || y < 0 || x >= m_render_target->width() || y >= m_render_target->height())
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
return m_depth_buffer->scanline(y)[x];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ public:
|
||||||
void wait_for_all_threads() const;
|
void wait_for_all_threads() const;
|
||||||
void set_options(const RasterizerOptions&);
|
void set_options(const RasterizerOptions&);
|
||||||
RasterizerOptions options() const { return m_options; }
|
RasterizerOptions options() const { return m_options; }
|
||||||
|
Gfx::RGBA32 get_backbuffer_pixel(int x, int y);
|
||||||
|
float get_depthbuffer_value(int x, int y);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<Gfx::Bitmap> m_render_target;
|
RefPtr<Gfx::Bitmap> m_render_target;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue