mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-21 20:11:24 +00:00
[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:
parent
acffacc59b
commit
790f62a209
11 changed files with 98 additions and 63 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue