From b78becde4c6a8994e3ccbce84f97ba4a3d650c6e Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Mon, 3 Mar 2025 05:49:16 +0100 Subject: [PATCH] Fix loading ridiculously large non-POT-textures After loading a texture, Doom3 calculates an MD4-sum of it.. this is mostly pointless and only used for the "reportImageDuplication" console command, but whatever. The problem here was that the image was 32000x2000 pixels (due to some error when creating it) which dhewm3 wanted to convert to the next bigger power-of-two values with R_ResampleTexture(), but that function clamps to 4096x4096, so the actually used pixeldata was for 2048x4096. However, R_ResampleTexture() didn't communicate this to its caller, and thus a too big size was used for calculating the MD4-sum and it crashed. That's fixed now and also a warning is printed about this. --- neo/renderer/Image.h | 2 +- neo/renderer/Image_files.cpp | 12 +++++++++--- neo/renderer/Image_process.cpp | 12 +++++++----- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/neo/renderer/Image.h b/neo/renderer/Image.h index 34515a37..5eac4531 100644 --- a/neo/renderer/Image.h +++ b/neo/renderer/Image.h @@ -468,7 +468,7 @@ FIXME: make an "imageBlock" type to hold byte*,width,height? byte *R_Dropsample( const byte *in, int inwidth, int inheight, int outwidth, int outheight ); byte *R_ResampleTexture( const byte *in, int inwidth, int inheight, - int outwidth, int outheight ); + int& outwidth, int& outheight ); byte *R_MipMapWithAlphaSpecularity( const byte *in, int width, int height ); byte *R_MipMap( const byte *in, int width, int height, bool preserveBorder ); byte *R_MipMap3D( const byte *in, int width, int height, int depth, bool preserveBorder ); diff --git a/neo/renderer/Image_files.cpp b/neo/renderer/Image_files.cpp index 174d544d..7871bc58 100644 --- a/neo/renderer/Image_files.cpp +++ b/neo/renderer/Image_files.cpp @@ -902,12 +902,18 @@ void R_LoadImage( const char *cname, byte **pic, int *width, int *height, ID_TIM if ( globalImages->image_roundDown.GetBool() && scaled_height > h ) { scaled_height >>= 1; } + int outWidth = scaled_width; + int outHeight = scaled_height; + resampledBuffer = R_ResampleTexture( *pic, w, h, outWidth, outHeight ); + if ( outWidth != scaled_width || outHeight != scaled_height ) { + common->Warning( "Texture '%s' didn't have power-of-two size *and* was too big, scaled from %dx%d to %dx%d", + name.c_str(), w, h, outWidth, outHeight ); + } - resampledBuffer = R_ResampleTexture( *pic, w, h, scaled_width, scaled_height ); R_StaticFree( *pic ); *pic = resampledBuffer; - *width = scaled_width; - *height = scaled_height; + *width = outWidth; + *height = outHeight; } } } diff --git a/neo/renderer/Image_process.cpp b/neo/renderer/Image_process.cpp index 920aad18..6027d930 100644 --- a/neo/renderer/Image_process.cpp +++ b/neo/renderer/Image_process.cpp @@ -46,7 +46,7 @@ after resampling to the next lower power of two. */ #define MAX_DIMENSION 4096 byte *R_ResampleTexture( const byte *in, int inwidth, int inheight, - int outwidth, int outheight ) { + int& _outwidth, int& _outheight ) { int i, j; const byte *inrow, *inrow2; unsigned int frac, fracstep; @@ -54,12 +54,14 @@ byte *R_ResampleTexture( const byte *in, int inwidth, int inheight, const byte *pix1, *pix2, *pix3, *pix4; byte *out, *out_p; - if ( outwidth > MAX_DIMENSION ) { - outwidth = MAX_DIMENSION; + if ( _outwidth > MAX_DIMENSION ) { + _outwidth = MAX_DIMENSION; } - if ( outheight > MAX_DIMENSION ) { - outheight = MAX_DIMENSION; + if ( _outheight > MAX_DIMENSION ) { + _outheight = MAX_DIMENSION; } + int outwidth = _outwidth; + int outheight = _outheight; out = (byte *)R_StaticAlloc( outwidth * outheight * 4 ); out_p = out;