Merge remote-tracking branch '0lvin/rerelease'

This commit is contained in:
Yamagi 2023-09-16 17:29:36 +02:00
commit 203780b613
23 changed files with 405 additions and 178 deletions

View file

@ -460,6 +460,7 @@ set(Client-Source
${COMMON_SRC_DIR}/shared/flash.c
${COMMON_SRC_DIR}/shared/rand.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/unzip/ioapi.c
${COMMON_SRC_DIR}/unzip/miniz.c
${COMMON_SRC_DIR}/unzip/unzip.c
@ -523,6 +524,7 @@ set(Server-Source
${COMMON_SRC_DIR}/zone.c
${COMMON_SRC_DIR}/shared/rand.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/unzip/ioapi.c
${COMMON_SRC_DIR}/unzip/miniz.c
${COMMON_SRC_DIR}/unzip/unzip.c
@ -573,6 +575,7 @@ set(GL1-Source
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/pvs.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/md4.c
)
@ -609,6 +612,7 @@ set(GL3-Source
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/pvs.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/md4.c
)
@ -663,6 +667,7 @@ set(SOFT-Source
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/pvs.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/md4.c
)

View file

@ -882,6 +882,7 @@ CLIENT_OBJS_ := \
src/common/shared/flash.o \
src/common/shared/rand.o \
src/common/shared/shared.o \
src/common/shared/utils.o \
src/common/unzip/ioapi.o \
src/common/unzip/miniz.o \
src/common/unzip/unzip.o \
@ -934,6 +935,7 @@ REFGL1_OBJS_ := \
src/client/refresh/files/wal.o \
src/client/refresh/files/pvs.o \
src/common/shared/shared.o \
src/common/shared/utils.o \
src/common/md4.o
ifeq ($(YQ2_OSTYPE), Windows)
@ -966,6 +968,7 @@ REFGL3_OBJS_ := \
src/client/refresh/files/wal.o \
src/client/refresh/files/pvs.o \
src/common/shared/shared.o \
src/common/shared/utils.o \
src/common/md4.o
REFGL3_OBJS_GLADE_ := \
@ -1009,6 +1012,7 @@ REFSOFT_OBJS_ := \
src/client/refresh/files/wal.o \
src/client/refresh/files/pvs.o \
src/common/shared/shared.o \
src/common/shared/utils.o \
src/common/md4.o
ifeq ($(YQ2_OSTYPE), Windows)
@ -1041,6 +1045,7 @@ SERVER_OBJS_ := \
src/common/zone.o \
src/common/shared/rand.o \
src/common/shared/shared.o \
src/common/shared/utils.o \
src/common/unzip/ioapi.o \
src/common/unzip/miniz.o \
src/common/unzip/unzip.o \

View file

@ -688,7 +688,7 @@ IN_Update(void)
event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
{
Key_MarkAllUp();
if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
{
S_Activate(false);
@ -1696,116 +1696,6 @@ static char *default_haptic_filter = (
"world/*train2 "
);
/*
* name: sound name
* filter: sound name rule with '*'
* return false for empty filter
*/
static qboolean
Haptic_Feedback_Filtered_Line(const char *name, const char *filter)
{
const char *current_filter = filter;
// skip empty filter
if (!*current_filter)
{
return false;
}
while (*current_filter)
{
char part_filter[MAX_QPATH];
const char *name_part;
const char *str_end;
str_end = strchr(current_filter, '*');
if (!str_end)
{
if (!strstr(name, current_filter))
{
// no such part in string
return false;
}
// have such part
break;
}
// copy filter line
if ((str_end - current_filter) >= MAX_QPATH)
{
return false;
}
memcpy(part_filter, current_filter, str_end - current_filter);
part_filter[str_end - current_filter] = 0;
// place part in name
name_part = strstr(name, part_filter);
if (!name_part)
{
// no such part in string
return false;
}
// have such part
name = name_part + strlen(part_filter);
// move to next filter
current_filter = str_end + 1;
}
return true;
}
/*
* name: sound name
* filter: sound names separated by space, and '!' for skip file
*/
static qboolean
Haptic_Feedback_Filtered(const char *name, const char *filter)
{
const char *current_filter = filter;
while (*current_filter)
{
char line_filter[MAX_QPATH];
const char *str_end;
str_end = strchr(current_filter, ' ');
// its end of filter
if (!str_end)
{
// check rules inside line
if (Haptic_Feedback_Filtered_Line(name, current_filter))
{
return true;
}
return false;
}
// copy filter line
if ((str_end - current_filter) >= MAX_QPATH)
{
return false;
}
memcpy(line_filter, current_filter, str_end - current_filter);
line_filter[str_end - current_filter] = 0;
// check rules inside line
if (*line_filter == '!')
{
// has invert rule
if (Haptic_Feedback_Filtered_Line(name, line_filter + 1))
{
return false;
}
}
else
{
if (Haptic_Feedback_Filtered_Line(name, line_filter))
{
return true;
}
}
// move to next filter
current_filter = str_end + 1;
}
return false;
}
/*
* Haptic Feedback:
* effect_volume=0..SHRT_MAX
@ -1841,7 +1731,7 @@ Haptic_Feedback(const char *name, int effect_volume, int effect_duration,
last_haptic_volume = joy_haptic_magnitude->value * 16;
if (Haptic_Feedback_Filtered(name, haptic_feedback_filter->string))
if (Utils_FilenameFiltered(name, haptic_feedback_filter->string, ' '))
{
int effect_id;

View file

@ -312,23 +312,180 @@ GetPCXInfo(const char *origname, int *width, int *height)
return;
}
static byte
Convert24to8(const byte *d_8to24table, const int rgb[3])
{
int i, best, diff;
best = 255;
diff = 1 << 20;
for (i = 0; i < 256; i ++)
{
int j, curr_diff;
curr_diff = 0;
for (j = 0; j < 3; j++)
{
int v;
v = d_8to24table[i * 4 + j] - rgb[j];
curr_diff += v * v;
}
if (curr_diff < diff)
{
diff = curr_diff;
best = i;
}
}
return best;
}
static void
GenerateColormap(const byte *palette, byte *out_colormap)
{
// https://quakewiki.org/wiki/Quake_palette
int num_fullbrights = 32; /* the last 32 colours will be full bright */
int x;
for (x = 0; x < 256; x++)
{
int y;
for (y = 0; y < 64; y++)
{
if (x < 256 - num_fullbrights)
{
int rgb[3], i;
for (i = 0; i < 3; i++)
{
/* divide by 32, rounding to nearest integer */
rgb[i] = (palette[x * 4 + i] * (63 - y) + 16) >> 5;
if (rgb[i] > 255)
{
rgb[i] = 255;
}
}
out_colormap[y*256+x] = Convert24to8(palette, rgb);
}
else
{
/* this colour is a fullbright, just keep the original colour */
out_colormap[y*256+x] = x;
}
}
}
}
void
GetPCXPalette24to8(byte *d_8to24table, byte** d_16to8table)
{
unsigned char * table16to8;
char tablefile[] = "pics/16to8.dat";
*d_16to8table = NULL;
ri.FS_LoadFile(tablefile, (void **)&table16to8);
if (!table16to8)
{
R_Printf(PRINT_ALL, "%s: Couldn't load %s\n", __func__, tablefile);
}
*d_16to8table = malloc(0x10000);
if (!(*d_16to8table))
{
ri.Sys_Error(ERR_FATAL, "%s: Couldn't allocate memory for d_16to8table", __func__);
// code never returns after ERR_FATAL
return;
}
if (table16to8)
{
// Use predefined convert map
memcpy(*d_16to8table, table16to8, 0x10000);
ri.FS_FreeFile((void *)table16to8);
}
else
{
// create new one
unsigned int r;
R_Printf(PRINT_ALL, "%s: Generate 16 to 8 bit table\n", __func__);
for (r = 0; r < 32; r++)
{
int g;
for (g = 0; g < 64; g++)
{
int b;
for (b = 0; b < 32; b++)
{
int c, rgb[3];
rgb[0] = r << 3;
rgb[1] = g << 2;
rgb[2] = b << 3;
c = r | ( g << 5 ) | ( b << 11 );
// set color with minimal difference
(*d_16to8table)[c & 0xFFFF] = Convert24to8(d_8to24table, rgb);
}
}
}
}
}
/*
===============
GetPCXPalette
===============
*/
void
GetPCXPalette (byte **colormap, unsigned *d_8to24table)
GetPCXPalette(byte **colormap, unsigned *d_8to24table)
{
char filename[] = "pics/colormap.pcx";
byte *pal;
int i;
/* get the palette and colormap */
LoadPCX ("pics/colormap.pcx", colormap, &pal, NULL, NULL);
LoadPCX(filename, colormap, &pal, NULL, NULL);
if (!*colormap || !pal)
{
ri.Sys_Error (ERR_FATAL, "%s: Couldn't load pics/colormap.pcx",
__func__);
R_Printf(PRINT_ALL, "%s: Couldn't load %s, use generated palette\n",
__func__, filename);
/* palette r:2bit, g:3bit, b:3bit */
for (i=0 ; i < 256; i++)
{
unsigned v;
v = (255U<<24) + (((i >> 0) & 0x3) << (6 + 0)) +
(((i >> 2) & 0x7) << (5 + 8)) +
(((i >> 5) & 0x7) << (5 + 16));
d_8to24table[i] = LittleLong(v);
}
d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent
/* generate colormap */
*colormap = malloc(256 * 320);
if (!(*colormap))
{
ri.Sys_Error(ERR_FATAL, "%s: Couldn't allocate memory for colormap", __func__);
// code never returns after ERR_FATAL
return;
}
GenerateColormap((const byte *)d_8to24table, *colormap);
return;
}
for (i=0 ; i<256 ; i++)

View file

@ -513,12 +513,40 @@ R_LoadImage(const char *name, const char* namewe, const char *ext, imagetype_t t
LoadPCX (namewe, &pic, &palette, &width, &height);
if (!pic)
{
return NULL;
}
image = load_image(name, pic,
width, width,
height, height,
width * height, type, 8);
if (r_retexturing && palette)
{
byte *image_buffer = NULL;
int i, size;
size = width * height;
image_buffer = malloc (size * 4);
for(i = 0; i < size; i++)
{
unsigned char value = pic[i];
image_buffer[i * 4 + 0] = palette[value * 3 + 0];
image_buffer[i * 4 + 1] = palette[value * 3 + 1];
image_buffer[i * 4 + 2] = palette[value * 3 + 2];
image_buffer[i * 4 + 3] = value == 255 ? 0 : 255;
}
image = load_image(name, image_buffer,
width, width,
height, height,
size, type, 32);
free (image_buffer);
}
else
{
image = load_image(name, pic,
width, width,
height, height,
width * height, type, 8);
}
if (palette)
{
@ -611,6 +639,13 @@ GetTexImage(const char *name, findimage_t find_image)
Com_sprintf(pathname, sizeof(pathname), "textures/%s.wal", name);
image = find_image(pathname, it_wall);
/* Quake2 Re-Release Nintendo 64 */
if (!image)
{
Com_sprintf(pathname, sizeof(pathname), "textures/%s.tga", name);
image = find_image(pathname, it_wall);
}
/* Heretic 2 */
if (!image)
{
@ -640,6 +675,13 @@ R_FindPic(const char *name, findimage_t find_image)
Com_sprintf(pathname, sizeof(pathname), "pics/%s.pcx", name);
image = find_image(pathname, it_pic);
/* Quake 2 Re-Release */
if (!image)
{
Com_sprintf(pathname, sizeof(pathname), "pics/%s.png", name);
image = find_image(pathname, it_pic);
}
/* Heretic 2 */
if (!image)
{

View file

@ -40,7 +40,7 @@ Draw_InitLocal(void)
draw_chars = R_FindPic("conchars", (findimage_t)R_FindImage);
if (!draw_chars)
{
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/conchars.pcx",
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/conchars",
__func__);
}
}

View file

@ -223,9 +223,9 @@ R_TextureMode(char *string)
if (unfiltered2D && glt->type == it_pic)
{
// exception to that exception: stuff on the r_lerp_list
nolerp = (lerplist== NULL) || (strstr(lerplist, glt->name) == NULL);
nolerp = (lerplist == NULL) || Utils_FilenameFiltered(glt->name, lerplist, ' ');
}
else if(nolerplist != NULL && strstr(nolerplist, glt->name) != NULL)
else if (nolerplist != NULL && Utils_FilenameFiltered(glt->name, nolerplist, ' '))
{
nolerp = true;
}
@ -1166,7 +1166,6 @@ R_ImageHasFreeSpace(void)
void
R_InitImages(void)
{
byte *colormap;
int i, j;
registration_sequence = 1;
@ -1182,21 +1181,6 @@ R_InitImages(void)
gl_state.inverse_intensity = 1 / intensity->value;
// FIXME: I think this is redundant - RI_Init() already calls that!
GetPCXPalette (&colormap, d_8to24table);
free(colormap);
if (gl_config.palettedtexture)
{
ri.FS_LoadFile("pics/16to8.dat", (void **)&gl_state.d_16to8table);
if (!gl_state.d_16to8table)
{
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/16to8.pcx",
__func__);
}
}
for (i = 0; i < 256; i++)
{
gammatable[i] = i;

View file

@ -1229,7 +1229,7 @@ R_Register(void)
r_scale8bittextures = ri.Cvar_Get("r_scale8bittextures", "0", CVAR_ARCHIVE);
/* don't bilerp characters and crosshairs */
gl_nolerp_list = ri.Cvar_Get("r_nolerp_list", "pics/conchars.pcx pics/ch1.pcx pics/ch2.pcx pics/ch3.pcx", CVAR_ARCHIVE);
gl_nolerp_list = ri.Cvar_Get("r_nolerp_list", DEFAULT_NOLERP_LIST, CVAR_ARCHIVE);
/* textures that should always be filtered, even if r_2D_unfiltered or an unfiltered gl mode is used */
r_lerp_list = ri.Cvar_Get("r_lerp_list", "", CVAR_ARCHIVE);
/* don't bilerp any 2D elements */
@ -1405,7 +1405,8 @@ RI_Init(void)
R_Printf(PRINT_ALL, "Refresh: " REF_VERSION "\n");
R_Printf(PRINT_ALL, "Client: " YQ2VERSION "\n\n");
GetPCXPalette (&colormap, d_8to24table);
GetPCXPalette(&colormap, d_8to24table);
GetPCXPalette24to8((byte *)d_8to24table, &gl_state.d_16to8table);
free(colormap);
R_Register();

View file

@ -40,7 +40,7 @@ GL3_Draw_InitLocal(void)
draw_chars = R_FindPic("conchars", (findimage_t)GL3_FindImage);
if (!draw_chars)
{
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/conchars.pcx",
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/conchars",
__func__);
}

View file

@ -99,9 +99,9 @@ GL3_TextureMode(char *string)
if (unfiltered2D && glt->type == it_pic)
{
// exception to that exception: stuff on the r_lerp_list
nolerp = (lerplist== NULL) || (strstr(lerplist, glt->name) == NULL);
nolerp = (lerplist == NULL) || Utils_FilenameFiltered(glt->name, lerplist, ' ');
}
else if(nolerplist != NULL && strstr(nolerplist, glt->name) != NULL)
else if (nolerplist != NULL && Utils_FilenameFiltered(glt->name, nolerplist, ' '))
{
nolerp = true;
}

View file

@ -236,7 +236,7 @@ GL3_Register(void)
r_validation = ri.Cvar_Get("r_validation", "0", CVAR_ARCHIVE);
/* don't bilerp characters and crosshairs */
gl_nolerp_list = ri.Cvar_Get("r_nolerp_list", "pics/conchars.pcx pics/ch1.pcx pics/ch2.pcx pics/ch3.pcx", CVAR_ARCHIVE);
gl_nolerp_list = ri.Cvar_Get("r_nolerp_list", DEFAULT_NOLERP_LIST, CVAR_ARCHIVE);
/* textures that should always be filtered, even if r_2D_unfiltered or an unfiltered gl mode is used */
r_lerp_list = ri.Cvar_Get("r_lerp_list", "", CVAR_ARCHIVE);
/* don't bilerp any 2D elements */
@ -515,7 +515,7 @@ GL3_Init(void)
return false;
}
GetPCXPalette (&colormap, d_8to24table);
GetPCXPalette(&colormap, d_8to24table);
free(colormap);
GL3_Register();

View file

@ -74,7 +74,7 @@ typedef enum
} modtype_t;
#define MAX_LBM_HEIGHT 480
#define DEFAULT_NOLERP_LIST "pics/conchars.* pics/ch1.* pics/ch2. pics/ch3.*"
extern void R_Printf(int level, const char* msg, ...) PRINTF_ATTR(2, 3);
/* Shared images load */
@ -85,6 +85,7 @@ extern struct image_s* LoadM8(const char *origname, imagetype_t type, loadimage_
extern struct image_s* LoadM32(const char *origname, imagetype_t type, loadimage_t load_image);
extern void FixFileExt(const char *origname, const char *ext, char *filename, size_t size);
extern void GetPCXPalette(byte **colormap, unsigned *d_8to24table);
extern void GetPCXPalette24to8(byte *d_8to24table, byte** d_16to8table);
extern void LoadPCX(const char *origname, byte **pic, byte **palette, int *width, int *height);
extern void GetPCXInfo(const char *origname, int *width, int *height);
extern void GetWalInfo(const char *name, int *width, int *height);

View file

@ -51,7 +51,7 @@ Draw_InitLocal (void)
draw_chars = R_FindPic ("conchars", (findimage_t)R_FindImage);
if (!draw_chars)
{
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/conchars.pcx", __func__);
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/conchars", __func__);
}
}

View file

@ -687,30 +687,12 @@ R_InitImages
void
R_InitImages (void)
{
unsigned char * table16to8;
registration_sequence = 1;
image_max = 0;
d_16to8table = NULL;
ri.FS_LoadFile("pics/16to8.dat", (void **)&table16to8);
if ( !table16to8 )
{
ri.Sys_Error(ERR_FATAL, "%s: Couldn't load pics/16to8.dat", __func__);
// code never returns after ERR_FATAL
return;
}
d_16to8table = malloc(0x10000);
if ( !d_16to8table )
{
ri.Sys_Error(ERR_FATAL, "%s: Couldn't allocate memory for d_16to8table", __func__);
// code never returns after ERR_FATAL
return;
}
memcpy(d_16to8table, table16to8, 0x10000);
ri.FS_FreeFile((void *)table16to8);
GetPCXPalette(&vid_colormap, (unsigned *)d_8to24table);
GetPCXPalette24to8(d_8to24table, &d_16to8table);
vid_alphamap = vid_colormap + 64*256;
R_InitTextures ();
}

View file

@ -450,6 +450,29 @@ R_BuildLightMap (drawsurf_t* drawsurf)
}
}
}
else
{
int maps;
for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
maps++)
{
unsigned scale;
light_t *curr_light, *max_light;
curr_light = blocklights;
max_light = blocklights + size;
scale = drawsurf->lightadj[maps]; // 8.8 fraction
do
{
*curr_light += 255 * scale;
curr_light++;
}
while(curr_light < max_light);
}
}
// add all the dynamic lights
if (surf->dlightframe == r_framecount)

