[image] Make WritePNG take settings from tex_t

This means that a tex_t object is passed in instead of just raw bytes
and width and height, but it means the texture can specify whether it's
flipped or uses BGR instead of RGB. This fixes the upside down
screenshots for vulkan.
This commit is contained in:
Bill Currie 2022-03-31 20:00:13 +09:00
parent acffacc59b
commit 790f62a209
11 changed files with 98 additions and 63 deletions

View file

@ -46,7 +46,14 @@ typedef struct tex_s {
int width; int width;
int height; int height;
QFFormat format; 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 const byte *palette; // 0 = 32 bit, otherwise 8
byte *data; byte *data;
} tex_t; } tex_t;

View file

@ -34,6 +34,6 @@
#include "QF/quakefs.h" #include "QF/quakefs.h"
struct tex_s *LoadPNG (QFile *infile, int load); 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 #endif//__QF_png_h

View file

@ -48,6 +48,7 @@
#include "QF/zone.h" #include "QF/zone.h"
#include "compat.h" #include "compat.h"
#include "qfalloca.h"
/* Qread wrapper for libpng */ /* Qread wrapper for libpng */
@ -206,7 +207,7 @@ LoadPNG (QFile *infile, int load)
#define WRITEPNG_BIT_DEPTH 8 #define WRITEPNG_BIT_DEPTH 8
int int
WritePNG (QFile *outfile, const byte *data, int width, int height) WritePNG (QFile *outfile, const tex_t *tex)
{ {
int i; int i;
png_structp png_ptr; png_structp png_ptr;
@ -240,27 +241,32 @@ WritePNG (QFile *outfile, const byte *data, int width, int height)
return 0; 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_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
/* NOTE: Write gamma support? */ /* NOTE: Write gamma support? */
/* png_set_gAMA (png_ptr, info_ptr, gamma); */ /* 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); png_write_info (png_ptr, info_ptr);
/* Setup row pointers */ /* Setup row pointers */
row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); row_pointers = (png_bytepp)alloca(tex->height * sizeof(png_bytep));
if (row_pointers == NULL) {
png_destroy_write_struct (&png_ptr, &info_ptr);
return 0; /* Out of memory */
}
for (i = 0; i < height; i++) { int rowbytes = tex->width * 3;
//FIXME stupid png types :P if (tex->flipped) {
row_pointers[height - i - 1] = (byte *) data + (i * width * 3); 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);
}
} }

View file

@ -54,7 +54,14 @@
#include "r_internal.h" #include "r_internal.h"
static byte null_data[] = {15, 15, 15, 15}; 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 static void
sw_iqm_clear (model_t *mod, void *data) sw_iqm_clear (model_t *mod, void *data)

View file

@ -368,7 +368,7 @@ scr_write_caputre (tex_t *tex, void *data)
scr_capture_t *cap = data; scr_capture_t *cap = data;
if (tex) { if (tex) {
WritePNG (cap->file, tex->data, tex->width, tex->height); WritePNG (cap->file, tex);
free (tex); free (tex);
Sys_Printf ("Wrote %s/%s\n", qfs_userpath, cap->name->str); Sys_Printf ("Wrote %s/%s\n", qfs_userpath, cap->name->str);
} else { } else {

View file

@ -473,6 +473,10 @@ gl_capture_screen (capfunc_t callback, void *data)
tex->height = vid.height; tex->height = vid.height;
tex->format = tex_rgb; tex->format = tex_rgb;
tex->palette = 0; 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, qfglReadPixels (0, 0, tex->width, tex->height, GL_BGR_EXT,
GL_UNSIGNED_BYTE, tex->data); GL_UNSIGNED_BYTE, tex->data);
} }

View file

