Skip to content

Commit

Permalink
Merge branch 'LIGHT-surfaces'
Browse files Browse the repository at this point in the history
  • Loading branch information
apanteleev committed Aug 9, 2021
2 parents c3046f4 + cf65b63 commit e8d1a5c
Show file tree
Hide file tree
Showing 10 changed files with 722 additions and 108 deletions.
2 changes: 2 additions & 0 deletions inc/refresh/images.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ extern uint32_t d_8to24table[256];
// these are implemented in src/refresh/images.c
void IMG_ReloadAll();
image_t *IMG_Find(const char *name, imagetype_t type, imageflags_t flags);
image_t *IMG_FindExisting(const char *name, imagetype_t type);
image_t *IMG_Clone(image_t *image, const char* new_name);
void IMG_FreeUnused(void);
void IMG_FreeAll(void);
void IMG_Init(void);
Expand Down
1 change: 1 addition & 0 deletions inc/refresh/refresh.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ typedef enum {
IF_NEAREST = (1 << 7),
IF_OPAQUE = (1 << 8),
IF_SRGB = (1 << 9),
IF_FAKE_EMISSIVE= (1 << 10),

// Image source indicator/requirement flags
IF_SRC_BASE = (0x1 << 16),
Expand Down
5 changes: 5 additions & 0 deletions inc/shared/shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ static inline float Q_fabs(float f)
#define Vector4Clear(a) ((a)[0]=(a)[1]=(a)[2]=(a)[3]=0)
#define Vector4Negate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2],(b)[3]=-(a)[3])
#define Vector4Set(v, a, b, c, d) ((v)[0]=(a),(v)[1]=(b),(v)[2]=(c),(v)[3]=(d))
#define Vector4MA(a,b,c,d) \
((d)[0]=(a)[0]+(b)*(c)[0], \
(d)[1]=(a)[1]+(b)*(c)[1], \
(d)[2]=(a)[2]+(b)*(c)[2], \
(d)[3]=(a)[3]+(b)*(c)[3])

#define QuatCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])

Expand Down
290 changes: 197 additions & 93 deletions src/refresh/images.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "stb_image.h"
#include "stb_image_write.h"

#include <assert.h>

#define R_COLORMAP_PCX "pics/colormap.pcx"

#define IMG_LOAD(x) \
Expand Down Expand Up @@ -802,6 +804,24 @@ static int _try_image_format(imageformat_t fmt, image_t *image, int try_src, byt
if (!data) {
return len;
}
/* Don't prefer game image if it's identical to the base version
Some games (eg rogue) ship image assets that are identical to the
baseq2 version.
If that is the case, prefer the baseq2 copy - because those may have
override image and additional material images!
*/
if (try_src == TRY_IMAGE_SRC_GAME) {
byte *data_base;
ssize_t len_base;
len_base = FS_LoadFileFlags(image->name, (void **)&data_base, FS_PATH_BASE);
if((len == len_base) && (memcmp(data, data_base, len) == 0)) {
// Identical data in game, pretend file doesn't exist
FS_FreeFile(data);
FS_FreeFile(data_base);
return Q_ERR_NOENT;
}
FS_FreeFile(data_base);
}

// decompress the image
ret = img_loaders[fmt].load(data, len, image, pic);
Expand Down Expand Up @@ -988,12 +1008,6 @@ load_img(const char *name, image_t *image)
get_image_dimensions(fmt, image);
}

// if we are replacing 8-bit texture with a higher resolution 32-bit
// texture, we need to recover original image dimensions
if (fmt <= IM_WAL && ret > IM_WAL) {
get_image_dimensions(fmt, image);
}

if (ret < 0) {
memset(image, 0, sizeof(*image));
return ret;
Expand All @@ -1006,6 +1020,74 @@ load_img(const char *name, image_t *image)
return Q_ERR_SUCCESS;
}

// Try to load an image, possibly with an alternative extension
static qerror_t try_load_image_candidate(image_t *image, const char *orig_name, size_t orig_len, byte **pic_p, imagetype_t type, imageflags_t flags, qboolean ignore_extension, int try_location)
{
qerror_t ret;

image->type = type;
image->flags = flags;
image->registration_sequence = registration_sequence;

// find out original extension
imageformat_t fmt;
for (fmt = 0; fmt < IM_MAX; fmt++)
{
if (!Q_stricmp(image->name + image->baselen + 1, img_loaders[fmt].ext))
{
break;
}
}

// load the pic from disk
*pic_p = NULL;

if (fmt == IM_MAX)
{
// unknown extension, but give it a chance to load anyway
ret = try_other_formats(IM_MAX, image, try_location, pic_p);
if (ret == Q_ERR_NOENT)
{
// not found, change error to invalid path
ret = Q_ERR_INVALID_PATH;
}
}
else if (ignore_extension)
{
// forcibly replace the extension
ret = try_other_formats(IM_MAX, image, try_location, pic_p);
}
else
{
// first try with original extension
ret = _try_image_format(fmt, image, try_location, pic_p);
if (ret == Q_ERR_NOENT)
{
// retry with remaining extensions
ret = try_other_formats(fmt, image, try_location, pic_p);
}
}

// record last modified time (skips reload when invoking IMG_ReloadAll)
image->last_modified = 0;
FS_LastModified(image->name, &image->last_modified);

// Restore original name if it was overridden
if(orig_name) {
memcpy(image->name, orig_name, orig_len + 1);
image->baselen = orig_len - 4;
}

// if we are replacing 8-bit texture with a higher resolution 32-bit
// texture, we need to recover original image dimensions
if (fmt <= IM_WAL && ret > IM_WAL)
{
get_image_dimensions(fmt, image);
}

return ret;
}

// finds or loads the given image, adding it to the hash table.
static qerror_t find_or_load_image(const char *name, size_t len,
imagetype_t type, imageflags_t flags,
Expand All @@ -1014,7 +1096,6 @@ static qerror_t find_or_load_image(const char *name, size_t len,
image_t *image;
byte *pic;
unsigned hash;
imageformat_t fmt;
qerror_t ret;

*image_p = NULL;
Expand Down Expand Up @@ -1047,100 +1128,43 @@ static qerror_t find_or_load_image(const char *name, size_t len,
if (!vid_rtx->integer && (type != IT_PIC))
override_textures = 0;

// Always prefer images from the game dir, even if format might be 'inferior'
for (int try_location = Q_stricmp(fs_game->string, BASEGAME) ? TRY_IMAGE_SRC_GAME : TRY_IMAGE_SRC_BASE;
try_location >= TRY_IMAGE_SRC_BASE;
try_location--)
if(override_textures)
{
int location_flag = try_location == TRY_IMAGE_SRC_GAME ? IF_SRC_GAME : IF_SRC_MASK;
if(((flags & IF_SRC_MASK) != 0) && ((flags & IF_SRC_MASK) != location_flag))
continue;

for (int use_override = override_textures; use_override >= 0; use_override--)
{
// fill in some basic info
if (use_override)
{
const char *last_slash = strrchr(name, '/');
if (!last_slash)
last_slash = name;
else
last_slash += 1;

strcpy(image->name, "overrides/");
strcat(image->name, last_slash);
image->baselen = strlen(image->name) - 4;
}
else
{
memcpy(image->name, name, len + 1);
image->baselen = len - 4;
}
image->type = type;
image->flags = flags | location_flag;
image->registration_sequence = registration_sequence;

// find out original extension
for (fmt = 0; fmt < IM_MAX; fmt++)
{
if (!Q_stricmp(image->name + image->baselen + 1, img_loaders[fmt].ext))
{
break;
}
}

// load the pic from disk
pic = NULL;

if (fmt == IM_MAX)
{
// unknown extension, but give it a chance to load anyway
ret = try_other_formats(IM_MAX, image, try_location, &pic);
if (ret == Q_ERR_NOENT)
{
// not found, change error to invalid path
ret = Q_ERR_INVALID_PATH;
}
}
else if (override_textures)
{
// forcibly replace the extension
ret = try_other_formats(IM_MAX, image, try_location, &pic);
}
else
{
// first try with original extension
ret = _try_image_format(fmt, image, try_location, &pic);
if (ret == Q_ERR_NOENT)
{
// retry with remaining extensions
ret = try_other_formats(fmt, image, try_location, &pic);
}
}
const char *last_slash = strrchr(name, '/');
if (!last_slash)
last_slash = name;
else
last_slash += 1;

// record last modified time (skips reload when invoking IMG_ReloadAll)
image->last_modified = 0;
FS_LastModified(image->name, &image->last_modified);
strcpy(image->name, "overrides/");
strcat(image->name, last_slash);
image->baselen = strlen(image->name) - 4;
ret = try_load_image_candidate(image, name, len, &pic, type, flags, qtrue, -1);
memcpy(image->name, name, len + 1);
image->baselen = len - 4;
}

if (use_override)
{
memcpy(image->name, name, len + 1);
image->baselen = len - 4;
}
// Try non-overridden image
if (ret < 0)
{
// Always prefer images from the game dir, even if format might be 'inferior'
for (int try_location = Q_stricmp(fs_game->string, BASEGAME) ? TRY_IMAGE_SRC_GAME : TRY_IMAGE_SRC_BASE;
try_location >= TRY_IMAGE_SRC_BASE;
try_location--)
{
int location_flag = try_location == TRY_IMAGE_SRC_GAME ? IF_SRC_GAME : IF_SRC_MASK;
if(((flags & IF_SRC_MASK) != 0) && ((flags & IF_SRC_MASK) != location_flag))
continue;

// if we are replacing 8-bit texture with a higher resolution 32-bit
// texture, we need to recover original image dimensions
if (fmt <= IM_WAL && ret > IM_WAL)
{
get_image_dimensions(fmt, image);
}
// fill in some basic info
memcpy(image->name, name, len + 1);
image->baselen = len - 4;
ret = try_load_image_candidate(image, NULL, 0, &pic, type, flags, !!override_textures, try_location);
image->flags |= location_flag;

if (ret >= 0)
break;
}

if (ret >= 0)
break;
}

if (ret < 0) {
Expand Down Expand Up @@ -1188,6 +1212,86 @@ image_t *IMG_Find(const char *name, imagetype_t type, imageflags_t flags)
return R_NOTEXTURE;
}

image_t *IMG_FindExisting(const char *name, imagetype_t type)
{
image_t *image;
size_t len;
unsigned hash;

if (!name) {
Com_Error(ERR_FATAL, "%s: NULL", __func__);
}

// this should never happen
len = strlen(name);
if (len >= MAX_QPATH) {
Com_Error(ERR_FATAL, "%s: oversize name", __func__);
}

// must have an extension and at least 1 char of base name
if (len <= 4) {
return R_NOTEXTURE;
}
if (name[len - 4] != '.') {
return R_NOTEXTURE;
}

hash = FS_HashPathLen(name, len - 4, RIMAGES_HASH);

// look for it
if ((image = lookup_image(name, type, hash, len - 4)) != NULL) {
return image;
}

return R_NOTEXTURE;
}

/*
===============
IMG_Clone
===============
*/
image_t *IMG_Clone(image_t *image, const char* new_name)
{
if(image == R_NOTEXTURE)
return image;

image_t* new_image = alloc_image();
if (!new_image)
return R_NOTEXTURE;

memcpy(new_image, image, sizeof(image_t));

#if USE_REF == REF_VKPT
size_t image_size = image->upload_width * image->upload_height * 4;
if(image->pix_data != NULL)
{
new_image->pix_data = IMG_AllocPixels(image_size);
memcpy(new_image->pix_data, image->pix_data, image_size);
}
#else
for (int m = 0; m < 4; m++)
{
if(image->pixels[m] != NULL)
{
size_t mip_size = (image->upload_width >> m) * (image->upload_height >> m) * 4;
new_image->pixels[m] = IMG_AllocPixels(mip_size);
memcpy(new_image->pixels[m], image->pixels[m], mip_size);
}
}
#endif

if(new_name)
{
Q_strlcpy(new_image->name, new_name, sizeof(new_image->name));
new_image->baselen = strlen(new_image->name) - 4;
assert(new_image->name[new_image->baselen] == '.');
}
unsigned hash = FS_HashPathLen(new_image->name, new_image->baselen, RIMAGES_HASH);
List_Append(&r_imageHash[hash], &new_image->entry);
return new_image;
}

/*
===============
IMG_ForHandle
Expand Down
Loading

0 comments on commit e8d1a5c

Please sign in to comment.