Last active
April 8, 2018 21:13
-
-
Save thennequin/719ef9c3db55f93ca16e161cc95d71ab to your computer and use it in GitHub Desktop.
sokol_gfx_plus.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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