@ -409,28 +409,20 @@ glsl_set_fov (float x, float y)
static void static void
glsl_capture_screen (capfunc_t callback, void *data) glsl_capture_screen (capfunc_t callback, void *data)
{ {
byte *r, *b; int count = vid.width * vid.height;
int count, i; tex_t *tex = malloc (sizeof (tex_t) + count * 3);
tex_t *tex;
count = vid.width * vid.height;
tex = malloc (sizeof (tex_t) + count * 3);
if (tex) { if (tex) {
tex->data = (byte *) (tex + 1); tex->data = (byte *) (tex + 1);
tex->width = vid.width; tex->width = vid.width;
tex->height = vid.height; tex->height = vid.height;
tex->format = tex_rgb; tex->format = tex_rgb;
tex->palette = 0; tex->palette = 0;
tex->flagbits = 0;
tex->loaded = 1;
tex->flipped = 1;
qfeglReadPixels (0, 0, tex->width, tex->height, GL_RGB, qfeglReadPixels (0, 0, tex->width, tex->height, GL_RGB,
GL_UNSIGNED_BYTE, tex->data); 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); callback (tex, data);
} }

View file

@ -429,17 +429,17 @@ sw_capture_screen (capfunc_t callback, void *data)
tex->height = fb->height; tex->height = fb->height;
tex->format = tex_rgb; tex->format = tex_rgb;
tex->palette = 0; tex->palette = 0;
tex->flagbits = 0;
tex->loaded = 1;
src = ((sw_framebuffer_t *) fb->buffer)->color; src = ((sw_framebuffer_t *) fb->buffer)->color;
int rowbytes = ((sw_framebuffer_t *) fb->buffer)->rowbytes; 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++) { 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++) { for (x = 0; x < tex->width; x++) {
byte c = src[x]; byte c = src[x];
*dst++ = vid.basepal[c * 3 + 2]; // blue *dst++ = vid.basepal[c * 3 + 0];
*dst++ = vid.basepal[c * 3 + 1]; // green *dst++ = vid.basepal[c * 3 + 1];
*dst++ = vid.basepal[c * 3 + 0]; // red *dst++ = vid.basepal[c * 3 + 2];
} }
src += rowbytes; src += rowbytes;
} }

View file

@ -478,36 +478,25 @@ capture_screenshot (const byte *data, int width, int height)
if (tex) { if (tex) {
tex->data = (byte *) (tex + 1); tex->data = (byte *) (tex + 1);
tex->flagbits = 0;
tex->width = width; tex->width = width;
tex->height = height; tex->height = height;
tex->format = tex_rgb; tex->format = tex_rgb;
tex->palette = 0; 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 || if (!vulkan_ctx->capture->canBlit ||
is_bgr (vulkan_ctx->swapchain->format)) { is_bgr (vulkan_ctx->swapchain->format)) {
const byte *src = data; tex->bgr = 1;
byte *dst = tex->data; }
for (int count = width * height; count-- > 0; ) { const byte *src = data;
*dst++ = *src++; byte *dst = tex->data;
*dst++ = *src++; for (int count = width * height; count-- > 0; ) {
*dst++ = *src++; *dst++ = *src++;
src++; *dst++ = *src++;
} *dst++ = *src++;
} else { src++;
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++;
}
} }
} }
capfunc_t callback = vulkan_ctx->capture_complete; capfunc_t callback = vulkan_ctx->capture_complete;

View file

@ -420,9 +420,30 @@ Vulkan_UnloadTex (vulkan_ctx_t *ctx, qfv_tex_t *tex)
static byte black_data[] = {0, 0, 0, 0}; static byte black_data[] = {0, 0, 0, 0};
static byte white_data[] = {255, 255, 255, 255}; static byte white_data[] = {255, 255, 255, 255};
static byte magenta_data[] = {255, 0, 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_black_tex = {
static tex_t default_white_tex = {1, 1, tex_rgba, 1, 0, white_data}; .width = 1,
static tex_t default_magenta_tex = {1, 1, tex_rgba, 1, 0, magenta_data}; .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 void
Vulkan_Texture_Init (vulkan_ctx_t *ctx) Vulkan_Texture_Init (vulkan_ctx_t *ctx)

View file

@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "QF/bspfile.h" #include "QF/bspfile.h"
#include "QF/cmd.h" #include "QF/cmd.h"
#include "QF/cvar.h" #include "QF/cvar.h"
#include "QF/image.h"
#include "QF/mathlib.h" #include "QF/mathlib.h"
#include "QF/pcx.h" #include "QF/pcx.h"
#include "QF/png.h" #include "QF/png.h"
@ -888,10 +889,17 @@ render_map (bsp_t *bsp)
static void static void
write_png (image_t *image) write_png (image_t *image)
{ {
byte *data, *in, *out, b; byte *in, *out, b;
int size = image->width * image->height; 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++) { for (in = image->image; in - image->image < size; in++) {
b = *in; b = *in;
*out++ = b; *out++ = b;
@ -900,9 +908,10 @@ write_png (image_t *image)
} }
QFile *file = Qopen (options.outf_name, "wb"); QFile *file = Qopen (options.outf_name, "wb");
if (file) { if (file) {
WritePNG (file, data, image->width, image->height); WritePNG (file, &tex);
Qclose (file); Qclose (file);
} }
free (tex.data);
} }
static void static void