From 5c0883594fc5f2915b446bd7728c4ff9dcf185e3 Mon Sep 17 00:00:00 2001 From: Denis Pauk Date: Sat, 1 Jul 2023 23:30:41 +0300 Subject: [PATCH] cl_cin: Support of RGBA png/jpg image with r_retexturing as cinematic --- src/client/cl_cin.c | 97 ++++++++++++++++++++++++-- src/client/refresh/gl1/gl1_draw.c | 19 +++-- src/client/refresh/gl1/header/local.h | 2 +- src/client/refresh/gl3/gl3_draw.c | 31 ++++---- src/client/refresh/gl3/header/local.h | 2 +- src/client/refresh/soft/header/local.h | 3 +- src/client/refresh/soft/sw_draw.c | 11 ++- src/client/refresh/soft/sw_image.c | 2 +- src/client/vid/header/ref.h | 9 ++- src/client/vid/vid.c | 4 +- 10 files changed, 147 insertions(+), 33 deletions(-) diff --git a/src/client/cl_cin.c b/src/client/cl_cin.c index c798ac59..44456c67 100644 --- a/src/client/cl_cin.c +++ b/src/client/cl_cin.c @@ -30,6 +30,20 @@ #include "header/client.h" #include "input/header/input.h" +// don't need HDR stuff +#define STBI_NO_LINEAR +#define STBI_NO_HDR +// make sure STB_image uses standard malloc(), as we'll use standard free() to deallocate +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,sz) realloc(p,sz) +#define STBI_FREE(p) free(p) +// Switch of the thread local stuff. Breaks mingw under Windows. +#define STBI_NO_THREAD_LOCALS +// include implementation part of stb_image into this file +#define STB_IMAGE_IMPLEMENTATION +#include "refresh/files/stb_image.h" + + extern cvar_t *vid_renderer; cvar_t *cin_force43; @@ -50,6 +64,7 @@ typedef struct int width; int height; + int color_bits; byte *pic; byte *pic_pending; @@ -598,6 +613,12 @@ SCR_DrawCinematic(void) if (Q_stricmp(vid_renderer->string, "soft") == 0) { color = SCR_MinimalColor(); + + /* Soft render requires to reset palette before show RGBA image */ + if (cin.color_bits == 32) + { + R_SetPalette(NULL); + } } else { @@ -621,16 +642,51 @@ SCR_DrawCinematic(void) Draw_Fill(x, y + h, w, viddef.height - (y + h), color); } - Draw_StretchRaw(x, y, w, h, cin.width, cin.height, cin.pic); + Draw_StretchRaw(x, y, w, h, cin.width, cin.height, cin.pic, cin.color_bits); return true; } +byte * +SCR_LoadHiColor(const char* namewe, const char *ext, int *width, int *height) +{ + char filename[256]; + int bytesPerPixel; + byte *pic, *data = NULL; + void *rawdata; + size_t len; + + Q_strlcpy(filename, namewe, sizeof(filename)); + Q_strlcat(filename, ".", sizeof(filename)); + Q_strlcat(filename, ext, sizeof(filename)); + + len = FS_LoadFile(filename, &rawdata); + + if (!rawdata || len <=0) + { + return NULL; + } + + data = stbi_load_from_memory(rawdata, len, width, height, + &bytesPerPixel, STBI_rgb_alpha); + if (data == NULL) + { + FS_FreeFile(rawdata); + return NULL; + } + + pic = Z_Malloc(cin.height * cin.width * 4); + memcpy(pic, data, cin.height * cin.width * 4); + free(data); + + return pic; +} + void SCR_PlayCinematic(char *arg) { int width, height; - byte *palette; + byte *palette = NULL; char name[MAX_OSPATH], *dot; In_FlushQueue(); @@ -645,11 +701,43 @@ SCR_PlayCinematic(char *arg) /* static pcx image */ if (dot && !strcmp(dot, ".pcx")) { + cvar_t *r_retexturing; + Com_sprintf(name, sizeof(name), "pics/%s", arg); - SCR_LoadPCX(name, &cin.pic, &palette, &cin.width, &cin.height); + r_retexturing = Cvar_Get("r_retexturing", "1", CVAR_ARCHIVE); + + if (r_retexturing->value) + { + char namewe[256]; + + cin.color_bits = 32; + + /* Remove the extension */ + memset(namewe, 0, 256); + memcpy(namewe, name, strlen(name) - strlen(dot)); + cin.pic = SCR_LoadHiColor(namewe, "tga", &cin.width, &cin.height); + + if (!cin.pic) + { + cin.pic = SCR_LoadHiColor(namewe, "png", &cin.width, &cin.height); + } + + if (!cin.pic) + { + cin.pic = SCR_LoadHiColor(namewe, "jpg", &cin.width, &cin.height); + } + } + + if (!cin.pic) + { + SCR_LoadPCX(name, &cin.pic, &palette, &cin.width, &cin.height); + cin.color_bits = 8; + } + cl.cinematicframe = -1; cl.cinematictime = 1; SCR_EndLoadingPlaque(); + cls.state = ca_active; if (!cin.pic) @@ -657,7 +745,7 @@ SCR_PlayCinematic(char *arg) Com_Printf("%s not found.\n", name); cl.cinematictime = 0; } - else + else if (palette) { memcpy(cl.cinematicpalette, palette, sizeof(cl.cinematicpalette)); Z_Free(palette); @@ -678,6 +766,7 @@ SCR_PlayCinematic(char *arg) SCR_EndLoadingPlaque(); + cin.color_bits = 8; cls.state = ca_active; FS_Read(&width, 4, cl.cinematic_file); diff --git a/src/client/refresh/gl1/gl1_draw.c b/src/client/refresh/gl1/gl1_draw.c index c8b92b26..c8093301 100644 --- a/src/client/refresh/gl1/gl1_draw.c +++ b/src/client/refresh/gl1/gl1_draw.c @@ -330,10 +330,9 @@ RDraw_FadeScreen(void) } void -RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data) +RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int bits) { GLfloat tex[8]; - byte *source; float hscale = 1.0f; int frac, fracstep; int i, j, trows; @@ -341,7 +340,7 @@ RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data) R_Bind(0); - if(gl_config.npottextures || rows <= 256) + if(gl_config.npottextures || rows <= 256 || bits == 32) { // X, X tex[0] = 0; @@ -389,7 +388,7 @@ RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data) x, y + h }; - if (!gl_config.palettedtexture) + if (!gl_config.palettedtexture || bits == 32) { unsigned image32[320*240]; /* was 256 * 256, but we want a bit more space */ @@ -398,7 +397,13 @@ RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data) * pixels to fit into a 256x256 texture. * This causes text in videos (which are 320x240) to not look broken anymore. */ - if(gl_config.npottextures || rows <= 256) + if (bits == 32) + { + glTexImage2D(GL_TEXTURE_2D, 0, gl_tex_solid_format, + cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, + data); + } + else if(gl_config.npottextures || rows <= 256) { unsigned* img = image32; @@ -435,6 +440,8 @@ RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data) for (i = 0; i < trows; i++) { + const byte *source; + row = (int)(i * hscale); if (row > rows) @@ -466,6 +473,8 @@ RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data) for (i = 0; i < trows; i++) { + const byte *source; + row = (int)(i * hscale); if (row > rows) diff --git a/src/client/refresh/gl1/header/local.h b/src/client/refresh/gl1/header/local.h index 0ba71ff4..7add3f83 100644 --- a/src/client/refresh/gl1/header/local.h +++ b/src/client/refresh/gl1/header/local.h @@ -407,6 +407,6 @@ extern void RDraw_CharScaled(int x, int y, int num, float scale); extern void RDraw_TileClear(int x, int y, int w, int h, char *pic); extern void RDraw_Fill(int x, int y, int w, int h, int c); extern void RDraw_FadeScreen(void); -extern void RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data); +extern void RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int bits); #endif diff --git a/src/client/refresh/gl3/gl3_draw.c b/src/client/refresh/gl3/gl3_draw.c index e58a7dbb..0897180e 100644 --- a/src/client/refresh/gl3/gl3_draw.c +++ b/src/client/refresh/gl3/gl3_draw.c @@ -350,7 +350,7 @@ GL3_Draw_FadeScreen(void) } void -GL3_Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data) +GL3_Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int bits) { int i, j; @@ -360,20 +360,27 @@ GL3_Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data) unsigned* img = image32; - if(cols*rows > 320*240) + if (bits == 32) { - /* in case there is a bigger video after all, - * malloc enough space to hold the frame */ - img = (unsigned*)malloc(cols*rows*4); + img = (unsigned *)data; } - - for(i=0; i 320*240) { - byte palIdx = data[rowOffset+j]; - img[rowOffset+j] = gl3_rawpalette[palIdx]; + /* in case there is a bigger video after all, + * malloc enough space to hold the frame */ + img = (unsigned*)malloc(cols*rows*4); + } + + for(i=0; ivalue) + if (bits == 32) + { + image_scaled = malloc(cols * rows); + R_Convert32To8bit(data, image_scaled, cols * rows, false); + } + else if (r_retexturing->value) { if (cols < (w / 3) || rows < (h / 3)) { @@ -352,7 +357,7 @@ RE_Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data) } else { - image_scaled = data; + image_scaled = (byte *)data; } pic.pixels[0] = image_scaled; diff --git a/src/client/refresh/soft/sw_image.c b/src/client/refresh/soft/sw_image.c index 3c0e3a68..dca2f6aa 100644 --- a/src/client/refresh/soft/sw_image.c +++ b/src/client/refresh/soft/sw_image.c @@ -206,7 +206,7 @@ Get_BestImageSize(const image_t *image, int *req_width, int *req_height) static byte *d_16to8table = NULL; // 16 to 8 bit conversion table -static void +void R_Convert32To8bit(const unsigned char* pic_in, pixel_t* pic_out, size_t size, qboolean transparent) { diff --git a/src/client/vid/header/ref.h b/src/client/vid/header/ref.h index eff3ab80..23aabb2e 100644 --- a/src/client/vid/header/ref.h +++ b/src/client/vid/header/ref.h @@ -197,8 +197,11 @@ typedef struct void (EXPORT *DrawFill) (int x, int y, int w, int h, int c); void (EXPORT *DrawFadeScreen) (void); - // Draw images for cinematic rendering (which can have a different palette). Note that calls - void (EXPORT *DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, byte *data); + /* + * Draw images for cinematic rendering (which can have a different palette if bits equals to 8). + * Note that calls + */ + void (EXPORT *DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, const byte *data, int bits); /* ** video mode and refresh state management entry points @@ -278,7 +281,7 @@ void Draw_CharScaled(int x, int y, int num, float scale); void Draw_TileClear(int x, int y, int w, int h, char *name); void Draw_Fill(int x, int y, int w, int h, int c); void Draw_FadeScreen(void); -void Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data); +void Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int bits); //int R_Init(void *hinstance, void *hWnd); //void R_Shutdown(void); void R_SetPalette(const unsigned char *palette); diff --git a/src/client/vid/vid.c b/src/client/vid/vid.c index 87edcdd9..12cc6e86 100644 --- a/src/client/vid/vid.c +++ b/src/client/vid/vid.c @@ -735,11 +735,11 @@ Draw_FadeScreen(void) } void -Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data) +Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int bits) { if (ref_active) { - re.DrawStretchRaw(x, y, w, h, cols, rows, data); + re.DrawStretchRaw(x, y, w, h, cols, rows, data, bits); } }