Skip to content

Instantly share code, notes, and snippets.

@thennequin
Last active April 8, 2018 21:13
Show Gist options
  • Save thennequin/719ef9c3db55f93ca16e161cc95d71ab to your computer and use it in GitHub Desktop.
Save thennequin/719ef9c3db55f93ca16e161cc95d71ab to your computer and use it in GitHub Desktop.
sokol_gfx_plus.h
#include "sokol_gfx.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
Return size of image mip level in bytes
*/
uint32_t sgp_read_image_mip_size(sg_image img_id, int mip_level);
/*
Return total size of image in bytes, including mip maps
*/
extern uint32_t sgp_read_image_size(sg_image img);
/*
Retrieve image informations and content
Fill some fields of `img_desc`:
- type
- pixel_format
- width
- height
- num_mipmaps
- depth
- content (support 2D and Cube image type, also support mipmaps)
content will use the `allocated_data` parameter
Memory is allocated if `allocated_data` is null, so we need to free the memory after calling sgp_read_image
free((void*)img_desc->content.subimage[0][0].ptr)
*/
extern bool sgp_read_image(sg_image img, sg_image_desc* img_desc, void* allocated_data);
#ifdef __cplusplus
}
#endif
/*--- IMPLEMENTATION ---------------------------------------------------------*/
#if defined(SOKOL_IMPL)
# if defined(SOKOL_GLCORE33)
void _sgp_read_image_mip(_sg_image* img, int mip, int face, bool is_cubemap, uint32_t width, uint32_t height, sg_subimage_content* content)
{
GLuint gl_framebuffer;
glGenFramebuffers(1, &gl_framebuffer);
_SG_GL_CHECK_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, gl_framebuffer);
_SG_GL_CHECK_ERROR();
glFramebufferTexture2D(
GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, is_cubemap ? _sg_gl_cubeface_target(face) : GL_TEXTURE_2D
, img->gl_tex[img->active_slot]
, mip
);
_SG_GL_CHECK_ERROR();
glReadBuffer(GL_COLOR_ATTACHMENT0);
_SG_GL_CHECK_ERROR();
glReadPixels(0, 0, width, height,
_sg_gl_teximage_format(img->pixel_format),
_sg_gl_teximage_type(img->pixel_format),
(void*)content->ptr
);
_SG_GL_CHECK_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
_SG_GL_CHECK_ERROR();
glDeleteFramebuffers(1, &gl_framebuffer);
_SG_GL_CHECK_ERROR();
}
# elif defined(SOKOL_D3D11)
# error ToDo
# else
# error Not supported API
# endif
uint32_t sgp_read_image_mip_size(sg_image img_id, int mip_level)
{
_sg_image* img = _sg_lookup_image(&_sg.pools, img_id.id);
if (!(img && img->slot.state == SG_RESOURCESTATE_VALID))
{
return 0;
}
if (img->type != SG_IMAGETYPE_2D && img->type != SG_IMAGETYPE_CUBE)
{
SOKOL_UNREACHABLE;
return 0;
}
uint32_t width = img->width;
uint32_t height = img->height;
for (int mip = 0; mip < img->num_mipmaps; ++mip)
{
if (mip == mip_level)
{
if (_sg_is_compressed_pixel_format(img->pixel_format))
{
SOKOL_UNREACHABLE;
}
else
{
int pixel_size = _sg_pixelformat_bytesize(img->pixel_format);
return width * height * pixel_size;
}
}
width = width >> 1;
height = height >> 1;
}
return 0;
}
uint32_t sgp_read_image_size(sg_image img_id)
{
_sg_image* img = _sg_lookup_image(&_sg.pools, img_id.id);
if (!(img && img->slot.state == SG_RESOURCESTATE_VALID))
{
return 0;
}
if (img->type != SG_IMAGETYPE_2D && img->type != SG_IMAGETYPE_CUBE)
{
SOKOL_UNREACHABLE;
return 0;
}
int face_count = img->type == SG_IMAGETYPE_CUBE ? 6 : 1;
uint32_t total_size = 0;
for (int mip = 0; mip < img->num_mipmaps; ++mip)
{
total_size += face_count * sgp_read_image_mip_size(img_id, mip);
}
return total_size;
}
bool sgp_read_image(sg_image img_id, sg_image_desc* img_desc, void* allocated_data)
{
if (img_desc == NULL)
{
return false;
}
*img_desc = { 0 };
_sg_image* img = _sg_lookup_image(&_sg.pools, img_id.id);
if (!(img && img->slot.state == SG_RESOURCESTATE_VALID))
{
return false;
}
if (_sg_is_compressed_pixel_format(img->pixel_format))
{
return false;
}
uint32_t total_size = sgp_read_image_size(img_id);
if (total_size == 0)
{
SOKOL_UNREACHABLE;
return false;
}
img_desc->type = img->type;
img_desc->pixel_format = img->pixel_format;
img_desc->width = img->width;
img_desc->height = img->height;
img_desc->num_mipmaps = img->num_mipmaps;
img_desc->depth = img->depth;
bool self_allocated = false;
if (allocated_data == NULL)
{
self_allocated = true;
allocated_data = malloc(total_size);
}
int face_count = (img->type == SG_IMAGETYPE_CUBE) ? 6 : 1;
uint32_t width = img->width;
uint32_t height = img->height;
for (int mip = 0; mip < img->num_mipmaps; ++mip)
{
uint32_t mip_size = sgp_read_image_mip_size(img_id, mip);
for (int face = 0; face < face_count; ++face)
{
img_desc->content.subimage[face][mip].ptr = allocated_data;
img_desc->content.subimage[face][mip].size = mip_size;
allocated_data = (char*)allocated_data + mip_size;
}
width = width >> 1;
height = height >> 1;
}
if (img->type == SG_IMAGETYPE_2D || img->type == SG_IMAGETYPE_CUBE)
{
uint32_t width = img->width;
uint32_t height = img->height;
for (int mip = 0; mip < img->num_mipmaps; ++mip)
{
for (int face = 0; face < face_count; ++face)
{
_sgp_read_image_mip(img, mip, face, face_count > 1, width, height, &img_desc->content.subimage[face][mip]);
}
width = width >> 1;
height = height >> 1;
}
return true;
}
if (self_allocated)
free(allocated_data);
SOKOL_UNREACHABLE;
return false;
}
#endif //SOKOL_IMPL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment