Add m8 textures support(heretic2 mods)

This commit is contained in:
Denis Pauk 2020-12-17 21:59:04 +02:00
parent f975a94c74
commit a4181a0bdb
16 changed files with 505 additions and 6 deletions

View File

@ -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;
}

View File

@ -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; i<width * height; i++)
{
unsigned char value = *((byte *)mt + ofs + i);
image_buffer[i * 4 + 0] = mt->palette[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
{

View File

@ -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);

View File

@ -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;

View File

@ -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; i<width * height; i++)
{
unsigned char value = *((byte *)mt + ofs + i);
image_buffer[i * 4 + 0] = mt->palette[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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -299,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)
{
@ -317,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)
@ -415,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;

View File

@ -1722,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);
}
}
}

View File

@ -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

View File

@ -1055,6 +1055,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; i<width * height; i++)
{
unsigned char value = *((byte *)mt + ofs + i);
image_buffer[i * 4 + 0] = mt->palette[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 +1142,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 +1216,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))

View File

@ -434,6 +434,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);

View File

@ -687,6 +687,11 @@ void RE_SetSky (char *name, float rotate, vec3_t axis)
Com_sprintf(pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]);
sky_images[i] = Vk_FindImage(pathname, it_sky);
if (!sky_images[i]) {
Com_sprintf(pathname, sizeof(pathname), "pics/Skies/%s%s.m8", skyname, suf[i]);
sky_images[i] = Vk_FindImage(pathname, it_sky);
}
if (!sky_images[i])
sky_images[i] = r_notexture;

View File

@ -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" */