diff --git a/src/pixel_stream.cpp b/src/pixel_stream.cpp index 8e93d50..bb43e90 100644 --- a/src/pixel_stream.cpp +++ b/src/pixel_stream.cpp @@ -60,5 +60,6 @@ const struct ComponentsPerFormat _ogx_pixels_components_per_format[] = { { GL_BLUE, 1, { 2 }}, { GL_ALPHA, 1, { 3 }}, { GL_DEPTH_COMPONENT, 1, {}}, + { GL_STENCIL_INDEX, 1, { 0 }}, { 0, } }; diff --git a/src/pixel_stream.h b/src/pixel_stream.h index c883502..e393c72 100644 --- a/src/pixel_stream.h +++ b/src/pixel_stream.h @@ -358,4 +358,17 @@ struct DepthPixelStream: public GenericPixelStream { } }; +template +struct StencilPixelStream: public GenericPixelStream { + using GenericPixelStream::GenericPixelStream; + using GenericPixelStream::m_write_pos; + + void write(GXColor color) override { + this->d()[m_write_pos++] = glcomponent(color.r) + * (1 << glparamstate.transfer_index_shift) + + glparamstate.transfer_index_offset; + this->check_next_row(); + } +}; + #endif /* OPENGX_PIXEL_STREAM_H */ diff --git a/src/raster.cpp b/src/raster.cpp index a5b24d1..a0a140e 100644 --- a/src/raster.cpp +++ b/src/raster.cpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "pixel_stream.h" #include "pixels.h" #include "state.h" +#include "stencil.h" #include "texel.h" #include "utils.h" @@ -355,6 +356,7 @@ struct TextureReader { Texel *new_texel_for_format(uint8_t gx_format) { switch (gx_format) { + case GX_CTF_R4: return new TexelI4; case GX_TF_I8: return new TexelI8; case GX_TF_IA8: return new TexelIA8; case GX_TF_RGBA8: return new TexelRGBA8; @@ -390,6 +392,17 @@ struct PixelWriter { case GL_FLOAT: return new DepthPixelStream(format, type); } + } else if (format == GL_STENCIL_INDEX) { + switch (type) { + case GL_UNSIGNED_BYTE: + return new StencilPixelStream(format, type); + case GL_UNSIGNED_SHORT: + return new StencilPixelStream(format, type); + case GL_UNSIGNED_INT: + return new StencilPixelStream(format, type); + case GL_FLOAT: + return new StencilPixelStream(format, type); + } } switch (type) { case GL_UNSIGNED_BYTE: @@ -435,17 +448,10 @@ void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, { uint8_t gxformat = 0xff; const ReadPixelFormat *read_format = NULL; + ReadPixelFormat stencil_format; int n_components; - - switch (format) { - case GL_COLOR_INDEX: - warning("glReadPixels: GL_COLOR_INDEX not supported"); - return; - case GL_STENCIL_INDEX: - warning("glReadPixels: GL_STENCIL_INDEX not implemented"); - // TODO - return; - } + void *texels = nullptr; + bool must_free_texels = false; for (int i = 0; s_read_pixel_formats[i].format != 0; i++) { if (s_read_pixel_formats[i].format == format) { @@ -454,15 +460,27 @@ void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, } } if (!read_format) { - warning("glReadPixels: unsupported format %04x", format); - return; + if (format == GL_STENCIL_INDEX) { + OgxEfbBuffer *stencil = _ogx_stencil_get_buffer(); + stencil_format = { + format, 0, + uint8_t(GX_GetTexObjFmt(&stencil->texobj)), 1 }; + read_format = &stencil_format; + texels = _ogx_efb_buffer_get_texels(stencil); + } else { + warning("glReadPixels: unsupported format %04x", format); + return; + } } - u32 size = GX_GetTexBufferSize(width, height, - read_format->gx_dest_format, 0, GX_FALSE); - void *texels = memalign(32, size); - _ogx_efb_save_area_to_buffer(read_format->gx_copy_format, x, y, - width, height, texels, OGX_EFB_NONE); + if (!texels) { + u32 size = GX_GetTexBufferSize(width, height, + read_format->gx_dest_format, 0, GX_FALSE); + texels = memalign(32, size); + _ogx_efb_save_area_to_buffer(read_format->gx_copy_format, x, y, + width, height, texels, OGX_EFB_NONE); + must_free_texels = true; + } TextureReader reader(read_format, texels, width, height); PixelWriter writer(data, width, height, format, type); for (int row = 0; row < height; row++) { @@ -472,7 +490,10 @@ void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, writer.write(&pixel); } } - free(texels); + + if (must_free_texels) { + free(texels); + } } void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, diff --git a/src/stencil.c b/src/stencil.c index 298957d..4ade837 100644 --- a/src/stencil.c +++ b/src/stencil.c @@ -630,6 +630,11 @@ void _ogx_stencil_clear() s_stencil_texture_needs_update = false; } +OgxEfbBuffer *_ogx_stencil_get_buffer() +{ + return s_stencil_buffer; +} + void ogx_stencil_create(OgxStencilFlags flags) { s_wants_stencil = true; diff --git a/src/stencil.h b/src/stencil.h index 9771cc2..2fa2f4e 100644 --- a/src/stencil.h +++ b/src/stencil.h @@ -33,11 +33,16 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef OPENGX_STENCIL_H #define OPENGX_STENCIL_H +#include "efb.h" #include "opengx.h" #include #include +#ifdef __cplusplus +extern "C" { +#endif + extern OgxStencilFlags _ogx_stencil_flags; void _ogx_stencil_enabled(void); @@ -56,4 +61,10 @@ void _ogx_stencil_draw(OgxStencilDrawCallback callback, void *cb_data); void _ogx_stencil_load_into_efb(); void _ogx_stencil_save_to_efb(); +OgxEfbBuffer *_ogx_stencil_get_buffer(void); + +#ifdef __cplusplus +} // extern C +#endif + #endif /* OPENGX_STENCIL_H */