diff --git a/include/QF/image.h b/include/QF/image.h index 2bbf7fb0a..d57b7253b 100644 --- a/include/QF/image.h +++ b/include/QF/image.h @@ -46,7 +46,14 @@ typedef struct tex_s { int width; int height; QFFormat format; - int loaded; // 0 if size info only, otherwise data loaded + union { + struct { + int loaded:1; // 0 if size info only, otherwise data loaded + int flipped:1; // 1 if first pixel is bottom instead of top + int bgr:1; // 1 if image is bgr (for tex_rgb) + }; + int flagbits; // for eazy zeroing + }; const byte *palette; // 0 = 32 bit, otherwise 8 byte *data; } tex_t; diff --git a/include/QF/png.h b/include/QF/png.h index 1128a8a4f..62c69a305 100644 --- a/include/QF/png.h +++ b/include/QF/png.h @@ -34,6 +34,6 @@ #include "QF/quakefs.h" struct tex_s *LoadPNG (QFile *infile, int load); -int WritePNG (QFile *outfile, const byte *data, int width, int height); +int WritePNG (QFile *outfile, const struct tex_s *tex); #endif//__QF_png_h diff --git a/libs/image/png.c b/libs/image/png.c index a64f91912..3b67983cd 100644 --- a/libs/image/png.c +++ b/libs/image/png.c @@ -48,6 +48,7 @@ #include "QF/zone.h" #include "compat.h" +#include "qfalloca.h" /* Qread wrapper for libpng */ @@ -206,7 +207,7 @@ LoadPNG (QFile *infile, int load) #define WRITEPNG_BIT_DEPTH 8 int -WritePNG (QFile *outfile, const byte *data, int width, int height) +WritePNG (QFile *outfile, const tex_t *tex) { int i; png_structp png_ptr; @@ -240,27 +241,32 @@ WritePNG (QFile *outfile, const byte *data, int width, int height) return 0; } - png_set_IHDR (png_ptr, info_ptr, width, height, WRITEPNG_BIT_DEPTH, + png_set_IHDR (png_ptr, info_ptr, tex->width, tex->height, + WRITEPNG_BIT_DEPTH, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* NOTE: Write gamma support? */ /* png_set_gAMA (png_ptr, info_ptr, gamma); */ - png_set_bgr(png_ptr); + if (tex->bgr) { + png_set_bgr(png_ptr); + } png_write_info (png_ptr, info_ptr); /* Setup row pointers */ - row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); - if (row_pointers == NULL) { - png_destroy_write_struct (&png_ptr, &info_ptr); - return 0; /* Out of memory */ - } + row_pointers = (png_bytepp)alloca(tex->height * sizeof(png_bytep)); - for (i = 0; i < height; i++) { - //FIXME stupid png types :P - row_pointers[height - i - 1] = (byte *) data + (i * width * 3); + int rowbytes = tex->width * 3; + if (tex->flipped) { + for (i = 0; i < tex->height; i++) { + row_pointers[tex->height - i - 1] = tex->data + (i * rowbytes); + } + } else { + for (i = 0; i < tex->height; i++) { + row_pointers[i] = tex->data + (i * rowbytes); + } } diff --git a/libs/models/iqm/sw_model_iqm.c b/libs/models/iqm/sw_model_iqm.c index b715bb5da..0e6d1fa48 100644 --- a/libs/models/iqm/sw_model_iqm.c +++ b/libs/models/iqm/sw_model_iqm.c @@ -54,7 +54,14 @@ #include "r_internal.h" static byte null_data[] = {15, 15, 15, 15}; -static tex_t null_texture = { 2, 2, tex_palette, 1, 0, null_data }; +static tex_t null_texture = { + .width = 2, + .height = 2, + .format = tex_palette, + .loaded = 1, + .palette =0, + .data = null_data +}; static void sw_iqm_clear (model_t *mod, void *data) diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index 31ebcbf0d..f07a51fd7 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -368,7 +368,7 @@ scr_write_caputre (tex_t *tex, void *data) scr_capture_t *cap = data; if (tex) { - WritePNG (cap->file, tex->data, tex->width, tex->height); + WritePNG (cap->file, tex); free (tex); Sys_Printf ("Wrote %s/%s\n", qfs_userpath, cap->name->str); } else { diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 761854407..0d5f5b640 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -473,6 +473,10 @@ gl_capture_screen (capfunc_t callback, void *data) tex->height = vid.height; tex->format = tex_rgb; tex->palette = 0; + tex->flagbits = 0; + tex->loaded = 1; + tex->bgr = 1; + tex->flipped = 1; qfglReadPixels (0, 0, tex->width, tex->height, GL_BGR_EXT, GL_UNSIGNED_BYTE, tex->data); } diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 1860f2ba7..5c93e36b1 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -409,28 +409,20 @@ glsl_set_fov (float x, float y) static void glsl_capture_screen (capfunc_t callback, void *data) { - byte *r, *b; - int count, i; - tex_t *tex; + int count = vid.width * vid.height; + tex_t *tex = malloc (sizeof (tex_t) + count * 3); - count = vid.width * vid.height; - tex = malloc (sizeof (tex_t) + count * 3); if (tex) { tex->data = (byte *) (tex + 1); tex->width = vid.width; tex->height = vid.height; tex->format = tex_rgb; tex->palette = 0; + tex->flagbits = 0; + tex->loaded = 1; + tex->flipped = 1; qfeglReadPixels (0, 0, tex->width, tex->height, GL_RGB, GL_UNSIGNED_BYTE, tex->data); - //FIXME shouldn't have to swap between rgb and bgr since WritePNG - //swaps back - for (i = 0, r = tex->data, b = tex->data + 2; i < count; - i++, r+= 3, b += 3) { - byte t = *b; - *b = *r; - *r = t; - } } callback (tex, data); } diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 43c1dfc1d..14e09d3d4 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -429,17 +429,17 @@ sw_capture_screen (capfunc_t callback, void *data) tex->height = fb->height; tex->format = tex_rgb; tex->palette = 0; + tex->flagbits = 0; + tex->loaded = 1; src = ((sw_framebuffer_t *) fb->buffer)->color; int rowbytes = ((sw_framebuffer_t *) fb->buffer)->rowbytes; - //FIXME shouldn't have to swap between rgb and bgr since WritePNG - //swaps back for (y = 0; y < tex->height; y++) { - dst = tex->data + (tex->height - 1 - y) * tex->width * 3; + dst = tex->data + y * tex->width * 3; for (x = 0; x < tex->width; x++) { byte c = src[x]; - *dst++ = vid.basepal[c * 3 + 2]; // blue - *dst++ = vid.basepal[c * 3 + 1]; // green - *dst++ = vid.basepal[c * 3 + 0]; // red + *dst++ = vid.basepal[c * 3 + 0]; + *dst++ = vid.basepal[c * 3 + 1]; + *dst++ = vid.basepal[c * 3 + 2]; } src += rowbytes; } diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 5cb1acf5c..9c65ef615 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -478,36 +478,25 @@ capture_screenshot (const byte *data, int width, int height) if (tex) { tex->data = (byte *) (tex + 1); + tex->flagbits = 0; tex->width = width; tex->height = height; tex->format = tex_rgb; tex->palette = 0; + tex->flagbits = 0; + tex->loaded = 1; - //FIXME shouldn't have to swap between rgb and bgr since WritePNG - //swaps back (ie, it can work with either) - //can it auto-convert RGBA to RGB? if (!vulkan_ctx->capture->canBlit || is_bgr (vulkan_ctx->swapchain->format)) { - const byte *src = data; - byte *dst = tex->data; - for (int count = width * height; count-- > 0; ) { - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - src++; - } - } else { - const byte *src = data; - byte *dst = tex->data; - for (int count = width * height; count-- > 0; ) { - byte r = *src++; - byte g = *src++; - byte b = *src++; - *dst++ = b; - *dst++ = g; - *dst++ = r; - src++; - } + tex->bgr = 1; + } + const byte *src = data; + byte *dst = tex->data; + for (int count = width * height; count-- > 0; ) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + src++; } } capfunc_t callback = vulkan_ctx->capture_complete; diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 611836cc2..f30d3407e 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -420,9 +420,30 @@ Vulkan_UnloadTex (vulkan_ctx_t *ctx, qfv_tex_t *tex) static byte black_data[] = {0, 0, 0, 0}; static byte white_data[] = {255, 255, 255, 255}; static byte magenta_data[] = {255, 0, 255, 255}; -static tex_t default_black_tex = {1, 1, tex_rgba, 1, 0, black_data}; -static tex_t default_white_tex = {1, 1, tex_rgba, 1, 0, white_data}; -static tex_t default_magenta_tex = {1, 1, tex_rgba, 1, 0, magenta_data}; +static tex_t default_black_tex = { + .width = 1, + .height = 1, + .format = tex_rgba, + .loaded = 1, + .palette =0, + .data = black_data, +}; +static tex_t default_white_tex = { + .width = 1, + .height = 1, + .format = tex_rgba, + .loaded = 1, + .palette =0, + .data = white_data, +}; +static tex_t default_magenta_tex = { + .width = 1, + .height = 1, + .format = tex_rgba, + .loaded = 1, + .palette =0, + .data = magenta_data, +}; void Vulkan_Texture_Init (vulkan_ctx_t *ctx) diff --git a/tools/bsp2img/bsp2img.c b/tools/bsp2img/bsp2img.c index 58c377fc6..1742034a8 100644 --- a/tools/bsp2img/bsp2img.c +++ b/tools/bsp2img/bsp2img.c @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "QF/bspfile.h" #include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/image.h" #include "QF/mathlib.h" #include "QF/pcx.h" #include "QF/png.h" @@ -888,10 +889,17 @@ render_map (bsp_t *bsp) static void write_png (image_t *image) { - byte *data, *in, *out, b; + byte *in, *out, b; int size = image->width * image->height; + tex_t tex = { + .width = image->width, + .height = image->height, + .format = tex_rgb, + .loaded = 1, + .data = malloc (size * 3), + }; - out = data = malloc (size * 3); + out = tex.data; for (in = image->image; in - image->image < size; in++) { b = *in; *out++ = b; @@ -900,9 +908,10 @@ write_png (image_t *image) } QFile *file = Qopen (options.outf_name, "wb"); if (file) { - WritePNG (file, data, image->width, image->height); + WritePNG (file, &tex); Qclose (file); } + free (tex.data); } static void