diff --git a/src/client/refresh/files/wal.c b/src/client/refresh/files/wal.c index 343b45ff..172d1cbf 100644 --- a/src/client/refresh/files/wal.c +++ b/src/client/refresh/files/wal.c @@ -57,3 +57,30 @@ GetWalInfo(char *name, int *width, int *height) return; } +void +GetM8Info(char *name, int *width, int *height) +{ + m8tex_t *mt; + int size; + + size = ri.FS_LoadFile(name, (void **)&mt); + + if (!mt) + { + return; + } + + + if (size < sizeof(m8tex_t) || LittleLong (mt->version) != M8_VERSION) + { + ri.FS_FreeFile((void *)mt); + return; + } + + *width = LittleLong(mt->width[0]); + *height = LittleLong(mt->height[0]); + + ri.FS_FreeFile((void *)mt); + + return; +} diff --git a/src/client/refresh/gl1/gl1_image.c b/src/client/refresh/gl1/gl1_image.c index 835dacb1..de1f7f90 100644 --- a/src/client/refresh/gl1/gl1_image.c +++ b/src/client/refresh/gl1/gl1_image.c @@ -1024,6 +1024,75 @@ LoadWal(char *origname, imagetype_t type) return image; } +static image_t * +LoadM8(char *origname, imagetype_t type) +{ + m8tex_t *mt; + int width, height, ofs, size; + image_t *image; + char name[256]; + unsigned char *image_buffer = NULL; + + Q_strlcpy(name, origname, sizeof(name)); + + /* Add the extension */ + if (strcmp(COM_FileExtension(name), "m8")) + { + Q_strlcat(name, ".m8", sizeof(name)); + } + + size = ri.FS_LoadFile(name, (void **)&mt); + + if (!mt) + { + R_Printf(PRINT_ALL, "%s: can't load %s\n", __func__, name); + return r_notexture; + } + + if (size < sizeof(m8tex_t)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small header\n", __func__, name); + ri.FS_FreeFile((void *)mt); + return r_notexture; + } + + if (LittleLong (mt->version) != M8_VERSION) + { + R_Printf(PRINT_ALL, "%s: can't load %s, wrong magic value.\n", __func__, name); + ri.FS_FreeFile ((void *)mt); + return r_notexture; + } + + width = LittleLong(mt->width[0]); + height = LittleLong(mt->height[0]); + ofs = LittleLong(mt->offsets[0]); + + if ((ofs <= 0) || (width <= 0) || (height <= 0) || + (((size - ofs) / height) < width)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small body\n", __func__, name); + ri.FS_FreeFile((void *)mt); + return r_notexture; + } + + image_buffer = malloc (width * height * 4); + for(int i=0; ipalette[value].r; + image_buffer[i * 4 + 1] = mt->palette[value].g; + image_buffer[i * 4 + 2] = mt->palette[value].b; + image_buffer[i * 4 + 3] = value == 255 ? 0 : 255; + } + + image = R_LoadPic(name, image_buffer, width, 0, height, 0, type, 32); + free(image_buffer); + + ri.FS_FreeFile((void *)mt); + + return image; +} + /* * Finds or loads the given image */ @@ -1128,12 +1197,20 @@ R_FindImage(char *name, imagetype_t type) image = R_LoadPic(name, pic, width, 0, height, 0, type, 8); } } - else if (strcmp(ext, "wal") == 0) + else if (strcmp(ext, "wal") == 0 || strcmp(ext, "m8") == 0) { if (gl_retexturing->value) { /* Get size of the original texture */ - GetWalInfo(name, &realwidth, &realheight); + if (strcmp(ext, "m8") == 0) + { + GetM8Info(name, &realwidth, &realheight); + } + else + { + GetWalInfo(name, &realwidth, &realheight); + } + if(realwidth == 0) { /* No texture found */ @@ -1149,6 +1226,10 @@ R_FindImage(char *name, imagetype_t type) image = R_LoadPic(name, pic, width, realwidth, height, realheight, type, 32); } + else if (strcmp(ext, "m8") == 0) + { + image = LoadM8(namewe, type); + } else { /* WAL if no TGA/PNG/JPEG available (exists always) */ @@ -1161,6 +1242,16 @@ R_FindImage(char *name, imagetype_t type) return NULL; } } + else if (strcmp(ext, "m8") == 0) + { + image = LoadM8(name, type); + + if (!image) + { + /* No texture found */ + return NULL; + } + } else /* gl_retexture is not set */ { image = LoadWal(name, type); @@ -1183,6 +1274,12 @@ R_FindImage(char *name, imagetype_t type) strcat(tmp_name, ".wal"); GetWalInfo(tmp_name, &realwidth, &realheight); + if (realwidth == 0 || realheight == 0) { + strcpy(tmp_name, namewe); + strcat(tmp_name, ".m8"); + GetM8Info(tmp_name, &realwidth, &realheight); + } + if (realwidth == 0 || realheight == 0) { /* It's a sky or model skin. */ strcpy(tmp_name, namewe); @@ -1199,6 +1296,10 @@ R_FindImage(char *name, imagetype_t type) { image = R_LoadPic(name, pic, width, realwidth, height, realheight, type, 32); } + else + { + return NULL; + } } else { diff --git a/src/client/refresh/gl1/gl1_misc.c b/src/client/refresh/gl1/gl1_misc.c index 204066cd..05690378 100644 --- a/src/client/refresh/gl1/gl1_misc.c +++ b/src/client/refresh/gl1/gl1_misc.c @@ -71,15 +71,6 @@ static byte notex[4][4] = { {0, 1, 1, 1} }; -typedef struct _TargaHeader -{ - unsigned char id_length, colormap_type, image_type; - unsigned short colormap_index, colormap_length; - unsigned char colormap_size; - unsigned short x_origin, y_origin, width, height; - unsigned char pixel_size, attributes; -} TargaHeader; - void R_InitParticleTexture(void) { diff --git a/src/client/refresh/gl1/gl1_model.c b/src/client/refresh/gl1/gl1_model.c index f85525be..d526e226 100644 --- a/src/client/refresh/gl1/gl1_model.c +++ b/src/client/refresh/gl1/gl1_model.c @@ -414,6 +414,12 @@ Mod_LoadTexinfo(lump_t *l) out->image = R_FindImage(name, it_wall); + if (!out->image || out->image == r_notexture) + { + Com_sprintf(name, sizeof(name), "textures/%s.m8", in->texture); + out->image = R_FindImage(name, it_wall); + } + if (!out->image) { R_Printf(PRINT_ALL, "Couldn't load %s\n", name); diff --git a/src/client/refresh/gl1/gl1_sp2.c b/src/client/refresh/gl1/gl1_sp2.c index c7e8b57b..2d9e529a 100644 --- a/src/client/refresh/gl1/gl1_sp2.c +++ b/src/client/refresh/gl1/gl1_sp2.c @@ -26,10 +26,8 @@ #include "header/local.h" -extern int modfilelen; - void -LoadSP2(model_t *mod, void *buffer) +LoadSP2(model_t *mod, void *buffer, int modfilelen) { dsprite_t *sprin, *sprout; int i; diff --git a/src/client/refresh/gl1/gl1_warp.c b/src/client/refresh/gl1/gl1_warp.c index 9d9e5676..1253d673 100644 --- a/src/client/refresh/gl1/gl1_warp.c +++ b/src/client/refresh/gl1/gl1_warp.c @@ -748,6 +748,13 @@ RI_SetSky(char *name, float rotate, vec3_t axis) sky_images[i] = R_FindImage(pathname, it_sky); + if (!sky_images[i] || sky_images[i] == r_notexture) + { + Com_sprintf(pathname, sizeof(pathname), "pics/Skies/%s%s.m8", + skyname, suf[i]); + sky_images[i] = R_FindImage(pathname, it_sky); + } + if (!sky_images[i]) { sky_images[i] = r_notexture; diff --git a/src/client/refresh/gl3/gl3_image.c b/src/client/refresh/gl3/gl3_image.c index 1fc00e8c..6c3ce937 100644 --- a/src/client/refresh/gl3/gl3_image.c +++ b/src/client/refresh/gl3/gl3_image.c @@ -608,6 +608,75 @@ LoadWal(char *origname, imagetype_t type) return image; } +static gl3image_t * +LoadM8(char *origname, imagetype_t type) +{ + m8tex_t *mt; + int width, height, ofs, size; + gl3image_t *image; + char name[256]; + unsigned char *image_buffer = NULL; + + Q_strlcpy(name, origname, sizeof(name)); + + /* Add the extension */ + if (strcmp(COM_FileExtension(name), "m8")) + { + Q_strlcat(name, ".m8", sizeof(name)); + } + + size = ri.FS_LoadFile(name, (void **)&mt); + + if (!mt) + { + R_Printf(PRINT_ALL, "%s: can't load %s\n", __func__, name); + return gl3_notexture; + } + + if (size < sizeof(m8tex_t)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small header\n", __func__, name); + ri.FS_FreeFile((void *)mt); + return gl3_notexture; + } + + if (LittleLong (mt->version) != M8_VERSION) + { + R_Printf(PRINT_ALL, "LoadWal: can't load %s, wrong magic value.\n", name); + ri.FS_FreeFile ((void *)mt); + return gl3_notexture; + } + + width = LittleLong(mt->width[0]); + height = LittleLong(mt->height[0]); + ofs = LittleLong(mt->offsets[0]); + + if ((ofs <= 0) || (width <= 0) || (height <= 0) || + (((size - ofs) / height) < width)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small body\n", __func__, name); + ri.FS_FreeFile((void *)mt); + return gl3_notexture; + } + + image_buffer = malloc (width * height * 4); + for(int i=0; ipalette[value].r; + image_buffer[i * 4 + 1] = mt->palette[value].g; + image_buffer[i * 4 + 2] = mt->palette[value].b; + image_buffer[i * 4 + 3] = value == 255 ? 0 : 255; + } + + image = GL3_LoadPic(name, image_buffer, width, 0, height, 0, type, 32); + free(image_buffer); + + ri.FS_FreeFile((void *)mt); + + return image; +} + /* * Finds or loads the given image */ @@ -712,12 +781,20 @@ GL3_FindImage(char *name, imagetype_t type) image = GL3_LoadPic(name, pic, width, 0, height, 0, type, 8); } } - else if (strcmp(ext, "wal") == 0) + else if (strcmp(ext, "wal") == 0 || strcmp(ext, "m8") == 0) { if (gl_retexturing->value) { /* Get size of the original texture */ - GetWalInfo(name, &realwidth, &realheight); + if (strcmp(ext, "m8") == 0) + { + GetM8Info(name, &realwidth, &realheight); + } + else + { + GetWalInfo(name, &realwidth, &realheight); + } + if(realwidth == 0) { /* No texture found */ @@ -732,6 +809,10 @@ GL3_FindImage(char *name, imagetype_t type) /* upload tga or png or jpg */ image = GL3_LoadPic(name, pic, width, realwidth, height, realheight, type, 32); } + else if (strcmp(ext, "m8") == 0) + { + image = LoadM8(namewe, type); + } else { /* WAL if no TGA/PNG/JPEG available (exists always) */ @@ -744,6 +825,16 @@ GL3_FindImage(char *name, imagetype_t type) return NULL; } } + else if (strcmp(ext, "m8") == 0) + { + image = LoadM8(name, type); + + if (!image) + { + /* No texture found */ + return NULL; + } + } else /* gl_retexture is not set */ { image = LoadWal(name, type); @@ -766,6 +857,12 @@ GL3_FindImage(char *name, imagetype_t type) strcat(tmp_name, ".wal"); GetWalInfo(tmp_name, &realwidth, &realheight); + if (realwidth == 0 || realheight == 0) { + strcpy(tmp_name, namewe); + strcat(tmp_name, ".m8"); + GetM8Info(tmp_name, &realwidth, &realheight); + } + if (realwidth == 0 || realheight == 0) { /* It's a sky or model skin. */ strcpy(tmp_name, namewe); @@ -781,6 +878,8 @@ GL3_FindImage(char *name, imagetype_t type) if(LoadSTB(name, ext, &pic, &width, &height)) { image = GL3_LoadPic(name, pic, width, realwidth, height, realheight, type, 32); + } else { + return NULL; } } else diff --git a/src/client/refresh/gl3/gl3_model.c b/src/client/refresh/gl3/gl3_model.c index 6fc03dd8..4b03a452 100644 --- a/src/client/refresh/gl3/gl3_model.c +++ b/src/client/refresh/gl3/gl3_model.c @@ -297,6 +297,12 @@ Mod_LoadTexinfo(lump_t *l) out->image = GL3_FindImage(name, it_wall); + if (!out->image || out->image == gl3_notexture) + { + Com_sprintf(name, sizeof(name), "textures/%s.m8", in->texture); + out->image = GL3_FindImage(name, it_wall); + } + if (!out->image) { R_Printf(PRINT_ALL, "Couldn't load %s\n", name); diff --git a/src/client/refresh/gl3/gl3_warp.c b/src/client/refresh/gl3/gl3_warp.c index 5062231b..59673155 100644 --- a/src/client/refresh/gl3/gl3_warp.c +++ b/src/client/refresh/gl3/gl3_warp.c @@ -329,6 +329,13 @@ GL3_SetSky(char *name, float rotate, vec3_t axis) sky_images[i] = GL3_FindImage(pathname, it_sky); + if (sky_images[i] == NULL || sky_images[i] == gl3_notexture) + { + Com_sprintf(pathname, sizeof(pathname), "pics/Skies/%s%s.m8", skyname, suf[i]); + + sky_images[i] = GL3_FindImage(pathname, it_sky); + } + if (sky_images[i] == NULL) { sky_images[i] = gl3_notexture; diff --git a/src/client/refresh/gl3/header/local.h b/src/client/refresh/gl3/header/local.h index 430639c1..13242854 100644 --- a/src/client/refresh/gl3/header/local.h +++ b/src/client/refresh/gl3/header/local.h @@ -187,8 +187,6 @@ typedef struct int prev_mode; - unsigned char *d_16to8table; - // each lightmap consists of 4 sub-lightmaps allowing changing shadows on the same surface // used for switching on/off light and stuff like that. // most surfaces only have one really and the remaining for are filled with dummy data diff --git a/src/client/refresh/ref_shared.h b/src/client/refresh/ref_shared.h index 3eb0c98d..b1b232e5 100644 --- a/src/client/refresh/ref_shared.h +++ b/src/client/refresh/ref_shared.h @@ -71,6 +71,7 @@ extern void scale2x(byte *src, byte *dst, int width, int height); extern void scale3x(byte *src, byte *dst, int width, int height); extern void GetWalInfo(char *name, int *width, int *height); +extern void GetM8Info(char *name, int *width, int *height); extern float Mod_RadiusFromBounds(const vec3_t mins, const vec3_t maxs); extern byte* Mod_DecompressVis(byte *in, int row); diff --git a/src/client/refresh/soft/header/local.h b/src/client/refresh/soft/header/local.h index daa1e014..c3439dbc 100644 --- a/src/client/refresh/soft/header/local.h +++ b/src/client/refresh/soft/header/local.h @@ -161,8 +161,6 @@ extern oldrefdef_t r_refdef; #define ALIAS_Z_CLIP 0x0010 #define ALIAS_XY_CLIP_MASK 0x000F -#define SURFCACHE_SIZE_AT_320X240 1024*768 - #define BMODEL_FULLY_CLIPPED 0x10 // value returned by R_BmodelCheckBBox () // if bbox is trivially rejected @@ -420,10 +418,12 @@ extern cvar_t *sw_stipplealpha; extern cvar_t *sw_surfcacheoverride; extern cvar_t *sw_waterwarp; extern cvar_t *sw_gunzposition; +extern cvar_t *sw_retexturing; extern cvar_t *r_fullbright; extern cvar_t *r_lefthand; extern cvar_t *r_gunfov; +extern cvar_t *r_farsee; extern cvar_t *r_drawworld; extern cvar_t *r_lerpmodels; extern cvar_t *r_lightlevel; diff --git a/src/client/refresh/soft/sw_draw.c b/src/client/refresh/soft/sw_draw.c index 47061881..76d865d6 100644 --- a/src/client/refresh/soft/sw_draw.c +++ b/src/client/refresh/soft/sw_draw.c @@ -89,7 +89,7 @@ RE_Draw_CharScaled(int x, int y, int c, float scale) c &= 255; - if (c == 32 || c == 32+128) + if ((c&127) == 32) return; if (y <= -8) @@ -208,17 +208,49 @@ RE_Draw_StretchPicImplementation (int x, int y, int w, int h, const image_t *pic } else { - int v; + int v, pic_height, pic_width; + byte *pic_pixels, *image_scaled; + + pic_height = pic->height; + pic_width = pic->width; + pic_pixels = pic->pixels[0]; + + if (sw_retexturing->value) + { + if (pic_width < (vid.width / 3) || pic_height < (vid.height / 3)) + { + image_scaled = malloc(pic_width * pic_height * 9); + + scale3x(pic_pixels, image_scaled, pic_width, pic_height); + + pic_width = pic_width * 3; + pic_height = pic_height * 3; + } + else + { + image_scaled = malloc(pic_width * pic_height * 4); + + scale2x(pic_pixels, image_scaled, pic_width, pic_height); + + pic_width = pic_width * 2; + pic_height = pic_height * 2; + } + } + else + { + image_scaled = pic_pixels; + } + // size of screen tile to pic pixel - int picupscale = h / pic->height; + int picupscale = h / pic_height; for (v=0 ; vheight/h; - source = pic->pixels[0] + sv*pic->width; + int sv = (skip + v)*pic_height/h; + source = image_scaled + sv*pic_width; f = 0; - fstep = (pic->width << SHIFT16XYZ) / w; + fstep = (pic_width << SHIFT16XYZ) / w; for (u=0 ; u>16]; @@ -240,6 +272,11 @@ RE_Draw_StretchPicImplementation (int x, int y, int w, int h, const image_t *pic v += (picupscale - 1); } } + + if (sw_retexturing->value) + { + free(image_scaled); + } } } diff --git a/src/client/refresh/soft/sw_image.c b/src/client/refresh/soft/sw_image.c index 8752892b..ea3d1c5c 100644 --- a/src/client/refresh/soft/sw_image.c +++ b/src/client/refresh/soft/sw_image.c @@ -20,8 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "header/local.h" -extern cvar_t *sw_retexturing; - #define MAX_RIMAGES 1024 static image_t r_images[MAX_RIMAGES]; static int numr_images; @@ -111,8 +109,8 @@ R_ImageShrink(const unsigned char* src, unsigned char *dst, int width, int realw int x, y; float xstep, ystep; - xstep = (float)height / realheight; - ystep = (float)width / realwidth; + xstep = (float)width / realwidth; + ystep = (float)height / realheight; for (y=0; ypixels[i-1], image->pixels[i], - image->height / (1 << (i - 1)), image->height / (1 << i), - image->width / (1 << (i - 1)), image->width / (1 << i)); + R_ImageShrink(image->pixels[i], image->pixels[i + 1], + image->width >> i, image->width >> (i + 1), + image->height >> i, image->height >> (i + 1)); } } @@ -155,10 +153,10 @@ R_RestoreImagePointers(image_t *image, int min_mips) { int i; - for (i=min_mips+1; ipixels[i] = image->pixels[i - 1] + ( - image->width * image->height / (1 << ((i - 1) * 2))); + image->pixels[i + 1] = image->pixels[i] + ( + image->width * image->height / (1 << (i * 2))); } } @@ -230,13 +228,13 @@ R_LoadWal (char *name, imagetype_t type) file_size = ri.FS_LoadFile (name, (void **)&mt); if (!mt) { - R_Printf(PRINT_ALL, "R_LoadWal: can't load %s\n", name); + R_Printf(PRINT_ALL, "%s: can't load %s\n", __func__, name); return r_notexture_mip; } if (file_size < sizeof(miptex_t)) { - R_Printf(PRINT_ALL, "R_LoadWal: can't load %s, small header\n", name); + R_Printf(PRINT_ALL, "%s: can't load %s, small header\n", __func__, name); ri.FS_FreeFile((void *)mt); return r_notexture_mip; } @@ -253,7 +251,7 @@ R_LoadWal (char *name, imagetype_t type) if ((ofs <= 0) || (image->width <= 0) || (image->height <= 0) || ((file_size - ofs) / image->width < image->height)) { - R_Printf(PRINT_ALL, "LoadWal: can't load %s, small body\n", name); + R_Printf(PRINT_ALL, "%s: can't load %s, small body\n", __func__, name); ri.FS_FreeFile((void *)mt); return r_notexture_mip; } @@ -301,6 +299,119 @@ R_Convert32To8bit(unsigned char* pic_in, unsigned char* pic_out, size_t size) } } +static void +R_FixPalette(unsigned char* pixels, size_t size, rgb_t* pallette) +{ + unsigned char* convert = malloc(256); + + size_t i; + + if (!d_16to8table) + { + free(convert); + return; + } + + for(i=0; i < 256; i ++) + { + unsigned int r, g, b, c; + + r = ( pallette[i].r >> 3 ) & 31; + g = ( pallette[i].g >> 2 ) & 63; + b = ( pallette[i].b >> 3 ) & 31; + + c = r | ( g << 5 ) | ( b << 11 ); + + convert[i] = d_16to8table[c & 0xFFFF]; + } + + for(i=0; i < size; i++) + { + pixels[i] = convert[pixels[i]]; + } + free(convert); +} + +/* +================ +R_LoadM8 +================ +*/ +static image_t * +R_LoadM8 (char *name, imagetype_t type) +{ + m8tex_t *mt; + int ofs, file_size; + image_t *image; + int size; + + file_size = ri.FS_LoadFile (name, (void **)&mt); + if (!mt) + { + R_Printf(PRINT_ALL, "%s: can't load %s\n", __func__, name); + return r_notexture_mip; + } + + if (file_size < sizeof(m8tex_t)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small header\n", __func__, name); + ri.FS_FreeFile ((void *)mt); + return r_notexture_mip; + } + + if (LittleLong (mt->version) != M8_VERSION) + { + R_Printf(PRINT_ALL, "%s: can't load %s, wrong magic value.\n", __func__, name); + ri.FS_FreeFile ((void *)mt); + return r_notexture_mip; + } + + image = R_FindFreeImage (); + strcpy (image->name, name); + image->width = LittleLong (mt->width[0]); + image->height = LittleLong (mt->height[0]); + image->type = type; + image->registration_sequence = registration_sequence; + ofs = LittleLong (mt->offsets[0]); + size = image->width * image->height * (256+64+16+4)/256; + + if ((ofs <= 0) || (image->width <= 0) || (image->height <= 0) || + ((file_size - ofs) / image->width < image->height)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small body\n", __func__, name); + ri.FS_FreeFile((void *)mt); + return r_notexture_mip; + } + + image->pixels[0] = malloc (size); + image->pixels[1] = image->pixels[0] + image->width*image->height; + image->pixels[2] = image->pixels[1] + image->width*image->height/4; + image->pixels[3] = image->pixels[2] + image->width*image->height/16; + + if (size > (file_size - ofs)) + { + memcpy(image->pixels[0], (byte *)mt + ofs, file_size - ofs); + // looks short, restore everything from first image + R_ImageShrink(image->pixels[0], image->pixels[1], + image->height, image->height/2, + image->width, image->width/2); + R_ImageShrink(image->pixels[1], image->pixels[2], + image->height/2, image->height/4, + image->width/2, image->width/4); + R_ImageShrink(image->pixels[2], image->pixels[3], + image->height/4, image->height/8, + image->width/4, image->width/8); + } + else + { + memcpy ( image->pixels[0], (byte *)mt + ofs, size); + } + + R_FixPalette(image->pixels[0], size, mt->palette); + ri.FS_FreeFile ((void *)mt); + return image; +} + static image_t * R_LoadHiColorImage(char *name, const char* namewe, const char *ext, imagetype_t type) { @@ -319,6 +430,11 @@ R_LoadHiColorImage(char *name, const char* namewe, const char *ext, imagetype_t /* Get size of the original texture */ GetWalInfo(name, &realwidth, &realheight); } + else if (strcmp(ext, "m8") == 0) + { + /* Get size of the original texture */ + GetM8Info(name, &realwidth, &realheight); + } /* try to load a tga, png or jpg (in that order/priority) */ if ( LoadSTB(namewe, "tga", &pic, &width, &height) @@ -417,6 +533,10 @@ R_LoadImage(char *name, const char* namewe, const char *ext, imagetype_t type) { image = R_LoadWal(name, type); } + else if (strcmp(ext, "m8") == 0) + { + image = R_LoadM8 (name, type); + } } return image; diff --git a/src/client/refresh/soft/sw_main.c b/src/client/refresh/soft/sw_main.c index b1fa48d4..1d4c874e 100644 --- a/src/client/refresh/soft/sw_main.c +++ b/src/client/refresh/soft/sw_main.c @@ -135,6 +135,7 @@ float se_time1, se_time2, de_time1, de_time2; cvar_t *r_lefthand; cvar_t *r_gunfov; +cvar_t *r_farsee; static cvar_t *sw_aliasstats; cvar_t *sw_clearcolor; cvar_t *sw_drawflat; @@ -389,6 +390,7 @@ R_RegisterVariables (void) r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE ); r_gunfov = ri.Cvar_Get( "r_gunfov", "80", CVAR_ARCHIVE ); + r_farsee = ri.Cvar_Get("r_farsee", "0", CVAR_LATCH | CVAR_ARCHIVE); r_speeds = ri.Cvar_Get ("r_speeds", "0", 0); r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0); r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0); @@ -543,7 +545,9 @@ R_ReallocateMapBuffers (void) r_outofsurfaces = false; } - if (r_cnumsurfs < NUMSTACKSURFACES) + if ((r_farsee->value > 0) && (r_cnumsurfs < NUMSTACKSURFACES)) + r_cnumsurfs = NUMSTACKSURFACES * 2; + else if (r_cnumsurfs < NUMSTACKSURFACES) r_cnumsurfs = NUMSTACKSURFACES; // edge_t->surf limited size to short @@ -618,7 +622,9 @@ R_ReallocateMapBuffers (void) r_outofedges = false; } - if (r_numallocatededges < NUMSTACKEDGES) + if ((r_farsee->value > 0) && (r_numallocatededges < NUMSTACKEDGES * 2)) + r_numallocatededges = NUMSTACKEDGES * 2; + else if (r_numallocatededges < NUMSTACKEDGES) r_numallocatededges = NUMSTACKEDGES; r_edges = malloc (r_numallocatededges * sizeof(edge_t)); @@ -1077,12 +1083,12 @@ R_DrawBEntitiesOnList (void) { entity_t *currententity = &r_newrefdef.entities[i]; const model_t *currentmodel = currententity->model; + if ( currententity->flags & RF_BEAM ) + continue; if (!currentmodel) continue; if (currentmodel->nummodelsurfaces == 0) continue; // clip brush only - if ( currententity->flags & RF_BEAM ) - continue; if (currentmodel->type != mod_brush) continue; // see if the bounding box lets us trivially reject, also sets @@ -1293,7 +1299,8 @@ RE_RenderFrame (refdef_t *fd) VectorCopy (fd->viewangles, r_refdef.viewangles); // compare current position with old - if (!VectorCompareRound(fd->vieworg, lastvieworg) || + if (vid.width <= 640 || + !VectorCompareRound(fd->vieworg, lastvieworg) || !VectorCompare(fd->viewangles, lastviewangles)) { fastmoving = true; @@ -1426,6 +1433,8 @@ RE_BeginFrame( float camera_separation ) { // pallete without changes palette_changed = false; + // run without speed optimization + fastmoving = false; while (r_mode->modified || vid_fullscreen->modified || r_vsync->modified) { @@ -1519,7 +1528,7 @@ RE_SetMode(void) } /* try setting it back to something safe */ - if ((err = SWimp_SetMode(&vid.width, &vid.height, sw_state.prev_mode, 0)) != rserr_ok) + if (SWimp_SetMode(&vid.width, &vid.height, sw_state.prev_mode, 0) != rserr_ok) { R_Printf(PRINT_ALL, "%s() - could not revert to safe mode\n", __func__); return false; @@ -1713,6 +1722,11 @@ RE_SetSky (char *name, float rotate, vec3_t axis) { Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]); r_skytexinfo[i].image = R_FindImage (pathname, it_sky); + if (!r_skytexinfo[i].image) + { + Com_sprintf (pathname, sizeof(pathname), "pics/Skies/%s%s.m8", skyname, suf[r_skysideimage[i]]); + r_skytexinfo[i].image = R_FindImage (pathname, it_sky); + } } } @@ -2055,10 +2069,13 @@ RE_CopyFrame (Uint32 * pixels, int pitch, int vmin, int vmax) max_pixels = pixels + vmax; buffer_pos = vid_buffer + vmin; - for (pixels_pos = pixels + vmin; pixels_pos < max_pixels; pixels_pos++) + pixels_pos = pixels + vmin; + + while ( pixels_pos < max_pixels) { *pixels_pos = sdl_palette[*buffer_pos]; buffer_pos++; + pixels_pos++; } } else @@ -2128,6 +2145,7 @@ RE_CleanFrame(void) Com_Printf("Can't lock texture: %s\n", SDL_GetError()); return; } + // only cleanup texture without flush texture to screen memset(pixels, 0, pitch * vid.height); SDL_UnlockTexture(texture); @@ -2157,6 +2175,12 @@ RE_FlushFrame(int vmin, int vmax) // code have to copy a whole screen to the texture RE_CopyFrame (pixels, pitch / sizeof(Uint32), 0, vid.height * vid.width); } + + if (((int)sw_texture_filtering->value & 0x01) && !fastmoving) + { + SmoothColorImage(pixels + vmin, vmax - vmin, vid.width >> 7); + } + SDL_UnlockTexture(texture); SDL_RenderCopy(renderer, texture, NULL, NULL); diff --git a/src/client/refresh/soft/sw_model.c b/src/client/refresh/soft/sw_model.c index c887147e..ad4ee8f5 100644 --- a/src/client/refresh/soft/sw_model.c +++ b/src/client/refresh/soft/sw_model.c @@ -514,6 +514,12 @@ Mod_LoadTexinfo (lump_t *l) Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture); out->image = R_FindImage (name, it_wall); + if (!out->image || out->image == r_notexture_mip) + { + Com_sprintf (name, sizeof(name), "textures/%s.m8", in->texture); + out->image = R_FindImage (name, it_wall); + } + if (!out->image) { out->image = r_notexture_mip; // texture not found diff --git a/src/client/refresh/soft/sw_scan.c b/src/client/refresh/soft/sw_scan.c index db1f699f..0c012b42 100644 --- a/src/client/refresh/soft/sw_scan.c +++ b/src/client/refresh/soft/sw_scan.c @@ -719,7 +719,7 @@ D_DrawSpansPow2 (espan_t *pspan, float d_ziorigin, float d_zistepu, float d_zist } // Drawing phrase - if (texture_filtering == 0 || fastmoving) + if ((texture_filtering & 0x02) == 0 || fastmoving) { pdest = D_DrawSpan(pdest, pbase, s, t, sstep, tstep, spancount); diff --git a/src/client/refresh/soft/sw_surf.c b/src/client/refresh/soft/sw_surf.c index ce62bfbf..ca79b63a 100644 --- a/src/client/refresh/soft/sw_surf.c +++ b/src/client/refresh/soft/sw_surf.c @@ -213,19 +213,21 @@ R_InitCaches (void) int size; // calculate size to allocate - if (sw_surfcacheoverride->value) + int pix; + // surface cache size at 320X240 + size = 1024*768; + + pix = vid.width*vid.height; + if (pix > 64000) + size += (pix-64000)*3; + + if (r_farsee->value > 0) + size *= 2; + + if (sw_surfcacheoverride->value > size) { size = sw_surfcacheoverride->value; } - else - { - int pix; - size = SURFCACHE_SIZE_AT_320X240; - - pix = vid.width*vid.height; - if (pix > 64000) - size += (pix-64000)*3; - } // round up to page size size = (size + 8191) & ~8191; diff --git a/src/client/refresh/vk/header/local.h b/src/client/refresh/vk/header/local.h index 5d27c2cd..33a99f35 100644 --- a/src/client/refresh/vk/header/local.h +++ b/src/client/refresh/vk/header/local.h @@ -197,7 +197,7 @@ void R_RenderDlights (void); void R_DrawAlphaSurfaces (void); void RE_InitParticleTexture (void); void Draw_InitLocal (void); -void Vk_SubdivideSurface (msurface_t *fa); +void Vk_SubdivideSurface (msurface_t *fa, model_t *loadmodel); qboolean R_CullBox (vec3_t mins, vec3_t maxs); void R_RotateForEntity (entity_t *e, float *mvMatrix); void R_MarkLeaves (void); @@ -232,9 +232,15 @@ void Vk_TextureMode( char *string ); void Vk_LmapTextureMode( char *string ); void Vk_ImageList_f (void); +void Vk_BuildPolygonFromSurface(msurface_t *fa, model_t *currentmodel); +void Vk_CreateSurfaceLightmap (msurface_t *surf); +void Vk_EndBuildingLightmaps (void); +void Vk_BeginBuildingLightmaps (model_t *m); + void Vk_InitImages (void); void Vk_ShutdownImages (void); void Vk_FreeUnusedImages (void); +qboolean Vk_ImageHasFreeSpace(void); void RE_BeginRegistration (char *model); struct model_s *RE_RegisterModel (char *name); diff --git a/src/client/refresh/vk/header/model.h b/src/client/refresh/vk/header/model.h index d553d08b..b3484f85 100644 --- a/src/client/refresh/vk/header/model.h +++ b/src/client/refresh/vk/header/model.h @@ -44,16 +44,6 @@ typedef struct vec3_t position; } mvertex_t; -typedef struct -{ - vec3_t mins, maxs; - vec3_t origin; // for sounds or lights - float radius; - int headnode; - int visleafs; // not including the solid leaf 0 - int firstface, numfaces; -} mmodel_t; - #define SIDE_FRONT 0 #define SIDE_BACK 1 @@ -200,7 +190,7 @@ typedef struct model_s int lightmap; // only for submodels int numsubmodels; - mmodel_t *submodels; + struct model_s *submodels; int numplanes; cplane_t *planes; @@ -239,6 +229,9 @@ typedef struct model_s int extradatasize; void *extradata; + + // submodules + vec3_t origin; // for sounds or lights } model_t; //============================================================================ diff --git a/src/client/refresh/vk/vk_image.c b/src/client/refresh/vk/vk_image.c index 18d9cacc..92294821 100644 --- a/src/client/refresh/vk/vk_image.c +++ b/src/client/refresh/vk/vk_image.c @@ -21,7 +21,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "header/local.h" image_t vktextures[MAX_VKTEXTURES]; -int numvktextures; +int numvktextures = 0; +static int img_loaded = 0; +static int image_max = 0; + // texture for storing raw image data (cinematics, endscreens, etc.) qvktexture_t vk_rawTexture = QVVKTEXTURE_INIT; @@ -530,17 +533,27 @@ Vk_ImageList_f */ void Vk_ImageList_f (void) { - int i; + int i, used, texels; image_t *image; - int texels; + qboolean freeup; R_Printf(PRINT_ALL, "------------------\n"); texels = 0; + used = 0; for (i = 0, image = vktextures; i < numvktextures; i++, image++) { + char *in_use = ""; + if (image->vk_texture.resource.image == VK_NULL_HANDLE) continue; + + if (image->registration_sequence == registration_sequence) + { + in_use = "*"; + used++; + } + texels += image->upload_width*image->upload_height; switch (image->type) { @@ -561,11 +574,13 @@ void Vk_ImageList_f (void) break; } - R_Printf(PRINT_ALL, " %4i %4i RGB: %s (%dx%d)\n", + R_Printf(PRINT_ALL, " %4i %4i RGB: %s (%dx%d) %s\n", image->upload_width, image->upload_height, image->name, - image->width, image->height); + image->width, image->height, in_use); } - R_Printf(PRINT_ALL, "Total texel count (not counting mipmaps): %i\n", texels); + R_Printf(PRINT_ALL, "Total texel count (not counting mipmaps): %i in %d images\n", texels, img_loaded); + freeup = Vk_ImageHasFreeSpace(); + R_Printf(PRINT_ALL, "Used %d of %d images%s.\n", used, image_max, freeup ? ", has free space" : ""); } typedef struct @@ -978,6 +993,12 @@ Vk_LoadPic(char *name, byte *pic, int width, int realwidth, image->width = realwidth; image->height = realheight; image->type = type; + // update count of loaded images + img_loaded ++; + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Load %s[%d]\n", __func__, image->name, img_loaded); + } if (type == it_skin && bits == 8) FloodFillSkin(pic, width, height); @@ -1055,6 +1076,75 @@ static image_t *Vk_LoadWal (char *name, imagetype_t type) return image; } +static image_t * +Vk_LoadM8(char *origname, imagetype_t type) +{ + m8tex_t *mt; + int width, height, ofs, size; + image_t *image; + char name[256]; + unsigned char *image_buffer = NULL; + + Q_strlcpy(name, origname, sizeof(name)); + + /* Add the extension */ + if (strcmp(COM_FileExtension(name), "m8")) + { + Q_strlcat(name, ".m8", sizeof(name)); + } + + size = ri.FS_LoadFile(name, (void **)&mt); + + if (!mt) + { + R_Printf(PRINT_ALL, "%s: can't load %s\n", __func__, name); + return r_notexture; + } + + if (size < sizeof(m8tex_t)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small header\n", __func__, name); + ri.FS_FreeFile((void *)mt); + return r_notexture; + } + + if (LittleLong (mt->version) != M8_VERSION) + { + R_Printf(PRINT_ALL, "LoadWal: can't load %s, wrong magic value.\n", name); + ri.FS_FreeFile ((void *)mt); + return r_notexture; + } + + width = LittleLong(mt->width[0]); + height = LittleLong(mt->height[0]); + ofs = LittleLong(mt->offsets[0]); + + if ((ofs <= 0) || (width <= 0) || (height <= 0) || + (((size - ofs) / height) < width)) + { + R_Printf(PRINT_ALL, "%s: can't load %s, small body\n", __func__, name); + ri.FS_FreeFile((void *)mt); + return r_notexture; + } + + image_buffer = malloc (width * height * 4); + for(int i=0; ipalette[value].r; + image_buffer[i * 4 + 1] = mt->palette[value].g; + image_buffer[i * 4 + 2] = mt->palette[value].b; + image_buffer[i * 4 + 3] = value == 255 ? 0 : 255; + } + + image = Vk_LoadPic(name, image_buffer, width, width, height, height, type, 32); + free(image_buffer); + + ri.FS_FreeFile((void *)mt); + + return image; +} + static image_t* Vk_LoadHiColorImage(char *name, const char* namewe, const char *ext, imagetype_t type) { @@ -1073,6 +1163,11 @@ Vk_LoadHiColorImage(char *name, const char* namewe, const char *ext, imagetype_t /* Get size of the original texture */ GetWalInfo(name, &realwidth, &realheight); } + else if (strcmp(ext, "m8") == 0) + { + /* Get size of the original texture */ + GetM8Info(name, &realwidth, &realheight); + } /* try to load a tga, png or jpg (in that order/priority) */ if ( LoadSTB(namewe, "tga", &pic, &width, &height) @@ -1142,6 +1237,10 @@ Vk_LoadImage(char *name, const char* namewe, const char *ext, imagetype_t type) { image = Vk_LoadWal (name, type); } + else if (!strcmp(ext, "m8")) + { + image = Vk_LoadM8 (name, type); + } else if (!strcmp(ext, "tga")) { if (!LoadSTB (namewe, "tga", &pic, &width, &height)) @@ -1232,6 +1331,31 @@ struct image_s *RE_RegisterSkin (char *name) return Vk_FindImage (name, it_skin); } +qboolean Vk_ImageHasFreeSpace(void) +{ + int i, used; + image_t *image; + + used = 0; + + for (i = 0, image = vktextures; i < numvktextures; i++, image++) + { + if (!image->name[0]) + continue; + if (image->registration_sequence == registration_sequence) + { + used ++; + } + } + + if (image_max < used) + { + image_max = used; + } + + // should same size of free slots as currently used + return (img_loaded + used) < MAX_VKTEXTURES; +} /* ================ @@ -1246,6 +1370,12 @@ void Vk_FreeUnusedImages (void) int i; image_t *image; + if (Vk_ImageHasFreeSpace()) + { + // should be enough space for load next images + return; + } + // never free r_notexture or particle texture r_notexture->registration_sequence = registration_sequence; r_particletexture->registration_sequence = registration_sequence; @@ -1259,9 +1389,21 @@ void Vk_FreeUnusedImages (void) continue; // free image_t slot if (image->type == it_pic) continue; // don't free pics + + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Unload %s[%d]\n", __func__, image->name, img_loaded); + } + // free it QVk_ReleaseTexture(&image->vk_texture); memset(image, 0, sizeof(*image)); + + img_loaded --; + if (img_loaded < 0) + { + ri.Sys_Error (ERR_DROP, "%s: Broken unload", __func__); + } } // free all unused blocks @@ -1318,6 +1460,9 @@ void Vk_InitImages (void) int i; float overbright; + numvktextures = 0; + img_loaded = 0; + image_max = 0; registration_sequence = 1; // init intensity conversions @@ -1377,8 +1522,19 @@ void Vk_ShutdownImages (void) if (!image->registration_sequence) continue; // free image_t slot + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Unload %s[%d]\n", __func__, image->name, img_loaded); + } + QVk_ReleaseTexture(&image->vk_texture); memset(image, 0, sizeof(*image)); + + img_loaded --; + if (img_loaded < 0) + { + ri.Sys_Error (ERR_DROP, "%s: Broken unload", __func__); + } } QVk_ReleaseTexture(&vk_rawTexture); diff --git a/src/client/refresh/vk/vk_model.c b/src/client/refresh/vk/vk_model.c index ac636070..99e9235f 100644 --- a/src/client/refresh/vk/vk_model.c +++ b/src/client/refresh/vk/vk_model.c @@ -22,23 +22,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "header/local.h" -model_t *loadmodel; -int modfilelen; - -static void Mod_LoadSpriteModel (model_t *mod, void *buffer); -static void Mod_LoadBrushModel (model_t *mod, void *buffer); -static void Mod_LoadAliasModel (model_t *mod, void *buffer); -static void Mod_Free (model_t *mod); - - -byte mod_novis[MAX_MAP_LEAFS/8]; +YQ2_ALIGNAS_TYPE(int) static byte mod_novis[MAX_MAP_LEAFS/8]; #define MAX_MOD_KNOWN 512 -model_t mod_known[MAX_MOD_KNOWN]; -int mod_numknown; - -// the inline * models from the current map are kept seperate -model_t mod_inline[MAX_MOD_KNOWN]; +static model_t *models_known; +static int mod_numknown = 0; +static int mod_loaded = 0; +static int mod_max = 0; +static int models_known_max = 0; int registration_sequence; @@ -52,7 +43,7 @@ mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) mnode_t *node; if (!model || !model->nodes) - ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model"); + ri.Sys_Error (ERR_DROP, "%s: bad model", __func__); node = model->nodes; while (1) @@ -93,26 +84,36 @@ byte *Mod_ClusterPVS (int cluster, model_t *model) //=============================================================================== /* -================ -Mod_Modellist_f -================ +=============== +Mod_Reallocate +=============== */ -void Mod_Modellist_f (void) +void Mod_Reallocate (void) { - int i; - model_t *mod; - int total; - - total = 0; - R_Printf(PRINT_ALL,"Loaded models:\n"); - for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++) + if ((models_known_max >= (mod_max * 4)) && (models_known != NULL)) { - if (!mod->name[0]) - continue; - R_Printf(PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name); - total += mod->extradatasize; + return; } - R_Printf(PRINT_ALL, "Total resident: %i\n", total); + + if (models_known) + { + // Always up if already allocated + models_known_max *= 2; + // free up + Mod_FreeAll(); + free(models_known); + } + + if (models_known_max < (mod_max * 4)) + { + // double is not enough? + models_known_max = ROUNDUP(mod_max * 4, 16); + } + + R_Printf(PRINT_ALL, "Reallocate space for %d models.\n", models_known_max); + + models_known = malloc(models_known_max * sizeof(model_t)); + memset(models_known, 0, models_known_max * sizeof(model_t)); } /* @@ -123,112 +124,57 @@ Mod_Init void Mod_Init (void) { memset (mod_novis, 0xff, sizeof(mod_novis)); + mod_numknown = 0; + mod_loaded = 0; + mod_max = 0; + models_known_max = MAX_MOD_KNOWN; + models_known = NULL; + + Mod_Reallocate (); } +/* +================ +Mod_Free +================ +*/ +static void Mod_Free (model_t *mod) +{ + if (!mod->extradata) + { + // looks as empty model + memset (mod, 0, sizeof(*mod)); + return; + } + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Unload %s[%d]\n", __func__, mod->name, mod_loaded); + } + + Hunk_Free (mod->extradata); + memset (mod, 0, sizeof(*mod)); + mod_loaded --; + if (mod_loaded < 0) + { + ri.Sys_Error (ERR_DROP, "%s: Broken unload", __func__); + } +} /* -================== -Mod_ForName - -Loads in a model for the given name -================== +================ +Mod_FreeAll +================ */ -static model_t *Mod_ForName (char *name, qboolean crash) +void Mod_FreeAll (void) { - model_t *mod; - unsigned *buf; int i; - if (!name[0]) - ri.Sys_Error (ERR_DROP, "%s: NULL name", __func__); - - // - // inline models are grabbed only from worldmodel - // - if (name[0] == '*') + for (i=0 ; i= r_worldmodel->numsubmodels) - ri.Sys_Error (ERR_DROP, "bad inline model number"); - return &mod_inline[i]; + if (models_known[i].extradatasize) + Mod_Free (&models_known[i]); } - - // - // search the currently loaded models - // - for (i=0 , mod=mod_known ; iname[0]) - continue; - if (!strcmp (mod->name, name) ) - return mod; - } - - // - // find a free model slot spot - // - for (i=0 , mod=mod_known ; iname[0]) - break; // free spot - } - if (i == mod_numknown) - { - if (mod_numknown == MAX_MOD_KNOWN) - ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN"); - mod_numknown++; - } - strcpy (mod->name, name); - - // - // load the file - // - modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf); - if (!buf) - { - if (crash) - ri.Sys_Error (ERR_DROP, "Mod_NumForName: %s not found", mod->name); - memset (mod->name, 0, sizeof(mod->name)); - return NULL; - } - - loadmodel = mod; - - // - // fill it in - // - - - // call the apropriate loader - - switch (LittleLong(*(unsigned *)buf)) - { - case IDALIASHEADER: - loadmodel->extradata = Hunk_Begin (0x200000); - Mod_LoadAliasModel (mod, buf); - break; - - case IDSPRITEHEADER: - loadmodel->extradata = Hunk_Begin (0x10000); - Mod_LoadSpriteModel (mod, buf); - break; - - case IDBSPHEADER: - loadmodel->extradata = Hunk_Begin (0x2000000); - Mod_LoadBrushModel (mod, buf); - break; - - default: - ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name); - break; - } - - loadmodel->extradatasize = Hunk_End (); - - ri.FS_FreeFile (buf); - - return mod; } /* @@ -239,15 +185,12 @@ static model_t *Mod_ForName (char *name, qboolean crash) =============================================================================== */ -byte *mod_base; - - /* ================= Mod_LoadLighting ================= */ -static void Mod_LoadLighting (lump_t *l) +static void Mod_LoadLighting (model_t *loadmodel, byte *mod_base, lump_t *l) { if (!l->filelen) { @@ -264,7 +207,7 @@ static void Mod_LoadLighting (lump_t *l) Mod_LoadVisibility ================= */ -static void Mod_LoadVisibility (lump_t *l) +static void Mod_LoadVisibility (model_t *loadmodel, byte *mod_base, lump_t *l) { int i; @@ -290,7 +233,7 @@ static void Mod_LoadVisibility (lump_t *l) Mod_LoadVertexes ================= */ -static void Mod_LoadVertexes (lump_t *l) +static void Mod_LoadVertexes (model_t *loadmodel, byte *mod_base, lump_t *l) { dvertex_t *in; mvertex_t *out; @@ -298,7 +241,11 @@ static void Mod_LoadVertexes (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - ri.Sys_Error (ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); out = Hunk_Alloc ( count*sizeof(*out)); @@ -337,15 +284,19 @@ static float RadiusFromBounds (vec3_t mins, vec3_t maxs) Mod_LoadSubmodels ================= */ -static void Mod_LoadSubmodels (lump_t *l) +static void Mod_LoadSubmodels (model_t *loadmodel, byte *mod_base, lump_t *l) { dmodel_t *in; - mmodel_t *out; + model_t *out; int i, j, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - ri.Sys_Error (ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); out = Hunk_Alloc ( count*sizeof(*out)); @@ -354,16 +305,38 @@ static void Mod_LoadSubmodels (lump_t *l) for ( i=0 ; isubmodels, sizeof(*out)); + } + + Com_sprintf (out->name, sizeof(out->name), "*%d", i); + for (j=0 ; j<3 ; j++) { // spread the mins / maxs by a pixel out->mins[j] = LittleFloat (in->mins[j]) - 1; out->maxs[j] = LittleFloat (in->maxs[j]) + 1; out->origin[j] = LittleFloat (in->origin[j]); } + out->radius = RadiusFromBounds (out->mins, out->maxs); - out->headnode = LittleLong (in->headnode); - out->firstface = LittleLong (in->firstface); - out->numfaces = LittleLong (in->numfaces); + out->firstnode = LittleLong (in->headnode); + out->firstmodelsurface = LittleLong (in->firstface); + out->nummodelsurfaces = LittleLong (in->numfaces); + // visleafs + out->numleafs = 0; + // check limits + if (out->firstnode >= loadmodel->numnodes) + { + ri.Sys_Error(ERR_DROP, "%s: Inline model %i has bad firstnode", + __func__, i); + } } } @@ -372,7 +345,7 @@ static void Mod_LoadSubmodels (lump_t *l) Mod_LoadEdges ================= */ -static void Mod_LoadEdges (lump_t *l) +static void Mod_LoadEdges (model_t *loadmodel, byte *mod_base, lump_t *l) { dedge_t *in; medge_t *out; @@ -380,7 +353,11 @@ static void Mod_LoadEdges (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - ri.Sys_Error (ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); out = Hunk_Alloc ( (count + 1) * sizeof(*out)); @@ -399,7 +376,7 @@ static void Mod_LoadEdges (lump_t *l) Mod_LoadTexinfo ================= */ -static void Mod_LoadTexinfo (lump_t *l) +static void Mod_LoadTexinfo (model_t *loadmodel, byte *mod_base, lump_t *l) { texinfo_t *in; mtexinfo_t *out, *step; @@ -408,7 +385,11 @@ static void Mod_LoadTexinfo (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - ri.Sys_Error (ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); out = Hunk_Alloc ( count*sizeof(*out)); @@ -434,6 +415,12 @@ static void Mod_LoadTexinfo (lump_t *l) Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture); out->image = Vk_FindImage (name, it_wall); + if (!out->image || out->image == r_notexture) + { + Com_sprintf (name, sizeof(name), "textures/%s.m8", in->texture); + out->image = Vk_FindImage (name, it_wall); + } + if (!out->image) { R_Printf(PRINT_ALL, "Couldn't load %s\n", name); @@ -458,11 +445,10 @@ CalcSurfaceExtents Fills in s->texturemins[] and s->extents[] ================ */ -static void CalcSurfaceExtents (msurface_t *s) +static void CalcSurfaceExtents (model_t *loadmodel, msurface_t *s) { float mins[2], maxs[2], val; - int i,j; - mvertex_t *v; + int i; mtexinfo_t *tex; int bmins[2], bmaxs[2]; @@ -473,7 +459,8 @@ static void CalcSurfaceExtents (msurface_t *s) for (i=0 ; inumedges ; i++) { - int e; + int e, j; + mvertex_t *v; e = loadmodel->surfedges[s->firstedge+i]; if (e >= 0) @@ -504,18 +491,87 @@ static void CalcSurfaceExtents (msurface_t *s) } } +static int calcTexinfoAndFacesSize(const lump_t *fl, byte *mod_base, const lump_t *tl) +{ + dface_t* face_in = (void *)(mod_base + fl->fileofs); + texinfo_t* texinfo_in = (void *)(mod_base + tl->fileofs); -void Vk_BuildPolygonFromSurface(msurface_t *fa, model_t *currentmodel); -void Vk_CreateSurfaceLightmap (msurface_t *surf); -void Vk_EndBuildingLightmaps (void); -void Vk_BeginBuildingLightmaps (model_t *m); + if (fl->filelen % sizeof(*face_in) || tl->filelen % sizeof(*texinfo_in)) + { + // will error out when actually loading it + return 0; + } + + int ret = 0; + + int face_count = fl->filelen / sizeof(*face_in); + int texinfo_count = tl->filelen / sizeof(*texinfo_in); + + { + // out = Hunk_Alloc(count * sizeof(*out)); + int baseSize = face_count * sizeof(msurface_t); + baseSize = (baseSize + 31) & ~31; + ret += baseSize; + + int ti_size = texinfo_count * sizeof(mtexinfo_t); + ti_size = (ti_size + 31) & ~31; + ret += ti_size; + } + + int numWarpFaces = 0; + + for (int surfnum = 0; surfnum < face_count; surfnum++, face_in++) + { + int numverts = LittleShort(face_in->numedges); + int ti = LittleShort(face_in->texinfo); + if ((ti < 0) || (ti >= texinfo_count)) + { + return 0; // will error out + } + int texFlags = LittleLong(texinfo_in[ti].flags); + + /* set the drawing flags */ + if (texFlags & SURF_WARP) + { + if (numverts > 60) + return 0; // will error out in R_SubdividePolygon() + + // Vk_SubdivideSurface(out, loadmodel); /* cut up polygon for warps */ + // for each (pot. recursive) call to R_SubdividePolygon(): + // sizeof(glpoly_t) + ((numverts - 4) + 2) * VERTEXSIZE*sizeof(float) + + // this is tricky, how much is allocated depends on the size of the surface + // which we don't know (we'd need the vertices etc to know, but we can't load + // those without allocating...) + // so we just count warped faces and use a generous estimate below + + ++numWarpFaces; + } + else + { + // Vk_BuildPolygonFromSurface(out); + // => poly = Hunk_Alloc(sizeof(vkpoly_t) + (numverts - 4) * VERTEXSIZE*sizeof(float)); + int polySize = sizeof(vkpoly_t) + (numverts - 4) * VERTEXSIZE*sizeof(float); + polySize = (polySize + 31) & ~31; + ret += polySize; + } + } + + // yeah, this is a bit hacky, but it looks like for each warped face + // 256-55000 bytes are allocated (usually on the lower end), + // so just assume 48k per face to be safe + ret += numWarpFaces * 49152; + ret += 1000000; // and 1MB extra just in case + + return ret; +} /* ================= Mod_LoadFaces ================= */ -static void Mod_LoadFaces (lump_t *l) +static void Mod_LoadFaces (model_t *loadmodel, byte *mod_base, lump_t *l) { dface_t *in; msurface_t *out; @@ -523,7 +579,11 @@ static void Mod_LoadFaces (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); out = Hunk_Alloc(count * sizeof(*out)); @@ -540,6 +600,11 @@ static void Mod_LoadFaces (lump_t *l) out->firstedge = LittleLong(in->firstedge); out->numedges = LittleShort(in->numedges); + if (out->numedges < 3) + { + ri.Sys_Error(ERR_DROP, "%s: Surface with %d edges", + __func__, out->numedges); + } out->flags = 0; out->polys = NULL; @@ -552,10 +617,12 @@ static void Mod_LoadFaces (lump_t *l) ti = LittleShort(in->texinfo); if (ti < 0 || ti >= loadmodel->numtexinfo) + { ri.Sys_Error(ERR_DROP, "%s: bad texinfo number", __func__); + } out->texinfo = loadmodel->texinfo + ti; - CalcSurfaceExtents(out); + CalcSurfaceExtents(loadmodel, out); // lighting info @@ -577,7 +644,7 @@ static void Mod_LoadFaces (lump_t *l) out->extents[i] = 16384; out->texturemins[i] = -8192; } - Vk_SubdivideSurface(out); // cut up polygon for warps + Vk_SubdivideSurface(out, loadmodel); // cut up polygon for warps } if (out->texinfo->flags & SURF_SKY) @@ -617,7 +684,7 @@ static void Mod_SetParent (mnode_t *node, mnode_t *parent) Mod_LoadNodes ================= */ -static void Mod_LoadNodes (lump_t *l) +static void Mod_LoadNodes (model_t *loadmodel, byte *mod_base, lump_t *l) { int i, j, count; dnode_t *in; @@ -625,7 +692,11 @@ static void Mod_LoadNodes (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - ri.Sys_Error (ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); out = Hunk_Alloc ( count*sizeof(*out)); @@ -667,7 +738,7 @@ static void Mod_LoadNodes (lump_t *l) Mod_LoadLeafs ================= */ -static void Mod_LoadLeafs (lump_t *l) +static void Mod_LoadLeafs (model_t *loadmodel, byte *mod_base, lump_t *l) { dleaf_t *in; mleaf_t *out; @@ -675,7 +746,11 @@ static void Mod_LoadLeafs (lump_t *l) in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - ri.Sys_Error (ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); out = Hunk_Alloc ( count*sizeof(*out)); @@ -684,7 +759,6 @@ static void Mod_LoadLeafs (lump_t *l) for ( i=0 ; iminmaxs[3+j] = LittleShort (in->maxs[j]); } - p = LittleLong(in->contents); - out->contents = p; - + out->contents = LittleLong(in->contents); out->cluster = LittleShort(in->cluster); out->area = LittleShort(in->area); @@ -706,7 +778,8 @@ static void Mod_LoadLeafs (lump_t *l) out->firstmarksurface = loadmodel->marksurfaces + firstleafface; if ((firstleafface + out->nummarksurfaces) > loadmodel->nummarksurfaces) { - ri.Sys_Error (ERR_DROP, "%s: wrong marksurfaces position in %s", __func__, loadmodel->name); + ri.Sys_Error(ERR_DROP, "%s: wrong marksurfaces position in %s", + __func__, loadmodel->name); } // gl underwater warp @@ -729,15 +802,20 @@ static void Mod_LoadLeafs (lump_t *l) Mod_LoadMarksurfaces ================= */ -static void Mod_LoadMarksurfaces (lump_t *l) +static void Mod_LoadMarksurfaces (model_t *loadmodel, byte *mod_base, lump_t *l) { int i, count; short *in; msurface_t **out; in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) - ri.Sys_Error (ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); out = Hunk_Alloc ( count*sizeof(*out)); @@ -750,7 +828,9 @@ static void Mod_LoadMarksurfaces (lump_t *l) j = LittleShort(in[i]); if (j < 0 || j >= loadmodel->numsurfaces) - ri.Sys_Error (ERR_DROP, "Mod_ParseMarksurfaces: bad surface number"); + { + ri.Sys_Error(ERR_DROP, "%s: bad surface number", __func__); + } out[i] = loadmodel->surfaces + j; } } @@ -760,14 +840,18 @@ static void Mod_LoadMarksurfaces (lump_t *l) Mod_LoadSurfedges ================= */ -static void Mod_LoadSurfedges (lump_t *l) +static void Mod_LoadSurfedges (model_t *loadmodel, byte *mod_base, lump_t *l) { int i, count; int *in, *out; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - ri.Sys_Error (ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); if (count < 1 || count >= MAX_MAP_SURFEDGES) ri.Sys_Error (ERR_DROP, "%s: bad surfedges count in %s: %i", @@ -788,16 +872,21 @@ static void Mod_LoadSurfedges (lump_t *l) Mod_LoadPlanes ================= */ -static void Mod_LoadPlanes (lump_t *l) +static void Mod_LoadPlanes (model_t *loadmodel, byte *mod_base, lump_t *l) { - int i, j; + int i; cplane_t *out; dplane_t *in; int count; in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) - ri.Sys_Error (ERR_DROP, "%s: funny lump size in %s", __func__, loadmodel->name); + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + count = l->filelen / sizeof(*in); out = Hunk_Alloc ( count*2*sizeof(*out)); @@ -806,7 +895,7 @@ static void Mod_LoadPlanes (lump_t *l) for ( i=0 ; i includes its padding), so we'll know how big the hunk needs to be +static int calcLumpHunkSize(const lump_t *l, int inSize, int outSize) +{ + if (l->filelen % inSize) + { + // Mod_Load*() will error out on this because of "funny size" + // don't error out here because in Mod_Load*() it can print the functionname + // (=> tells us what kind of lump) before shutting down the game + return 0; + } + + int count = l->filelen / inSize; + int size = count * outSize; + + // round to cacheline, like Hunk_Alloc() does + size = (size + 31) & ~31; + return size; +} + /* ================= Mod_LoadBrushModel ================= */ -static void Mod_LoadBrushModel (model_t *mod, void *buffer) +static void Mod_LoadBrushModel (model_t *loadmodel, void *buffer, int modfilelen) { int i; dheader_t *header; - mmodel_t *bm; - - loadmodel->type = mod_brush; - if (loadmodel != mod_known) - ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world"); + byte *mod_base; header = (dheader_t *)buffer; - i = LittleLong (header->version); + i = LittleLong(header->version); + if (i != BSPVERSION) - ri.Sys_Error (ERR_DROP, "%s: %s has wrong version number (%i should be %i)", __func__, mod->name, i, BSPVERSION); + { + ri.Sys_Error(ERR_DROP, "%s: %s has wrong version number (%i should be %i)", + __func__, loadmodel->name, i, BSPVERSION); + } // swap all the lumps mod_base = (byte *)header; - for (i=0 ; ilumps[LUMP_VERTEXES], sizeof(dvertex_t), sizeof(mvertex_t)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_EDGES], sizeof(dedge_t), sizeof(medge_t)); + hunkSize += sizeof(medge_t) + 31; // for count+1 in Mod_LoadEdges() + int surfEdgeCount = (header->lumps[LUMP_SURFEDGES].filelen+sizeof(int)-1)/sizeof(int); + if(surfEdgeCount < MAX_MAP_SURFEDGES) // else it errors out later anyway + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_SURFEDGES], sizeof(int), sizeof(int)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LIGHTING], 1, 1); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_PLANES], sizeof(dplane_t), sizeof(cplane_t)*2); + hunkSize += calcTexinfoAndFacesSize(&header->lumps[LUMP_FACES], mod_base, &header->lumps[LUMP_TEXINFO]); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFFACES], sizeof(short), sizeof(msurface_t *)); // yes, out is indeeed a pointer! + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_VISIBILITY], 1, 1); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFS], sizeof(dleaf_t), sizeof(mleaf_t)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_NODES], sizeof(dnode_t), sizeof(mnode_t)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_MODELS], sizeof(dmodel_t), sizeof(model_t)); + + loadmodel->extradata = Hunk_Begin(hunkSize); + loadmodel->type = mod_brush; + loadmodel->numframes = 2; // regular and alternate animation // load into heap - Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]); - Mod_LoadEdges (&header->lumps[LUMP_EDGES]); - Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); - Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); - Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); - Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); - Mod_LoadFaces (&header->lumps[LUMP_FACES]); - Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]); - Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); - Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]); - Mod_LoadNodes (&header->lumps[LUMP_NODES]); - Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); - mod->numframes = 2; // regular and alternate animation - -// -// set up the submodels -// - for (i=0 ; inumsubmodels ; i++) - { - model_t *starmod; - - bm = &mod->submodels[i]; - starmod = &mod_inline[i]; - - *starmod = *loadmodel; - - starmod->firstmodelsurface = bm->firstface; - starmod->nummodelsurfaces = bm->numfaces; - starmod->firstnode = bm->headnode; - if (starmod->firstnode >= loadmodel->numnodes) - ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i); - - VectorCopy (bm->maxs, starmod->maxs); - VectorCopy (bm->mins, starmod->mins); - starmod->radius = bm->radius; - - if (i == 0) - *loadmodel = *starmod; - - starmod->numleafs = bm->visleafs; - } + Mod_LoadVertexes (loadmodel, mod_base, &header->lumps[LUMP_VERTEXES]); + Mod_LoadEdges (loadmodel, mod_base, &header->lumps[LUMP_EDGES]); + Mod_LoadSurfedges (loadmodel, mod_base, &header->lumps[LUMP_SURFEDGES]); + Mod_LoadLighting (loadmodel, mod_base, &header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanes (loadmodel, mod_base, &header->lumps[LUMP_PLANES]); + Mod_LoadTexinfo (loadmodel, mod_base, &header->lumps[LUMP_TEXINFO]); + Mod_LoadFaces (loadmodel, mod_base, &header->lumps[LUMP_FACES]); + Mod_LoadMarksurfaces (loadmodel, mod_base, &header->lumps[LUMP_LEAFFACES]); + Mod_LoadVisibility (loadmodel, mod_base, &header->lumps[LUMP_VISIBILITY]); + Mod_LoadLeafs (loadmodel, mod_base, &header->lumps[LUMP_LEAFS]); + Mod_LoadNodes (loadmodel, mod_base, &header->lumps[LUMP_NODES]); + Mod_LoadSubmodels (loadmodel, mod_base, &header->lumps[LUMP_MODELS]); } /* @@ -906,50 +1010,78 @@ ALIAS MODELS Mod_LoadAliasModel ================= */ -static void Mod_LoadAliasModel (model_t *mod, void *buffer) +static void Mod_LoadAliasModel (model_t *mod, void *buffer, int modfilelen) { - int i, j; - dmdl_t *pinmodel, *pheader; - dstvert_t *pinst, *poutst; - dtriangle_t *pintri, *pouttri; - int *pincmd, *poutcmd; - int version; + int i, j; + dmdl_t *pinmodel, *pheader; + dstvert_t *pinst, *poutst; + dtriangle_t *pintri, *pouttri; + int *pincmd, *poutcmd; + int version; + int ofs_end; pinmodel = (dmdl_t *)buffer; version = LittleLong (pinmodel->version); if (version != ALIAS_VERSION) - ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)", - mod->name, version, ALIAS_VERSION); + { + ri.Sys_Error(ERR_DROP, "%s: %s has wrong version number (%i should be %i)", + __func__, mod->name, version, ALIAS_VERSION); + } - pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end)); + ofs_end = LittleLong(pinmodel->ofs_end); + if (ofs_end < 0 || ofs_end > modfilelen) + { + ri.Sys_Error(ERR_DROP, "%s: model %s file size(%d) too small, should be %d", + __func__, mod->name, modfilelen, ofs_end); + } + + mod->extradata = Hunk_Begin(modfilelen); + pheader = Hunk_Alloc(ofs_end); // byte swap the header fields and sanity check for (i=0 ; iskinheight > MAX_LBM_HEIGHT) - ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name, - MAX_LBM_HEIGHT); + { + ri.Sys_Error(ERR_DROP, "%s: model %s has a skin taller than %d", + __func__, mod->name, MAX_LBM_HEIGHT); + } if (pheader->num_xyz <= 0) - ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name); + { + ri.Sys_Error(ERR_DROP, "%s: model %s has no vertices", + __func__, mod->name); + } if (pheader->num_xyz > MAX_VERTS) - ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name); + { + ri.Sys_Error(ERR_DROP, "%s: model %s has too many vertices", + __func__, mod->name); + } if (pheader->num_st <= 0) - ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name); + { + ri.Sys_Error(ERR_DROP, "%s: model %s has no st vertices", + __func__, mod->name); + } if (pheader->num_tris <= 0) - ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name); + { + ri.Sys_Error(ERR_DROP, "%s: model %s has no triangles", + __func__, mod->name); + } if (pheader->num_frames <= 0) - ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name); + { + ri.Sys_Error(ERR_DROP, "%s: model %s has no frames", + __func__, mod->name); + } -// -// load base s and t vertices (not used in gl version) -// + // + // load base s and t vertices (not used in gl version) + // pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st); poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st); @@ -959,9 +1091,9 @@ static void Mod_LoadAliasModel (model_t *mod, void *buffer) poutst[i].t = LittleShort (pinst[i].t); } -// -// load triangle lists -// + // + // load triangle lists + // pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris); pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris); @@ -974,9 +1106,9 @@ static void Mod_LoadAliasModel (model_t *mod, void *buffer) } } -// -// load the frames -// + // + // load the frames + // for (i=0 ; inum_frames ; i++) { daliasframe_t *pinframe, *poutframe; @@ -1039,25 +1171,30 @@ SPRITE MODELS Mod_LoadSpriteModel ================= */ -static void Mod_LoadSpriteModel (model_t *mod, void *buffer) +static void Mod_LoadSpriteModel (model_t *mod, void *buffer, int modfilelen) { dsprite_t *sprin, *sprout; int i; sprin = (dsprite_t *)buffer; - sprout = Hunk_Alloc (modfilelen); + mod->extradata = Hunk_Begin(modfilelen); + sprout = Hunk_Alloc(modfilelen); sprout->ident = LittleLong (sprin->ident); sprout->version = LittleLong (sprin->version); sprout->numframes = LittleLong (sprin->numframes); if (sprout->version != SPRITE_VERSION) - ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)", - mod->name, sprout->version, SPRITE_VERSION); + { + ri.Sys_Error(ERR_DROP, "%s: %s has wrong version number (%i should be %i)", + __func__, mod->name, sprout->version, SPRITE_VERSION); + } if (sprout->numframes > MAX_MD2SKINS) - ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)", - mod->name, sprout->numframes, MAX_MD2SKINS); + { + ri.Sys_Error(ERR_DROP, "%s: %s has too many frames (%i > %i)", + __func__, mod->name, sprout->numframes, MAX_MD2SKINS); + } // byte swap everything for (i=0 ; inumframes ; i++) @@ -1076,6 +1213,122 @@ static void Mod_LoadSpriteModel (model_t *mod, void *buffer) //============================================================================= +/* +================== +Mod_ForName + +Loads in a model for the given name +================== +*/ +static model_t *Mod_ForName (char *name, model_t *parent_model, qboolean crash) +{ + model_t *mod; + unsigned *buf; + int i, modfilelen; + + if (!name[0]) + { + ri.Sys_Error(ERR_DROP, "%s: NULL name", __func__); + } + + // + // inline models are grabbed only from worldmodel + // + if (name[0] == '*' && parent_model) + { + i = atoi(name+1); + if (i < 1 || i >= parent_model->numsubmodels) + ri.Sys_Error (ERR_DROP, "bad inline model number"); + return &parent_model->submodels[i]; + } + + // + // search the currently loaded models + // + for (i=0 , mod=models_known ; iname[0]) + continue; + if (!strcmp (mod->name, name) ) + return mod; + } + + // + // find a free model slot spot + // + for (i=0 , mod=models_known ; iname[0]) + break; // free spot + } + if (i == mod_numknown) + { + if (mod_numknown == models_known_max) + ri.Sys_Error(ERR_DROP, "%s: mod_numknown == models_known_max", __func__); + mod_numknown++; + } + strcpy (mod->name, name); + + // + // load the file + // + modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf); + if (!buf) + { + if (crash) + { + ri.Sys_Error(ERR_DROP, "%s: %s not found", + __func__, mod->name); + } + + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Can't load %s\n", __func__, mod->name); + } + memset (mod->name, 0, sizeof(mod->name)); + return NULL; + } + + // update count of loaded models + mod_loaded ++; + if (vk_validation->value) + { + R_Printf(PRINT_ALL, "%s: Load %s[%d]\n", __func__, mod->name, mod_loaded); + } + + // + // fill it in + // + + // call the apropriate loader + + switch (LittleLong(*(unsigned *)buf)) + { + case IDALIASHEADER: + Mod_LoadAliasModel(mod, buf, modfilelen); + break; + + case IDSPRITEHEADER: + Mod_LoadSpriteModel(mod, buf, modfilelen); + break; + + case IDBSPHEADER: + Mod_LoadBrushModel(mod, buf, modfilelen); + break; + + default: + ri.Sys_Error(ERR_DROP, "%s: unknown fileid for %s", + __func__, mod->name); + break; + } + + mod->extradatasize = Hunk_End (); + + ri.FS_FreeFile(buf); + + return mod; +} + /* ===================== RE_BeginRegistration @@ -1089,22 +1342,25 @@ RE_BeginRegistration (char *model) char fullname[MAX_QPATH]; cvar_t *flushmap; + Mod_Reallocate(); + registration_sequence++; r_oldviewcluster = -1; // force markleafs Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model); // explicitly free the old map if different - // this guarantees that mod_known[0] is the world map + // this guarantees that models_known[0] is the world map flushmap = ri.Cvar_Get ("flushmap", "0", 0); - if ( strcmp(mod_known[0].name, fullname) || flushmap->value) - Mod_Free (&mod_known[0]); - r_worldmodel = Mod_ForName(fullname, true); + if ( strcmp(models_known[0].name, fullname) || flushmap->value) + Mod_Free (&models_known[0]); + r_worldmodel = Mod_ForName(fullname, NULL, true); + if (r_worldmodel != models_known) + ri.Sys_Error(ERR_DROP, "%s: Loaded a brush model after the world", __func__); r_viewcluster = -1; } - /* ===================== RE_RegisterModel @@ -1114,9 +1370,8 @@ RE_RegisterModel struct model_s *RE_RegisterModel (char *name) { model_t *mod; - dmdl_t *pheader; - mod = Mod_ForName (name, false); + mod = Mod_ForName (name, r_worldmodel, false); if (mod) { int i; @@ -1134,6 +1389,8 @@ struct model_s *RE_RegisterModel (char *name) } else if (mod->type == mod_alias) { + dmdl_t *pheader; + pheader = (dmdl_t *)mod->extradata; for (i=0 ; inum_skins ; i++) mod->skins[i] = Vk_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin); @@ -1150,6 +1407,69 @@ struct model_s *RE_RegisterModel (char *name) return mod; } +static qboolean +Mod_HasFreeSpace(void) +{ + int i, used; + model_t *mod; + + used = 0; + + for (i=0, mod=models_known ; iname[0]) + continue; + if (mod->registration_sequence == registration_sequence) + { + used ++; + } + } + + if (mod_max < used) + { + mod_max = used; + } + + // should same size of free slots as currently used + return (mod_loaded + mod_max) < models_known_max; +} + +/* +================ +Mod_Modellist_f +================ +*/ +void Mod_Modellist_f (void) +{ + int i, total, used; + model_t *mod; + qboolean freeup; + + total = 0; + used = 0; + + R_Printf(PRINT_ALL,"Loaded models:\n"); + for (i=0, mod=models_known ; i < mod_numknown ; i++, mod++) + { + char *in_use = ""; + + if (mod->registration_sequence == registration_sequence) + { + in_use = "*"; + used ++; + } + + if (!mod->name[0]) + continue; + R_Printf(PRINT_ALL, "%8i : %s %s\n", + mod->extradatasize, mod->name, in_use); + total += mod->extradatasize; + } + R_Printf(PRINT_ALL, "Total resident: %i in %d models\n", total, mod_loaded); + // update statistics + freeup = Mod_HasFreeSpace(); + R_Printf(PRINT_ALL, "Used %d of %d models%s.\n", used, mod_max, freeup ? ", has free space" : ""); +} /* ===================== @@ -1162,7 +1482,13 @@ void RE_EndRegistration (void) int i; model_t *mod; - for (i=0, mod=mod_known ; iname[0]) continue; @@ -1174,34 +1500,3 @@ void RE_EndRegistration (void) Vk_FreeUnusedImages (); } - - -//============================================================================= - - -/* -================ -Mod_Free -================ -*/ -static void Mod_Free (model_t *mod) -{ - Hunk_Free (mod->extradata); - memset (mod, 0, sizeof(*mod)); -} - -/* -================ -Mod_FreeAll -================ -*/ -void Mod_FreeAll (void) -{ - int i; - - for (i=0 ; i= '0' || c <= '9')) + dot = 0; + } + else if (c < '0' || c > '9') { - return false; - } - } while (*s); + return false; + } + } while (*s); - return true; + return true; } float @@ -514,7 +516,7 @@ void Cvar_Set_f(void) { char *firstarg; - int c, flags, i; + int c, i; c = Cmd_Argc(); @@ -537,6 +539,8 @@ Cvar_Set_f(void) if (c == 4) { + int flags; + if (!strcmp(Cmd_Argv(3), "u")) { flags = CVAR_USERINFO; diff --git a/src/common/header/files.h b/src/common/header/files.h index 87e1cf30..2d00a190 100644 --- a/src/common/header/files.h +++ b/src/common/header/files.h @@ -174,6 +174,31 @@ typedef struct miptex_s int value; } miptex_t; +/* .M8 texture file format */ + +#define M8_MIP_LEVELS 16 +#define M8_VERSION 0x2 + +typedef struct { + unsigned char r; + unsigned char g; + unsigned char b; +} rgb_t; + +typedef struct m8tex_s +{ + unsigned version; + char name[32]; + unsigned width[M8_MIP_LEVELS]; + unsigned height[M8_MIP_LEVELS]; + unsigned offsets[M8_MIP_LEVELS]; /* 16 mip maps stored */ + char animname[32]; /* next frame in animation chain */ + rgb_t palette[256]; + int flags; + int contents; + int value; +} m8tex_t; + /* .BSP file format */ #define IDBSPHEADER (('P' << 24) + ('S' << 16) + ('B' << 8) + 'I') /* little-endian "IBSP" */ diff --git a/src/common/shared/shared.c b/src/common/shared/shared.c index 2164389f..f7d8639e 100644 --- a/src/common/shared/shared.c +++ b/src/common/shared/shared.c @@ -1356,7 +1356,12 @@ Info_SetValueForKey(char *s, char *key, char *value) int c; int maxsize = MAX_INFO_STRING; - if (strstr(key, "\\") || strstr(value, "\\")) + if (!key) + { + return; + } + + if (strstr(key, "\\") || (value && strstr(value, "\\"))) { Com_Printf("Can't use keys or values with a \\\n"); return; @@ -1368,13 +1373,13 @@ Info_SetValueForKey(char *s, char *key, char *value) return; } - if (strstr(key, "\"") || strstr(value, "\"")) + if (strstr(key, "\"") || (value && strstr(value, "\""))) { Com_Printf("Can't use keys or values with a \"\n"); return; } - if ((strlen(key) > MAX_INFO_KEY - 1) || (strlen(value) > MAX_INFO_KEY - 1)) + if ((strlen(key) > MAX_INFO_KEY - 1) || (value && (strlen(value) > MAX_INFO_KEY - 1))) { Com_Printf("Keys and values must be < 64 characters.\n"); return; diff --git a/src/game/g_turret.c b/src/game/g_turret.c index 620d2e90..54577cc7 100644 --- a/src/game/g_turret.c +++ b/src/game/g_turret.c @@ -27,7 +27,7 @@ #include "header/local.h" void infantry_die(edict_t *self, edict_t *inflictor, edict_t *attacker, - int damage); + int damage, vec3_t point); void infantry_stand(edict_t *self); void monster_use(edict_t *self, edict_t *other, edict_t *activator); qboolean FindTarget(edict_t *self); @@ -410,7 +410,7 @@ SP_turret_base(edict_t *self) */ void turret_driver_die(edict_t *self, edict_t *inflictor, edict_t *attacker, - int damage, vec3_t point /* unused */) + int damage, vec3_t point) { edict_t *ent; @@ -436,7 +436,7 @@ turret_driver_die(edict_t *self, edict_t *inflictor, edict_t *attacker, self->target_ent->owner = NULL; self->target_ent->teammaster->owner = NULL; - infantry_die(self, inflictor, attacker, damage); + infantry_die(self, inflictor, attacker, damage, point); } void diff --git a/src/game/player/client.c b/src/game/player/client.c index 292c6ba6..d8606015 100644 --- a/src/game/player/client.c +++ b/src/game/player/client.c @@ -392,7 +392,7 @@ SP_info_player_coop(edict_t *self) * roll as well as yaw. 'pitch yaw roll' */ void -SP_info_player_intermission(void) +SP_info_player_intermission(edict_t *self) { /* Thus function cannot be removed * since the info_player_intermission diff --git a/src/game/savegame/tables/gamefunc_decs.h b/src/game/savegame/tables/gamefunc_decs.h index 8b3481b0..8cad0879 100644 --- a/src/game/savegame/tables/gamefunc_decs.h +++ b/src/game/savegame/tables/gamefunc_decs.h @@ -194,7 +194,7 @@ extern void ClientObituary ( edict_t * self , edict_t * inflictor , edict_t * at extern qboolean IsNeutral ( edict_t * ent ) ; extern qboolean IsFemale ( edict_t * ent ) ; extern void player_pain ( edict_t * self , edict_t * other , float kick , int damage ) ; -extern void SP_info_player_intermission ( void ) ; +extern void SP_info_player_intermission ( edict_t * ent ) ; extern void SP_info_player_coop ( edict_t * self ) ; extern void SP_info_player_deathmatch ( edict_t * self ) ; extern void SP_info_player_start ( edict_t * self ) ;