diff --git a/Userland/Libraries/LibGL/GL/gl.h b/Userland/Libraries/LibGL/GL/gl.h index d7ad62a267..ed3e2934dc 100644 --- a/Userland/Libraries/LibGL/GL/gl.h +++ b/Userland/Libraries/LibGL/GL/gl.h @@ -201,6 +201,18 @@ extern "C" { // Source pixel data format #define GL_UNSIGNED_BYTE 0x1401 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 // Stencil buffer operations #define GL_KEEP 0x1E00 @@ -450,6 +462,7 @@ GLAPI void glColorPointer(GLint size, GLenum type, GLsizei stride, const void* p GLAPI void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void* pointer); GLAPI void glDrawArrays(GLenum mode, GLint first, GLsizei count); GLAPI void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); +GLAPI void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data); GLAPI void glDepthRange(GLdouble nearVal, GLdouble farVal); GLAPI void glDepthFunc(GLenum func); GLAPI void glPolygonMode(GLenum face, GLenum mode); @@ -475,6 +488,7 @@ GLAPI void glMaterialfv(GLenum face, GLenum pname, GLfloat const* params); GLAPI void glLineWidth(GLfloat width); GLAPI void glPushAttrib(GLbitfield mask); GLAPI void glPopAttrib(); +GLAPI void glBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte const* bitmap); #ifdef __cplusplus } diff --git a/Userland/Libraries/LibGL/GLContext.h b/Userland/Libraries/LibGL/GLContext.h index 24e3af6bed..20fc85db37 100644 --- a/Userland/Libraries/LibGL/GLContext.h +++ b/Userland/Libraries/LibGL/GLContext.h @@ -79,6 +79,7 @@ public: virtual void gl_tex_coord_pointer(GLint size, GLenum type, GLsizei stride, const void* pointer) = 0; virtual void gl_draw_arrays(GLenum mode, GLint first, GLsizei count) = 0; virtual void gl_draw_elements(GLenum mode, GLsizei count, GLenum type, const void* indices) = 0; + virtual void gl_draw_pixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data) = 0; virtual void gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) = 0; virtual void gl_get_booleanv(GLenum pname, GLboolean* data) = 0; virtual void gl_get_doublev(GLenum pname, GLdouble* params) = 0; @@ -102,6 +103,7 @@ public: virtual void gl_push_attrib(GLbitfield mask) = 0; virtual void gl_pop_attrib() = 0; virtual void gl_light_model(GLenum pname, GLfloat x, GLfloat y, GLfloat z, GLfloat w) = 0; + virtual void gl_bitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte const* bitmap) = 0; virtual void present() = 0; }; diff --git a/Userland/Libraries/LibGL/GLDraw.cpp b/Userland/Libraries/LibGL/GLDraw.cpp index 5be277a741..6139975933 100644 --- a/Userland/Libraries/LibGL/GLDraw.cpp +++ b/Userland/Libraries/LibGL/GLDraw.cpp @@ -9,6 +9,16 @@ extern GL::GLContext* g_gl_context; +void glBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte const* bitmap) +{ + g_gl_context->gl_bitmap(width, height, xorig, yorig, xmove, ymove, bitmap); +} + +void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data) +{ + g_gl_context->gl_draw_pixels(width, height, format, type, data); +} + void glLineWidth(GLfloat width) { g_gl_context->gl_line_width(width); diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.cpp b/Userland/Libraries/LibGL/SoftwareGLContext.cpp index 826eda3c8a..5cd7b061e7 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.cpp +++ b/Userland/Libraries/LibGL/SoftwareGLContext.cpp @@ -1926,6 +1926,106 @@ void SoftwareGLContext::gl_draw_elements(GLenum mode, GLsizei count, GLenum type glEnd(); } +void SoftwareGLContext::gl_draw_pixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data) +{ + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_draw_pixels, width, height, format, type, data); + + RETURN_WITH_ERROR_IF(!(format == GL_COLOR_INDEX + || format == GL_STENCIL_INDEX + || format == GL_DEPTH_COMPONENT + || format == GL_RGBA + || format == GL_BGRA + || format == GL_RED + || format == GL_GREEN + || format == GL_BLUE + || format == GL_ALPHA + || format == GL_RGB + || format == GL_BGR + || format == GL_LUMINANCE + || format == GL_LUMINANCE_ALPHA), + GL_INVALID_ENUM); + + RETURN_WITH_ERROR_IF(!(type == GL_UNSIGNED_BYTE + || type == GL_BYTE + || type == GL_BITMAP + || type == GL_UNSIGNED_SHORT + || type == GL_SHORT + || type == GL_UNSIGNED_INT + || type == GL_INT + || type == GL_FLOAT + || type == GL_UNSIGNED_BYTE_3_3_2 + || type == GL_UNSIGNED_BYTE_2_3_3_REV + || type == GL_UNSIGNED_SHORT_5_6_5 + || type == GL_UNSIGNED_SHORT_5_6_5_REV + || type == GL_UNSIGNED_SHORT_4_4_4_4 + || type == GL_UNSIGNED_SHORT_4_4_4_4_REV + || type == GL_UNSIGNED_SHORT_5_5_5_1 + || type == GL_UNSIGNED_SHORT_1_5_5_5_REV + || type == GL_UNSIGNED_INT_8_8_8_8 + || type == GL_UNSIGNED_INT_8_8_8_8_REV + || type == GL_UNSIGNED_INT_10_10_10_2 + || type == GL_UNSIGNED_INT_2_10_10_10_REV), + GL_INVALID_ENUM); + + RETURN_WITH_ERROR_IF(type == GL_BITMAP && !(format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX), GL_INVALID_ENUM); + + RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); + + // FIXME: GL_INVALID_OPERATION is generated if format is GL_STENCIL_INDEX and there is no stencil buffer + // FIXME: GL_INVALID_OPERATION is generated if format is GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, + // GL_BGR, GL_BGRA, GL_LUMINANCE, or GL_LUMINANCE_ALPHA, and the GL is in color index mode + + RETURN_WITH_ERROR_IF(format != GL_RGB + && (type == GL_UNSIGNED_BYTE_3_3_2 + || type == GL_UNSIGNED_BYTE_2_3_3_REV + || type == GL_UNSIGNED_SHORT_5_6_5 + || type == GL_UNSIGNED_SHORT_5_6_5_REV), + GL_INVALID_OPERATION); + + RETURN_WITH_ERROR_IF(!(format == GL_RGBA || format == GL_BGRA) + && (type == GL_UNSIGNED_SHORT_4_4_4_4 + || type == GL_UNSIGNED_SHORT_4_4_4_4_REV + || type == GL_UNSIGNED_SHORT_5_5_5_1 + || type == GL_UNSIGNED_SHORT_1_5_5_5_REV + || type == GL_UNSIGNED_INT_8_8_8_8 + || type == GL_UNSIGNED_INT_8_8_8_8_REV + || type == GL_UNSIGNED_INT_10_10_10_2 + || type == GL_UNSIGNED_INT_2_10_10_10_REV), + GL_INVALID_OPERATION); + + // FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER + // target and the buffer object's data store is currently mapped. + // FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER + // target and the data would be unpacked from the buffer object such that the memory reads required would + // exceed the data store size. + // FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER + // target and data is not evenly divisible into the number of bytes needed to store in memory a datum + // indicated by type. + + RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); + + // FIXME: we only support RGBA + GL_UNSIGNED_BYTE, implement all the others! + if (format != GL_RGBA || type != GL_UNSIGNED_BYTE) { + dbgln("gl_draw_pixels: unsupported format {:#x} or type {:#x}", format, type); + return; + } + + auto bitmap_or_error = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, { width, height }); + RETURN_WITH_ERROR_IF(bitmap_or_error.is_error(), GL_OUT_OF_MEMORY); + auto bitmap = bitmap_or_error.release_value(); + + // FIXME: implement support for GL_UNPACK_ALIGNMENT and other pixel parameters + auto pixel_data = static_cast(data); + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) + bitmap->set_pixel(x, y, Color::from_rgba(*(pixel_data++))); + + m_rasterizer.blit( + bitmap, + static_cast(m_current_raster_position.window_coordinates.x()), + static_cast(m_current_raster_position.window_coordinates.y())); +} + void SoftwareGLContext::gl_depth_range(GLdouble min, GLdouble max) { APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_range, min, max); @@ -2366,6 +2466,15 @@ void SoftwareGLContext::gl_light_model(GLenum pname, GLfloat x, GLfloat y, GLflo } } +void SoftwareGLContext::gl_bitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte const* bitmap) +{ + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_bitmap, width, height, xorig, yorig, xmove, ymove, bitmap); + RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); + + // FIXME: implement + dbgln_if(GL_DEBUG, "SoftwareGLContext FIXME: implement gl_bitmap({}, {}, {}, {}, {}, {}, {})", width, height, xorig, yorig, xmove, ymove, bitmap); +} + void SoftwareGLContext::present() { m_rasterizer.blit_to(*m_frontbuffer); diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.h b/Userland/Libraries/LibGL/SoftwareGLContext.h index 091a16919d..3413a46ea1 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.h +++ b/Userland/Libraries/LibGL/SoftwareGLContext.h @@ -90,6 +90,7 @@ public: virtual void gl_tex_coord_pointer(GLint size, GLenum type, GLsizei stride, const void* pointer) override; virtual void gl_draw_arrays(GLenum mode, GLint first, GLsizei count) override; virtual void gl_draw_elements(GLenum mode, GLsizei count, GLenum type, const void* indices) override; + virtual void gl_draw_pixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data) override; virtual void gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) override; virtual void gl_get_booleanv(GLenum pname, GLboolean* data) override; virtual void gl_get_doublev(GLenum pname, GLdouble* params) override; @@ -113,6 +114,7 @@ public: virtual void gl_push_attrib(GLbitfield mask) override; virtual void gl_pop_attrib() override; virtual void gl_light_model(GLenum pname, GLfloat x, GLfloat y, GLfloat z, GLfloat w) override; + virtual void gl_bitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte const* bitmap) override; virtual void present() override; private: @@ -275,6 +277,7 @@ private: decltype(&SoftwareGLContext::gl_depth_mask), decltype(&SoftwareGLContext::gl_draw_arrays), decltype(&SoftwareGLContext::gl_draw_elements), + decltype(&SoftwareGLContext::gl_draw_pixels), decltype(&SoftwareGLContext::gl_depth_range), decltype(&SoftwareGLContext::gl_polygon_offset), decltype(&SoftwareGLContext::gl_scissor), @@ -286,7 +289,8 @@ private: decltype(&SoftwareGLContext::gl_line_width), decltype(&SoftwareGLContext::gl_push_attrib), decltype(&SoftwareGLContext::gl_pop_attrib), - decltype(&SoftwareGLContext::gl_light_model)>; + decltype(&SoftwareGLContext::gl_light_model), + decltype(&SoftwareGLContext::gl_bitmap)>; using ExtraSavedArguments = Variant< FloatMatrix4x4>; diff --git a/Userland/Libraries/LibGL/SoftwareRasterizer.cpp b/Userland/Libraries/LibGL/SoftwareRasterizer.cpp index dbf06c0dd6..d9c3c5b431 100644 --- a/Userland/Libraries/LibGL/SoftwareRasterizer.cpp +++ b/Userland/Libraries/LibGL/SoftwareRasterizer.cpp @@ -604,6 +604,14 @@ void SoftwareRasterizer::clear_depth(float depth) m_depth_buffer->clear(depth); } +void SoftwareRasterizer::blit(Gfx::Bitmap const& source, int x, int y) +{ + wait_for_all_threads(); + + Gfx::Painter painter { *m_render_target }; + painter.blit({ x, y }, source, source.rect(), 1.0f, true); +} + void SoftwareRasterizer::blit_to(Gfx::Bitmap& target) { wait_for_all_threads(); diff --git a/Userland/Libraries/LibGL/SoftwareRasterizer.h b/Userland/Libraries/LibGL/SoftwareRasterizer.h index 479d0d1450..85acfa1569 100644 --- a/Userland/Libraries/LibGL/SoftwareRasterizer.h +++ b/Userland/Libraries/LibGL/SoftwareRasterizer.h @@ -61,6 +61,7 @@ public: void resize(const Gfx::IntSize& min_size); void clear_color(const FloatVector4&); void clear_depth(float); + void blit(Gfx::Bitmap const&, int x, int y); void blit_to(Gfx::Bitmap&); void wait_for_all_threads() const; void set_options(const RasterizerOptions&);