View file

@ -471,9 +471,6 @@ RE_Init(void)
r_aliasuvscale = 1.0;
GetPCXPalette (&vid_colormap, (unsigned *)d_8to24table);
vid_alphamap = vid_colormap + 64*256;
/* set our "safe" mode */
sw_state.prev_mode = 4;

View file

@ -276,7 +276,7 @@ void SDL_Update(void);
* playback
*/
void SDL_RawSamples(int samples, int rate, int width,
int channels, byte *data, float volume);
int channels, const byte *data, float volume);
/*
* Spartializes a sample
@ -348,7 +348,7 @@ void AL_Update(void);
* Plays raw samples
*/
void AL_RawSamples(int samples, int rate, int width,
int channels, byte *data, float volume);
int channels, const byte *data, float volume);
/*
* Unqueues any raw samples

View file

@ -42,7 +42,7 @@ void S_StartSound(vec3_t origin, int entnum, int entchannel,
void S_StartLocalSound(char *sound);
void S_RawSamples(int samples, int rate, int width, int channels,
byte *data, float volume);
const byte *data, float volume);
void S_StopAllSounds(void);
void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up);
void S_Activate(qboolean active);

View file

@ -954,7 +954,7 @@ AL_IssuePlaysounds(void)
*/
void
AL_RawSamples(int samples, int rate, int width, int channels,
byte *data, float volume)
const byte *data, float volume)
{
ALuint buffer;
ALuint format = 0;

View file

@ -1000,7 +1000,7 @@ SDL_Cache(sfx_t *sfx, wavinfo_t *info, byte *data, short volume,
* and cinematic playback.
*/
void
SDL_RawSamples(int samples, int rate, int width, int channels, byte *data, float volume)
SDL_RawSamples(int samples, int rate, int width, int channels, const byte *data, float volume)
{
float scale;
int dst;

View file

@ -1379,7 +1379,7 @@ S_BuildSoundList(int *sounds)
*/
void
S_RawSamples(int samples, int rate, int width,
int channels, byte *data, float volume)
int channels, const byte *data, float volume)
{
if (sound_started == SS_NOT)
{

View file

@ -372,6 +372,9 @@ float frandk(void);
float crandk(void);
void randk_seed(void);
/* Addition code utilities */
qboolean Utils_FilenameFiltered(const char *name, const char *filter, char sepator);
/*
* ==============================================================
*

137
src/common/shared/utils.c Normal file
View file

@ -0,0 +1,137 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* 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 the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Additional functions shared between client and renders
*
* =======================================================================
*/
#include "../header/shared.h"
/*
* name: file name
* filter: file name line rule with '*'
* return false for empty filter
*/
static qboolean
Utils_FilenameFiltered_Line(const char *name, const char *filter)
{
const char *current_filter = filter;
// skip empty filter
if (!*current_filter)
{
return false;
}
while (*current_filter)
{
char part_filter[MAX_QPATH];
const char *name_part;
const char *str_end;
str_end = strchr(current_filter, '*');
if (!str_end)
{
if (!strstr(name, current_filter))
{
// no such part in string
return false;
}
// have such part
break;
}
// copy filter line
if ((str_end - current_filter) >= MAX_QPATH)
{
return false;
}
memcpy(part_filter, current_filter, str_end - current_filter);
part_filter[str_end - current_filter] = 0;
// place part in name
name_part = strstr(name, part_filter);
if (!name_part)
{
// no such part in string
return false;
}
// have such part
name = name_part + strlen(part_filter);
// move to next filter
current_filter = str_end + 1;
}
return true;
}
/*
* name: file name
* filter: file names separated by sepator, and '!' for skip file
*/
qboolean
Utils_FilenameFiltered(const char *name, const char *filter, char sepator)
{
const char *current_filter = filter;
while (*current_filter)
{
char line_filter[MAX_QPATH];
const char *str_end;
str_end = strchr(current_filter, sepator);
// its end of filter
if (!str_end)
{
// check rules inside line
if (Utils_FilenameFiltered_Line(name, current_filter))
{
return true;
}
return false;
}
// copy filter line
if ((str_end - current_filter) >= MAX_QPATH)
{
return false;
}
memcpy(line_filter, current_filter, str_end - current_filter);
line_filter[str_end - current_filter] = 0;
// check rules inside line
if (*line_filter == '!')
{
// has invert rule
if (Utils_FilenameFiltered_Line(name, line_filter + 1))
{
return false;
}
}
else
{
if (Utils_FilenameFiltered_Line(name, line_filter))
{
return true;
}
}
// move to next filter
current_filter = str_end + 1;
}
return false;
}