From 444c36345e34df8a1565dd9913778faacb1d4363 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 29 May 2013 19:02:33 +0200 Subject: [PATCH] initial WebP support by graphitemaster --- cl_screen.c | 18 ++++++- cl_screen.h | 2 + gl_textures.c | 5 ++ image.c | 30 ++++++----- image_webp.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ image_webp.h | 40 +++++++++++++++ makefile.inc | 1 + 7 files changed, 221 insertions(+), 15 deletions(-) create mode 100644 image_webp.c create mode 100644 image_webp.h diff --git a/cl_screen.c b/cl_screen.c index 2a7af7dd..5f99d57d 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -51,6 +51,8 @@ cvar_t vid_pixelheight = {CVAR_SAVE, "vid_pixelheight", "1", "adjusts vertical f cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","1", "save jpeg instead of targa"}; cvar_t scr_screenshot_jpeg_quality = {CVAR_SAVE, "scr_screenshot_jpeg_quality","0.9", "image quality of saved jpeg"}; cvar_t scr_screenshot_png = {CVAR_SAVE, "scr_screenshot_png","0", "save png instead of targa"}; +cvar_t scr_screenshot_webp = {CVAR_SAVE, "scr_screenshot_webp", "0", "save webp instead of targa"}; +cvar_t scr_screenshot_webp_quality = {CVAR_SAVE, "scr_screenshot_webp_quality", "0.9", "image quality of saved webp"}; cvar_t scr_screenshot_gammaboost = {CVAR_SAVE, "scr_screenshot_gammaboost","1", "gamma correction on saved screenshots and videos, 1.0 saves unmodified images"}; cvar_t scr_screenshot_hwgamma = {CVAR_SAVE, "scr_screenshot_hwgamma","1", "apply the video gamma ramp to saved screenshots and videos"}; cvar_t scr_screenshot_alpha = {CVAR_SAVE, "scr_screenshot_alpha","0", "try to write an alpha channel to screenshots (debugging feature)"}; @@ -1332,6 +1334,8 @@ void CL_Screen_Init(void) Cvar_RegisterVariable (&scr_screenshot_jpeg); Cvar_RegisterVariable (&scr_screenshot_jpeg_quality); Cvar_RegisterVariable (&scr_screenshot_png); + Cvar_RegisterVariable (&scr_screenshot_webp); + Cvar_RegisterVariable (&scr_screenshot_webp_quality); Cvar_RegisterVariable (&scr_screenshot_gammaboost); Cvar_RegisterVariable (&scr_screenshot_hwgamma); Cvar_RegisterVariable (&scr_screenshot_name_in_mapdir); @@ -1404,6 +1408,7 @@ void SCR_ScreenShot_f (void) unsigned char *buffer2; qboolean jpeg = (scr_screenshot_jpeg.integer != 0); qboolean png = (scr_screenshot_png.integer != 0) && !jpeg; + qboolean webp = (scr_screenshot_webp.integer != 0) && !png; char vabuf[1024]; if (Cmd_Argc() == 2) @@ -1415,16 +1420,25 @@ void SCR_ScreenShot_f (void) { jpeg = true; png = false; + webp = false; } else if (!strcasecmp(ext, "tga")) { jpeg = false; png = false; + webp = false; } else if (!strcasecmp(ext, "png")) { jpeg = false; png = true; + webp = false; + } + else if (!strcasecmp(ext, "webp")) + { + jpeg = false; + png = false; + webp = true; } else { @@ -1454,7 +1468,7 @@ void SCR_ScreenShot_f (void) return; } - dpsnprintf(filename, sizeof(filename), "screenshots/%s-%02d.%s", prefix_name, shotnumber100, jpeg ? "jpg" : png ? "png" : "tga"); + dpsnprintf(filename, sizeof(filename), "screenshots/%s-%02d.%s", prefix_name, shotnumber100, jpeg ? "jpg" : png ? "png" : webp ? "webp" : "tga"); } else { @@ -1485,7 +1499,7 @@ void SCR_ScreenShot_f (void) return; } - dpsnprintf(filename, sizeof(filename), "screenshots/%s%06d.%s", prefix_name, shotnumber, jpeg ? "jpg" : png ? "png" : "tga"); + dpsnprintf(filename, sizeof(filename), "screenshots/%s%06d.%s", prefix_name, shotnumber, jpeg ? "jpg" : png ? "png" : webp ? "webp" : "tga"); shotnumber++; } diff --git a/cl_screen.h b/cl_screen.h index faf906b2..8d7a165c 100644 --- a/cl_screen.h +++ b/cl_screen.h @@ -12,6 +12,8 @@ extern cvar_t vid_pixelheight; extern cvar_t scr_screenshot_jpeg; extern cvar_t scr_screenshot_jpeg_quality; extern cvar_t scr_screenshot_png; +extern cvar_t scr_screenshot_webp; +extern cvar_t scr_screenshot_webp_quality; extern cvar_t scr_screenshot_gammaboost; extern cvar_t scr_screenshot_name; diff --git a/gl_textures.c b/gl_textures.c index 2dd11ebf..18ee3720 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -7,6 +7,7 @@ extern LPDIRECT3DDEVICE9 vid_d3d9dev; #include "image.h" #include "jpeg.h" #include "image_png.h" +#include "image_webp.h" #include "intoverflow.h" #include "dpsoftrast.h" @@ -795,6 +796,8 @@ static void r_textures_start(void) Cvar_SetValueQuick (&scr_screenshot_jpeg, 0); if (! PNG_OpenLibrary ()) Cvar_SetValueQuick (&scr_screenshot_png, 0); + if (! WEBP_OpenLibrary ()) + Cvar_SetValueQuick (&scr_screenshot_webp, 0); } static void r_textures_shutdown(void) @@ -802,6 +805,8 @@ static void r_textures_shutdown(void) rtexturepool_t *temp; JPEG_CloseLibrary (); + PNG_CloseLibrary (); + WEBP_CloseLibrary (); while(gltexturepoolchain) { diff --git a/image.c b/image.c index 366e80dd..14704620 100644 --- a/image.c +++ b/image.c @@ -3,6 +3,7 @@ #include "image.h" #include "jpeg.h" #include "image_png.h" +#include "image_webp.h" #include "r_shadow.h" int image_width; @@ -881,29 +882,32 @@ imageformat_t imageformats_dq[] = imageformat_t imageformats_textures[] = { - {"%s.tga", LoadTGA_BGRA}, - {"%s.png", PNG_LoadImage_BGRA}, - {"%s.jpg", JPEG_LoadImage_BGRA}, - {"%s.pcx", LoadPCX_BGRA}, - {"%s.wal", LoadWAL_BGRA}, + {"%s.tga", LoadTGA_BGRA}, + {"%s.png", PNG_LoadImage_BGRA}, + {"%s.jpg", JPEG_LoadImage_BGRA}, + {"%s.pcx", LoadPCX_BGRA}, + {"%s.wal", LoadWAL_BGRA}, + {"%s.webp", WEBP_LoadImage_BGRA}, {NULL, NULL} }; imageformat_t imageformats_gfx[] = { - {"%s.tga", LoadTGA_BGRA}, - {"%s.png", PNG_LoadImage_BGRA}, - {"%s.jpg", JPEG_LoadImage_BGRA}, - {"%s.pcx", LoadPCX_BGRA}, + {"%s.tga", LoadTGA_BGRA}, + {"%s.png", PNG_LoadImage_BGRA}, + {"%s.jpg", JPEG_LoadImage_BGRA}, + {"%s.pcx", LoadPCX_BGRA}, + {"%s.webp", WEBP_LoadImage_BGRA}, {NULL, NULL} }; imageformat_t imageformats_other[] = { - {"%s.tga", LoadTGA_BGRA}, - {"%s.png", PNG_LoadImage_BGRA}, - {"%s.jpg", JPEG_LoadImage_BGRA}, - {"%s.pcx", LoadPCX_BGRA}, + {"%s.tga", LoadTGA_BGRA}, + {"%s.png", PNG_LoadImage_BGRA}, + {"%s.jpg", JPEG_LoadImage_BGRA}, + {"%s.pcx", LoadPCX_BGRA}, + {"%s.webp", WEBP_LoadImage_BGRA}, {NULL, NULL} }; diff --git a/image_webp.c b/image_webp.c new file mode 100644 index 00000000..bd86ceb3 --- /dev/null +++ b/image_webp.c @@ -0,0 +1,140 @@ +/* + Copyright (C) 2013 Dale "graphitemaster" Weiler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + (comment) + * I Dale Weiler allow this code to be relicensed if required. + * The GPL is just for compatability with darkplaces. If in the + * distant future this code needs to be relicensed for what ever + * reason, I herby allow it, no questions asked. Consider this + * public domain. + (endcomment) +*/ + +#include "quakedef.h" +#include "image.h" +#include "image_webp.h" + +static int (*qwebp_get_info) (const unsigned char *, size_t, int *, int *); +static unsigned char *(*qwebp_decode_bgra_into) (const unsigned char *, size_t, unsigned char *, size_t, int); +static size_t (*qwebp_encode_rgb) (const unsigned char *, int, int, int, float, unsigned char **); +static size_t (*qwebp_encode_rgba) (const unsigned char *, int, int, int, float, unsigned char **); + +static dllfunction_t webpfuncs[] = +{ + {"WebPGetInfo", (void **) &qwebp_get_info}, + {"WebPDecodeBGRAInto", (void **) &qwebp_decode_bgra_into}, + {"WebPEncodeRGB", (void **) &qwebp_encode_rgb}, + {"WebPEncodeRGBA", (void **) &qwebp_encode_rgba}, + {NULL, NULL} +}; + +dllhandle_t webp_dll = NULL; + +qboolean WEBP_OpenLibrary (void) +{ + + // anything older than 2 doesn't have WebPGetInfo + const char* dllnames [] = + { +#if WIN32 + "libwebp-4.dll", // always search newest version + "libwebp-3.dll", + "libwebp-2.dll", // this one ships with SDL2 + "libwebp_a.dll", // this one only ships with old SDL releases +#elif defined(MACOSX) + "libwebp.dylib", // no versions for OSX +#else + "libwebp.so.4", + "libwebp.so.3", + "libwebp.so.2", + "libwebp.so.0", + "libwebp.so", +#endif + NULL + }; + + if (webp_dll) + return true; + + if(!Sys_LoadLibrary (dllnames, &webp_dll, webpfuncs)) + return false; + + return true; +} + +void WEBP_CloseLibrary (void) +{ + Sys_UnloadLibrary (&webp_dll); +} + +unsigned char *WEBP_LoadImage_BGRA (const unsigned char *raw, int filesize, int *miplevel) +{ + unsigned char *data = NULL; + + if (!webp_dll) + return NULL; + + if (!qwebp_get_info(raw, filesize, &image_width, &image_height)) + return NULL; + + if ((data = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4))) + { + if (!qwebp_decode_bgra_into(raw, filesize, data, 4 * image_height, 4)) + { + Con_Printf("WEBP_LoadImage : failed decode\n"); + Mem_Free(data); + return NULL; + } + return data; + } + + Con_Printf("WEBP_LoadImage : not enough memory\n"); + return NULL; +} + + +qboolean WEBP_SaveImage_preflipped (const char *filename, int width, int height, qboolean has_alpha, unsigned char *data) +{ + qfile_t *file = NULL; + unsigned char *memory = NULL; + unsigned int wrote = 0; + + size_t (*encode)(const unsigned char *, int, int, int, float, unsigned char **) = (has_alpha) + ? qwebp_encode_rgba + : qwebp_encode_rgb; + + + if (!(wrote = encode(data, width, height, 4, scr_screenshot_webp_quality.value * 100, &memory))) + return false; + + + if (!(file = FS_OpenRealFile(filename, "wb", true))) + { + free(memory); + return false; + } + + FS_Write(file, memory, wrote); + FS_Close(file); + + free(memory); + return true; +} diff --git a/image_webp.h b/image_webp.h new file mode 100644 index 00000000..7b17d52c --- /dev/null +++ b/image_webp.h @@ -0,0 +1,40 @@ +/* + Copyright (C) 2013 Dale "graphitemaster" Weiler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + (comment) + * I Dale Weiler allow this code to be relicensed if required. + * The GPL is just for compatability with darkplaces. If in the + * distant future this code needs to be relicensed for what ever + * reason, I herby allow it, no questions asked. Consider this + * public domain. + (endcomment) +*/ + +#ifndef WEBP_H +#define WEBP_H + +qboolean WEBP_OpenLibrary (void); +void WEBP_CloseLibrary (void); +unsigned char* WEBP_LoadImage_BGRA (const unsigned char *f, int filesize, int *miplevel); +qboolean WEBP_SaveImage_preflipped (const char *filename, int width, int height, qboolean has_alpha, unsigned char *data); + +#endif + diff --git a/makefile.inc b/makefile.inc index fe1eabe1..7ad855e2 100644 --- a/makefile.inc +++ b/makefile.inc @@ -133,6 +133,7 @@ OBJ_COMMON= \ host_cmd.o \ image.o \ image_png.o \ + image_webp.o \ jpeg.o \ keys.o \ lhnet.o \ -- 2.39.2