2014-03-15 16:59:03 +00:00
|
|
|
// Emacs style mode select -*- C++ -*-
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/// \file
|
|
|
|
/// \brief MD2 Handling
|
|
|
|
/// Inspired from md2.c by Mete Ciragan (mete@swissquake.ch)
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "../doomdef.h"
|
|
|
|
#include "../doomstat.h"
|
|
|
|
|
|
|
|
#ifdef HWRENDER
|
|
|
|
#include "hw_drv.h"
|
|
|
|
#include "hw_light.h"
|
|
|
|
#include "hw_md2.h"
|
2018-05-13 19:34:08 +00:00
|
|
|
#include "../d_main.h"
|
2014-03-15 16:59:03 +00:00
|
|
|
#include "../r_bsp.h"
|
|
|
|
#include "../r_main.h"
|
|
|
|
#include "../m_misc.h"
|
|
|
|
#include "../w_wad.h"
|
|
|
|
#include "../z_zone.h"
|
|
|
|
#include "../r_things.h"
|
2018-12-16 01:57:11 +00:00
|
|
|
// #include "../r_draw.h"
|
|
|
|
// #include "../p_tick.h"
|
|
|
|
#include "hw_model.h"
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
#include "hw_main.h"
|
2015-07-26 19:14:47 +00:00
|
|
|
#include "../v_video.h"
|
2014-03-15 16:59:03 +00:00
|
|
|
#ifdef HAVE_PNG
|
|
|
|
|
|
|
|
#ifndef _MSC_VER
|
|
|
|
#ifndef _LARGEFILE64_SOURCE
|
|
|
|
#define _LARGEFILE64_SOURCE
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef _LFS64_LARGEFILE
|
|
|
|
#define _LFS64_LARGEFILE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef _FILE_OFFSET_BITS
|
|
|
|
#define _FILE_OFFSET_BITS 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "png.h"
|
|
|
|
#ifndef PNG_READ_SUPPORTED
|
|
|
|
#undef HAVE_PNG
|
|
|
|
#endif
|
|
|
|
#if PNG_LIBPNG_VER < 100207
|
|
|
|
//#undef HAVE_PNG
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2018-05-13 20:04:34 +00:00
|
|
|
#ifndef errno
|
|
|
|
#include "errno.h"
|
|
|
|
#endif
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
md2_t md2_models[NUMSPRITES];
|
|
|
|
md2_t md2_playermodels[MAXSKINS];
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* free model
|
|
|
|
*/
|
2018-12-19 00:17:33 +00:00
|
|
|
#if 0
|
2018-12-16 01:57:11 +00:00
|
|
|
static void md2_freeModel (model_t *model)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2018-12-16 01:57:11 +00:00
|
|
|
UnloadModel(model);
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
2018-12-19 00:17:33 +00:00
|
|
|
#endif
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// load model
|
|
|
|
//
|
|
|
|
// Hurdler: the current path is the Legacy.exe path
|
2018-12-16 01:57:11 +00:00
|
|
|
static model_t *md2_readModel(const char *filename)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2018-05-13 19:19:36 +00:00
|
|
|
//Filename checking fixed ~Monster Iestyn and Golden
|
2018-12-16 01:57:11 +00:00
|
|
|
return LoadModel(va("%s"PATHSEP"%s", srb2home, filename), PU_STATIC);
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
2018-12-16 01:57:11 +00:00
|
|
|
static inline void md2_printModelInfo (model_t *model)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
INT32 i;
|
|
|
|
|
|
|
|
CONS_Debug(DBG_RENDER, "magic:\t\t\t%c%c%c%c\n", model->header.magic>>24,
|
|
|
|
(model->header.magic>>16)&0xff,
|
|
|
|
(model->header.magic>>8)&0xff,
|
|
|
|
model->header.magic&0xff);
|
|
|
|
CONS_Debug(DBG_RENDER, "version:\t\t%d\n", model->header.version);
|
|
|
|
CONS_Debug(DBG_RENDER, "skinWidth:\t\t%d\n", model->header.skinWidth);
|
|
|
|
CONS_Debug(DBG_RENDER, "skinHeight:\t\t%d\n", model->header.skinHeight);
|
|
|
|
CONS_Debug(DBG_RENDER, "frameSize:\t\t%d\n", model->header.frameSize);
|
|
|
|
CONS_Debug(DBG_RENDER, "numSkins:\t\t%d\n", model->header.numSkins);
|
|
|
|
CONS_Debug(DBG_RENDER, "numVertices:\t\t%d\n", model->header.numVertices);
|
|
|
|
CONS_Debug(DBG_RENDER, "numTexCoords:\t\t%d\n", model->header.numTexCoords);
|
|
|
|
CONS_Debug(DBG_RENDER, "numTriangles:\t\t%d\n", model->header.numTriangles);
|
|
|
|
CONS_Debug(DBG_RENDER, "numGlCommands:\t\t%d\n", model->header.numGlCommands);
|
|
|
|
CONS_Debug(DBG_RENDER, "numFrames:\t\t%d\n", model->header.numFrames);
|
|
|
|
CONS_Debug(DBG_RENDER, "offsetSkins:\t\t%d\n", model->header.offsetSkins);
|
|
|
|
CONS_Debug(DBG_RENDER, "offsetTexCoords:\t%d\n", model->header.offsetTexCoords);
|
|
|
|
CONS_Debug(DBG_RENDER, "offsetTriangles:\t%d\n", model->header.offsetTriangles);
|
|
|
|
CONS_Debug(DBG_RENDER, "offsetFrames:\t\t%d\n", model->header.offsetFrames);
|
|
|
|
CONS_Debug(DBG_RENDER, "offsetGlCommands:\t%d\n", model->header.offsetGlCommands);
|
|
|
|
CONS_Debug(DBG_RENDER, "offsetEnd:\t\t%d\n", model->header.offsetEnd);
|
|
|
|
|
|
|
|
for (i = 0; i < model->header.numFrames; i++)
|
|
|
|
CONS_Debug(DBG_RENDER, "%s ", model->frames[i].name);
|
|
|
|
CONS_Debug(DBG_RENDER, "\n");
|
|
|
|
#else
|
|
|
|
(void)model;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_PNG
|
|
|
|
static void PNG_error(png_structp PNG, png_const_charp pngtext)
|
|
|
|
{
|
|
|
|
CONS_Debug(DBG_RENDER, "libpng error at %p: %s", PNG, pngtext);
|
|
|
|
//I_Error("libpng error at %p: %s", PNG, pngtext);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PNG_warn(png_structp PNG, png_const_charp pngtext)
|
|
|
|
{
|
|
|
|
CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_t *grpatch)
|
|
|
|
{
|
|
|
|
png_structp png_ptr;
|
|
|
|
png_infop png_info_ptr;
|
|
|
|
png_uint_32 width, height;
|
|
|
|
int bit_depth, color_type;
|
|
|
|
#ifdef PNG_SETJMP_SUPPORTED
|
|
|
|
#ifdef USE_FAR_KEYWORD
|
|
|
|
jmp_buf jmpbuf;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
png_FILE_p png_FILE;
|
2018-05-13 19:19:36 +00:00
|
|
|
//Filename checking fixed ~Monster Iestyn and Golden
|
|
|
|
char *pngfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
FIL_ForceExtension(pngfilename, ".png");
|
|
|
|
png_FILE = fopen(pngfilename, "rb");
|
|
|
|
if (!png_FILE)
|
|
|
|
{
|
|
|
|
//CONS_Debug(DBG_RENDER, "M_SavePNG: Error on opening %s for loading\n", filename);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
|
|
|
|
PNG_error, PNG_warn);
|
|
|
|
if (!png_ptr)
|
|
|
|
{
|
|
|
|
CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n");
|
|
|
|
fclose(png_FILE);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
png_info_ptr = png_create_info_struct(png_ptr);
|
|
|
|
if (!png_info_ptr)
|
|
|
|
{
|
|
|
|
CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n");
|
|
|
|
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
|
|
|
fclose(png_FILE);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_FAR_KEYWORD
|
|
|
|
if (setjmp(jmpbuf))
|
|
|
|
#else
|
|
|
|
if (setjmp(png_jmpbuf(png_ptr)))
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
//CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename);
|
|
|
|
png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
|
|
|
|
fclose(png_FILE);
|
|
|
|
Z_Free(grpatch->mipmap.grInfo.data);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#ifdef USE_FAR_KEYWORD
|
|
|
|
png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
png_init_io(png_ptr, png_FILE);
|
|
|
|
|
|
|
|
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
|
|
|
|
png_set_user_limits(png_ptr, 2048, 2048);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
png_read_info(png_ptr, png_info_ptr);
|
|
|
|
|
|
|
|
png_get_IHDR(png_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (bit_depth == 16)
|
|
|
|
png_set_strip_16(png_ptr);
|
|
|
|
|
|
|
|
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
|
|
|
png_set_gray_to_rgb(png_ptr);
|
|
|
|
else if (color_type == PNG_COLOR_TYPE_PALETTE)
|
|
|
|
png_set_palette_to_rgb(png_ptr);
|
|
|
|
|
|
|
|
if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS))
|
|
|
|
png_set_tRNS_to_alpha(png_ptr);
|
|
|
|
else if (color_type != PNG_COLOR_TYPE_RGB_ALPHA && color_type != PNG_COLOR_TYPE_GRAY_ALPHA)
|
|
|
|
{
|
|
|
|
#if PNG_LIBPNG_VER < 10207
|
|
|
|
png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
|
|
|
|
#else
|
|
|
|
png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
png_read_update_info(png_ptr, png_info_ptr);
|
|
|
|
|
|
|
|
{
|
|
|
|
png_uint_32 i, pitch = png_get_rowbytes(png_ptr, png_info_ptr);
|
|
|
|
png_bytep PNG_image = Z_Malloc(pitch*height, PU_HWRCACHE, &grpatch->mipmap.grInfo.data);
|
|
|
|
png_bytepp row_pointers = png_malloc(png_ptr, height * sizeof (png_bytep));
|
|
|
|
for (i = 0; i < height; i++)
|
|
|
|
row_pointers[i] = PNG_image + i*pitch;
|
|
|
|
png_read_image(png_ptr, row_pointers);
|
|
|
|
png_free(png_ptr, (png_voidp)row_pointers);
|
|
|
|
}
|
|
|
|
|
|
|
|
png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
|
|
|
|
|
|
|
|
fclose(png_FILE);
|
|
|
|
*w = (int)width;
|
|
|
|
*h = (int)height;
|
|
|
|
return GR_RGBA;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
UINT8 manufacturer;
|
|
|
|
UINT8 version;
|
|
|
|
UINT8 encoding;
|
|
|
|
UINT8 bitsPerPixel;
|
|
|
|
INT16 xmin;
|
|
|
|
INT16 ymin;
|
|
|
|
INT16 xmax;
|
|
|
|
INT16 ymax;
|
|
|
|
INT16 hDpi;
|
|
|
|
INT16 vDpi;
|
|
|
|
UINT8 colorMap[48];
|
|
|
|
UINT8 reserved;
|
|
|
|
UINT8 numPlanes;
|
|
|
|
INT16 bytesPerLine;
|
|
|
|
INT16 paletteInfo;
|
|
|
|
INT16 hScreenSize;
|
|
|
|
INT16 vScreenSize;
|
|
|
|
UINT8 filler[54];
|
|
|
|
} PcxHeader;
|
|
|
|
|
|
|
|
static GrTextureFormat_t PCX_Load(const char *filename, int *w, int *h,
|
|
|
|
GLPatch_t *grpatch)
|
|
|
|
{
|
|
|
|
PcxHeader header;
|
|
|
|
#define PALSIZE 768
|
|
|
|
UINT8 palette[PALSIZE];
|
|
|
|
const UINT8 *pal;
|
|
|
|
RGBA_t *image;
|
|
|
|
size_t pw, ph, size, ptr = 0;
|
|
|
|
INT32 ch, rep;
|
|
|
|
FILE *file;
|
2018-05-13 19:19:36 +00:00
|
|
|
//Filename checking fixed ~Monster Iestyn and Golden
|
|
|
|
char *pcxfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
FIL_ForceExtension(pcxfilename, ".pcx");
|
|
|
|
file = fopen(pcxfilename, "rb");
|
|
|
|
if (!file)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (fread(&header, sizeof (PcxHeader), 1, file) != 1)
|
|
|
|
{
|
|
|
|
fclose(file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (header.bitsPerPixel != 8)
|
|
|
|
{
|
|
|
|
fclose(file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fseek(file, -PALSIZE, SEEK_END);
|
|
|
|
|
|
|
|
pw = *w = header.xmax - header.xmin + 1;
|
|
|
|
ph = *h = header.ymax - header.ymin + 1;
|
|
|
|
image = Z_Malloc(pw*ph*4, PU_HWRCACHE, &grpatch->mipmap.grInfo.data);
|
|
|
|
|
|
|
|
if (fread(palette, sizeof (UINT8), PALSIZE, file) != PALSIZE)
|
|
|
|
{
|
|
|
|
Z_Free(image);
|
|
|
|
fclose(file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
fseek(file, sizeof (PcxHeader), SEEK_SET);
|
|
|
|
|
|
|
|
size = pw * ph;
|
|
|
|
while (ptr < size)
|
|
|
|
{
|
|
|
|
ch = fgetc(file); //Hurdler: beurk
|
|
|
|
if (ch >= 192)
|
|
|
|
{
|
|
|
|
rep = ch - 192;
|
|
|
|
ch = fgetc(file);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rep = 1;
|
|
|
|
}
|
|
|
|
while (rep--)
|
|
|
|
{
|
|
|
|
pal = palette + ch*3;
|
|
|
|
image[ptr].s.red = *pal++;
|
|
|
|
image[ptr].s.green = *pal++;
|
|
|
|
image[ptr].s.blue = *pal++;
|
|
|
|
image[ptr].s.alpha = 0xFF;
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(file);
|
|
|
|
return GR_RGBA;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------+
|
|
|
|
// md2_loadTexture : Download a pcx or png texture for MD2 models
|
|
|
|
// -----------------+
|
|
|
|
static void md2_loadTexture(md2_t *model)
|
|
|
|
{
|
|
|
|
GLPatch_t *grpatch;
|
|
|
|
const char *filename = model->filename;
|
|
|
|
|
|
|
|
if (model->grpatch)
|
|
|
|
{
|
|
|
|
grpatch = model->grpatch;
|
|
|
|
Z_Free(grpatch->mipmap.grInfo.data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
grpatch = Z_Calloc(sizeof *grpatch, PU_HWRPATCHINFO,
|
|
|
|
&(model->grpatch));
|
|
|
|
|
|
|
|
if (!grpatch->mipmap.downloaded && !grpatch->mipmap.grInfo.data)
|
|
|
|
{
|
|
|
|
int w = 0, h = 0;
|
|
|
|
#ifdef HAVE_PNG
|
|
|
|
grpatch->mipmap.grInfo.format = PNG_Load(filename, &w, &h, grpatch);
|
|
|
|
if (grpatch->mipmap.grInfo.format == 0)
|
|
|
|
#endif
|
|
|
|
grpatch->mipmap.grInfo.format = PCX_Load(filename, &w, &h, grpatch);
|
|
|
|
if (grpatch->mipmap.grInfo.format == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
grpatch->mipmap.downloaded = 0;
|
|
|
|
grpatch->mipmap.flags = 0;
|
|
|
|
|
|
|
|
grpatch->width = (INT16)w;
|
|
|
|
grpatch->height = (INT16)h;
|
|
|
|
grpatch->mipmap.width = (UINT16)w;
|
|
|
|
grpatch->mipmap.height = (UINT16)h;
|
|
|
|
|
|
|
|
// not correct!
|
|
|
|
grpatch->mipmap.grInfo.smallLodLog2 = GR_LOD_LOG2_256;
|
|
|
|
grpatch->mipmap.grInfo.largeLodLog2 = GR_LOD_LOG2_256;
|
|
|
|
grpatch->mipmap.grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
|
|
|
|
}
|
|
|
|
HWD.pfnSetTexture(&grpatch->mipmap);
|
|
|
|
HWR_UnlockCachedPatch(grpatch);
|
|
|
|
}
|
|
|
|
|
2015-07-26 19:14:47 +00:00
|
|
|
// -----------------+
|
|
|
|
// md2_loadBlendTexture : Download a pcx or png texture for blending MD2 models
|
|
|
|
// -----------------+
|
|
|
|
static void md2_loadBlendTexture(md2_t *model)
|
|
|
|
{
|
|
|
|
GLPatch_t *grpatch;
|
|
|
|
char *filename = Z_Malloc(strlen(model->filename)+7, PU_STATIC, NULL);
|
|
|
|
strcpy(filename, model->filename);
|
|
|
|
|
|
|
|
FIL_ForceExtension(filename, "_blend.png");
|
|
|
|
|
|
|
|
if (model->blendgrpatch)
|
|
|
|
{
|
|
|
|
grpatch = model->blendgrpatch;
|
|
|
|
Z_Free(grpatch->mipmap.grInfo.data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
grpatch = Z_Calloc(sizeof *grpatch, PU_HWRPATCHINFO,
|
|
|
|
&(model->blendgrpatch));
|
|
|
|
|
|
|
|
if (!grpatch->mipmap.downloaded && !grpatch->mipmap.grInfo.data)
|
|
|
|
{
|
|
|
|
int w = 0, h = 0;
|
|
|
|
#ifdef HAVE_PNG
|
|
|
|
grpatch->mipmap.grInfo.format = PNG_Load(filename, &w, &h, grpatch);
|
|
|
|
if (grpatch->mipmap.grInfo.format == 0)
|
|
|
|
#endif
|
|
|
|
grpatch->mipmap.grInfo.format = PCX_Load(filename, &w, &h, grpatch);
|
|
|
|
if (grpatch->mipmap.grInfo.format == 0)
|
|
|
|
{
|
|
|
|
Z_Free(filename);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
grpatch->mipmap.downloaded = 0;
|
|
|
|
grpatch->mipmap.flags = 0;
|
|
|
|
|
|
|
|
grpatch->width = (INT16)w;
|
|
|
|
grpatch->height = (INT16)h;
|
|
|
|
grpatch->mipmap.width = (UINT16)w;
|
|
|
|
grpatch->mipmap.height = (UINT16)h;
|
|
|
|
|
|
|
|
// not correct!
|
|
|
|
grpatch->mipmap.grInfo.smallLodLog2 = GR_LOD_LOG2_256;
|
|
|
|
grpatch->mipmap.grInfo.largeLodLog2 = GR_LOD_LOG2_256;
|
|
|
|
grpatch->mipmap.grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
|
|
|
|
}
|
|
|
|
HWD.pfnSetTexture(&grpatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary
|
|
|
|
HWR_UnlockCachedPatch(grpatch);
|
|
|
|
|
|
|
|
Z_Free(filename);
|
|
|
|
}
|
|
|
|
|
2014-04-14 05:14:58 +00:00
|
|
|
// Don't spam the console, or the OS with fopen requests!
|
|
|
|
static boolean nomd2s = false;
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
void HWR_InitMD2(void)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
INT32 s;
|
|
|
|
FILE *f;
|
|
|
|
char name[18], filename[32];
|
|
|
|
float scale, offset;
|
|
|
|
|
|
|
|
CONS_Printf("InitMD2()...\n");
|
|
|
|
for (s = 0; s < MAXSKINS; s++)
|
|
|
|
{
|
|
|
|
md2_playermodels[s].scale = -1.0f;
|
|
|
|
md2_playermodels[s].model = NULL;
|
|
|
|
md2_playermodels[s].grpatch = NULL;
|
|
|
|
md2_playermodels[s].skin = -1;
|
|
|
|
md2_playermodels[s].notfound = true;
|
2016-11-03 21:06:23 +00:00
|
|
|
md2_playermodels[s].error = false;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < NUMSPRITES; i++)
|
|
|
|
{
|
|
|
|
md2_models[i].scale = -1.0f;
|
|
|
|
md2_models[i].model = NULL;
|
|
|
|
md2_models[i].grpatch = NULL;
|
|
|
|
md2_models[i].skin = -1;
|
|
|
|
md2_models[i].notfound = true;
|
2016-11-06 17:50:04 +00:00
|
|
|
md2_models[i].error = false;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
2014-04-14 05:14:58 +00:00
|
|
|
// read the md2.dat file
|
2018-05-13 19:19:36 +00:00
|
|
|
//Filename checking fixed ~Monster Iestyn and Golden
|
|
|
|
f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt");
|
2014-04-14 05:14:58 +00:00
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
if (!f)
|
|
|
|
{
|
2018-05-13 19:35:38 +00:00
|
|
|
CONS_Printf("%s %s\n", M_GetText("Error while loading md2.dat:"), strerror(errno));
|
2014-04-14 05:14:58 +00:00
|
|
|
nomd2s = true;
|
2014-03-15 16:59:03 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4)
|
|
|
|
{
|
2015-01-10 20:54:17 +00:00
|
|
|
if (stricmp(name, "PLAY") == 0)
|
|
|
|
{
|
|
|
|
CONS_Printf("MD2 for sprite PLAY detected in md2.dat, use a player skin instead!\n");
|
|
|
|
continue;
|
|
|
|
}
|
2015-06-18 14:01:57 +00:00
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
for (i = 0; i < NUMSPRITES; i++)
|
|
|
|
{
|
|
|
|
if (stricmp(name, sprnames[i]) == 0)
|
|
|
|
{
|
2015-01-10 20:54:17 +00:00
|
|
|
//if (stricmp(name, "PLAY") == 0)
|
|
|
|
//continue;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
//CONS_Debug(DBG_RENDER, " Found: %s %s %f %f\n", name, filename, scale, offset);
|
|
|
|
md2_models[i].scale = scale;
|
|
|
|
md2_models[i].offset = offset;
|
|
|
|
md2_models[i].notfound = false;
|
|
|
|
strcpy(md2_models[i].filename, filename);
|
2015-01-10 20:54:17 +00:00
|
|
|
goto md2found;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (s = 0; s < MAXSKINS; s++)
|
|
|
|
{
|
|
|
|
if (stricmp(name, skins[s].name) == 0)
|
|
|
|
{
|
|
|
|
//CONS_Printf(" Found: %s %s %f %f\n", name, filename, scale, offset);
|
|
|
|
md2_playermodels[s].skin = s;
|
|
|
|
md2_playermodels[s].scale = scale;
|
|
|
|
md2_playermodels[s].offset = offset;
|
|
|
|
md2_playermodels[s].notfound = false;
|
|
|
|
strcpy(md2_playermodels[s].filename, filename);
|
2015-01-10 20:54:17 +00:00
|
|
|
goto md2found;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-10 20:54:17 +00:00
|
|
|
// no sprite/player skin name found?!?
|
|
|
|
CONS_Printf("Unknown sprite/player skin %s detected in md2.dat\n", name);
|
|
|
|
md2found:
|
|
|
|
// move on to next line...
|
|
|
|
continue;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
char name[18], filename[32];
|
|
|
|
float scale, offset;
|
|
|
|
|
2014-04-14 05:14:58 +00:00
|
|
|
if (nomd2s)
|
|
|
|
return;
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
CONS_Printf("AddPlayerMD2()...\n");
|
|
|
|
|
|
|
|
// read the md2.dat file
|
2018-05-13 19:19:36 +00:00
|
|
|
//Filename checking fixed ~Monster Iestyn and Golden
|
|
|
|
f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt");
|
2014-04-14 05:14:58 +00:00
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
CONS_Printf("Error while loading md2.dat\n");
|
2014-04-14 05:14:58 +00:00
|
|
|
nomd2s = true;
|
2014-03-15 16:59:03 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for any MD2s that match the names of player skins!
|
|
|
|
while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4)
|
|
|
|
{
|
|
|
|
if (stricmp(name, skins[skin].name) == 0)
|
|
|
|
{
|
|
|
|
md2_playermodels[skin].skin = skin;
|
|
|
|
md2_playermodels[skin].scale = scale;
|
|
|
|
md2_playermodels[skin].offset = offset;
|
|
|
|
md2_playermodels[skin].notfound = false;
|
|
|
|
strcpy(md2_playermodels[skin].filename, filename);
|
2015-01-10 20:54:17 +00:00
|
|
|
goto playermd2found;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-10 20:54:17 +00:00
|
|
|
//CONS_Printf("MD2 for player skin %s not found\n", skins[skin].name);
|
|
|
|
md2_playermodels[skin].notfound = true;
|
|
|
|
playermd2found:
|
2014-03-15 16:59:03 +00:00
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startup
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
// name[18] is used to check for names in the md2.dat file that match with sprites or player skins
|
|
|
|
// sprite names are always 4 characters long, and names is for player skins can be up to 19 characters long
|
|
|
|
char name[18], filename[32];
|
|
|
|
float scale, offset;
|
|
|
|
|
2014-04-14 05:14:58 +00:00
|
|
|
if (nomd2s)
|
|
|
|
return;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2015-01-10 20:54:17 +00:00
|
|
|
if (spritenum == SPR_PLAY) // Handled already NEWMD2: Per sprite, per-skin check
|
|
|
|
return;
|
|
|
|
|
2014-04-14 05:14:58 +00:00
|
|
|
// Read the md2.dat file
|
2018-05-13 19:19:36 +00:00
|
|
|
//Filename checking fixed ~Monster Iestyn and Golden
|
|
|
|
f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt");
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
CONS_Printf("Error while loading md2.dat\n");
|
2014-04-14 05:14:58 +00:00
|
|
|
nomd2s = true;
|
2014-03-15 16:59:03 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-16 01:57:11 +00:00
|
|
|
// Check for any MD2s that match the names of sprite names!
|
2014-03-15 16:59:03 +00:00
|
|
|
while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4)
|
|
|
|
{
|
2015-01-10 20:54:17 +00:00
|
|
|
if (stricmp(name, sprnames[spritenum]) == 0)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2015-01-10 20:54:17 +00:00
|
|
|
md2_models[spritenum].scale = scale;
|
|
|
|
md2_models[spritenum].offset = offset;
|
|
|
|
md2_models[spritenum].notfound = false;
|
|
|
|
strcpy(md2_models[spritenum].filename, filename);
|
|
|
|
goto spritemd2found;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-10 20:54:17 +00:00
|
|
|
//CONS_Printf("MD2 for sprite %s not found\n", sprnames[spritenum]);
|
|
|
|
md2_models[spritenum].notfound = true;
|
|
|
|
spritemd2found:
|
2014-03-15 16:59:03 +00:00
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
2015-07-26 19:14:47 +00:00
|
|
|
static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, skincolors_t color)
|
|
|
|
{
|
|
|
|
UINT16 w = gpatch->width, h = gpatch->height;
|
2016-01-20 15:55:32 +00:00
|
|
|
UINT32 size = w*h;
|
|
|
|
RGBA_t *image, *blendimage, *cur, blendcolor;
|
2015-07-26 19:14:47 +00:00
|
|
|
|
|
|
|
if (grmip->width == 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
grmip->width = gpatch->width;
|
|
|
|
grmip->height = gpatch->height;
|
|
|
|
|
|
|
|
// no wrap around, no chroma key
|
|
|
|
grmip->flags = 0;
|
|
|
|
// setup the texture info
|
|
|
|
grmip->grInfo.format = GR_RGBA;
|
|
|
|
}
|
|
|
|
|
|
|
|
Z_Free(grmip->grInfo.data);
|
|
|
|
grmip->grInfo.data = NULL;
|
|
|
|
|
|
|
|
cur = Z_Malloc(size*4, PU_HWRCACHE, &grmip->grInfo.data);
|
|
|
|
memset(cur, 0x00, size*4);
|
|
|
|
|
|
|
|
image = gpatch->mipmap.grInfo.data;
|
|
|
|
blendimage = blendgpatch->mipmap.grInfo.data;
|
|
|
|
|
|
|
|
switch (color)
|
|
|
|
{
|
|
|
|
case SKINCOLOR_WHITE:
|
|
|
|
blendcolor = V_GetColor(3);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_SILVER:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(10);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_GREY:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(15);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_BLACK:
|
|
|
|
blendcolor = V_GetColor(27);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_CYAN:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(215);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_TEAL:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(221);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_STEELBLUE:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(203);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_BLUE:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(232);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_PEACH:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(71);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_TAN:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(79);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_PINK:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(147);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_LAVENDER:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(251);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_PURPLE:
|
|
|
|
blendcolor = V_GetColor(195);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_ORANGE:
|
|
|
|
blendcolor = V_GetColor(87);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_ROSEWOOD:
|
|
|
|
blendcolor = V_GetColor(94);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_BEIGE:
|
|
|
|
blendcolor = V_GetColor(40);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_BROWN:
|
|
|
|
blendcolor = V_GetColor(57);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_RED:
|
|
|
|
blendcolor = V_GetColor(130);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_DARKRED:
|
|
|
|
blendcolor = V_GetColor(139);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_NEONGREEN:
|
|
|
|
blendcolor = V_GetColor(184);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_GREEN:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(166);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_ZIM:
|
|
|
|
blendcolor = V_GetColor(180);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_OLIVE:
|
|
|
|
blendcolor = V_GetColor(108);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_YELLOW:
|
|
|
|
blendcolor = V_GetColor(104);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_GOLD:
|
|
|
|
blendcolor = V_GetColor(115);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SKINCOLOR_SUPER1:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(97);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_SUPER2:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(100);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_SUPER3:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(103);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_SUPER4:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(113);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_SUPER5:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(116);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SKINCOLOR_TSUPER1:
|
2015-08-03 01:01:56 +00:00
|
|
|
blendcolor = V_GetColor(81);
|
2015-07-26 19:14:47 +00:00
|
|
|
break;
|
|
|
|
case SKINCOLOR_TSUPER2:
|
|
|
|
blendcolor = V_GetColor(82);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_TSUPER3:
|
|
|
|
blendcolor = V_GetColor(84);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_TSUPER4:
|
|
|
|
blendcolor = V_GetColor(85);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_TSUPER5:
|
|
|
|
blendcolor = V_GetColor(87);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SKINCOLOR_KSUPER1:
|
|
|
|
blendcolor = V_GetColor(122);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_KSUPER2:
|
|
|
|
blendcolor = V_GetColor(123);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_KSUPER3:
|
|
|
|
blendcolor = V_GetColor(124);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_KSUPER4:
|
|
|
|
blendcolor = V_GetColor(125);
|
|
|
|
break;
|
|
|
|
case SKINCOLOR_KSUPER5:
|
|
|
|
blendcolor = V_GetColor(126);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
blendcolor = V_GetColor(247);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (size--)
|
|
|
|
{
|
|
|
|
if (blendimage->s.alpha == 0)
|
|
|
|
{
|
|
|
|
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
|
|
|
|
cur->rgba = image->rgba;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
INT32 tempcolor;
|
|
|
|
INT16 tempmult, tempalpha;
|
|
|
|
tempalpha = -(abs(blendimage->s.red-127)-127)*2;
|
|
|
|
if (tempalpha > 255)
|
|
|
|
tempalpha = 255;
|
|
|
|
else if (tempalpha < 0)
|
|
|
|
tempalpha = 0;
|
|
|
|
|
|
|
|
tempmult = (blendimage->s.red-127)*2;
|
|
|
|
if (tempmult > 255)
|
|
|
|
tempmult = 255;
|
|
|
|
else if (tempmult < 0)
|
|
|
|
tempmult = 0;
|
|
|
|
|
|
|
|
tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255;
|
|
|
|
cur->s.red = (UINT8)tempcolor;
|
|
|
|
tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255;
|
|
|
|
cur->s.green = (UINT8)tempcolor;
|
|
|
|
tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255;
|
|
|
|
cur->s.blue = (UINT8)tempcolor;
|
|
|
|
cur->s.alpha = image->s.alpha;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur++; image++; blendimage++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, const UINT8 *colormap, skincolors_t color)
|
|
|
|
{
|
|
|
|
// mostly copied from HWR_GetMappedPatch, hence the similarities and comment
|
|
|
|
GLMipmap_t *grmip, *newmip;
|
|
|
|
|
|
|
|
if (colormap == colormaps || colormap == NULL)
|
|
|
|
{
|
|
|
|
// Don't do any blending
|
|
|
|
HWD.pfnSetTexture(&gpatch->mipmap);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// search for the mimmap
|
|
|
|
// skip the first (no colormap translated)
|
|
|
|
for (grmip = &gpatch->mipmap; grmip->nextcolormap; )
|
|
|
|
{
|
|
|
|
grmip = grmip->nextcolormap;
|
|
|
|
if (grmip->colormap == colormap)
|
|
|
|
{
|
|
|
|
if (grmip->downloaded && grmip->grInfo.data)
|
|
|
|
{
|
|
|
|
HWD.pfnSetTexture(grmip); // found the colormap, set it to the correct texture
|
|
|
|
Z_ChangeTag(grmip->grInfo.data, PU_HWRCACHE_UNLOCKED);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If here, the blended texture has not been created
|
|
|
|
// So we create it
|
|
|
|
|
|
|
|
//BP: WARNING: don't free it manually without clearing the cache of harware renderer
|
|
|
|
// (it have a liste of mipmap)
|
|
|
|
// this malloc is cleared in HWR_FreeTextureCache
|
|
|
|
// (...) unfortunately z_malloc fragment alot the memory :(so malloc is better
|
|
|
|
newmip = calloc(1, sizeof (*newmip));
|
|
|
|
if (newmip == NULL)
|
|
|
|
I_Error("%s: Out of memory", "HWR_GetMappedPatch");
|
|
|
|
grmip->nextcolormap = newmip;
|
|
|
|
newmip->colormap = colormap;
|
|
|
|
|
|
|
|
HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, color);
|
|
|
|
|
|
|
|
HWD.pfnSetTexture(newmip);
|
|
|
|
Z_ChangeTag(newmip->grInfo.data, PU_HWRCACHE_UNLOCKED);
|
|
|
|
}
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// -----------------+
|
|
|
|
// HWR_DrawMD2 : Draw MD2
|
|
|
|
// : (monsters, bonuses, weapons, lights, ...)
|
|
|
|
// Returns :
|
|
|
|
// -----------------+
|
|
|
|
/*
|
|
|
|
wait/stand
|
|
|
|
death
|
|
|
|
pain
|
|
|
|
walk
|
|
|
|
shoot/fire
|
|
|
|
|
|
|
|
die?
|
|
|
|
atka?
|
|
|
|
atkb?
|
|
|
|
attacka/b/c/d?
|
|
|
|
res?
|
|
|
|
run?
|
|
|
|
*/
|
|
|
|
#define NORMALFOG 0x00000000
|
|
|
|
#define FADEFOG 0x19000000
|
|
|
|
void HWR_DrawMD2(gr_vissprite_t *spr)
|
|
|
|
{
|
|
|
|
FSurfaceInfo Surf;
|
|
|
|
|
|
|
|
char filename[64];
|
|
|
|
md2_t *md2;
|
|
|
|
|
2015-01-28 15:16:50 +00:00
|
|
|
if (!cv_grmd2.value)
|
|
|
|
return;
|
|
|
|
|
2016-01-03 03:53:43 +00:00
|
|
|
if (spr->precip)
|
2015-01-28 15:16:50 +00:00
|
|
|
return;
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// MD2 colormap fix
|
|
|
|
// colormap test
|
|
|
|
{
|
|
|
|
sector_t *sector = spr->mobj->subsector->sector;
|
2015-01-10 20:54:17 +00:00
|
|
|
UINT8 lightlevel = 255;
|
2014-03-15 16:59:03 +00:00
|
|
|
extracolormap_t *colormap = sector->extra_colormap;
|
|
|
|
|
|
|
|
if (sector->numlights)
|
|
|
|
{
|
2014-03-19 23:10:37 +00:00
|
|
|
INT32 light;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2014-03-19 23:10:37 +00:00
|
|
|
light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2014-03-19 23:10:37 +00:00
|
|
|
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
2014-03-24 16:11:25 +00:00
|
|
|
lightlevel = *sector->lightlist[light].lightlevel;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2014-03-19 23:10:37 +00:00
|
|
|
if (sector->lightlist[light].extra_colormap)
|
|
|
|
colormap = sector->lightlist[light].extra_colormap;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
2014-03-24 16:11:25 +00:00
|
|
|
lightlevel = sector->lightlevel;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
if (sector->extra_colormap)
|
|
|
|
colormap = sector->extra_colormap;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (colormap)
|
|
|
|
Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
|
|
|
|
else
|
|
|
|
Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
|
|
|
|
}
|
|
|
|
|
2015-01-28 15:16:50 +00:00
|
|
|
// Look at HWR_ProjectSprite for more
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
|
|
|
GLPatch_t *gpatch;
|
2014-04-07 11:37:15 +00:00
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
if (spr->mobj->flags2 & MF2_SHADOW)
|
|
|
|
Surf.FlatColor.s.alpha = 0x40;
|
|
|
|
else if (spr->mobj->frame & FF_TRANSMASK)
|
2014-03-21 18:03:40 +00:00
|
|
|
HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
|
2014-03-15 16:59:03 +00:00
|
|
|
else
|
|
|
|
Surf.FlatColor.s.alpha = 0xFF;
|
|
|
|
|
|
|
|
// dont forget to enabled the depth test because we can't do this like
|
|
|
|
// before: polygons models are not sorted
|
|
|
|
|
|
|
|
// 1. load model+texture if not already loaded
|
|
|
|
// 2. draw model with correct position, rotation,...
|
2014-03-19 23:10:37 +00:00
|
|
|
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) // Use the player MD2 list if the mobj has a skin and is using the player sprites
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
|
|
|
md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins];
|
|
|
|
md2->skin = (skin_t*)spr->mobj->skin-skins;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
md2 = &md2_models[spr->mobj->sprite];
|
|
|
|
|
2016-11-03 21:06:23 +00:00
|
|
|
if (md2->error)
|
|
|
|
return; // we already failed loading this before :(
|
2014-03-15 16:59:03 +00:00
|
|
|
if (!md2->model)
|
|
|
|
{
|
|
|
|
//CONS_Debug(DBG_RENDER, "Loading MD2... (%s)", sprnames[spr->mobj->sprite]);
|
|
|
|
sprintf(filename, "md2/%s", md2->filename);
|
|
|
|
md2->model = md2_readModel(filename);
|
|
|
|
|
|
|
|
if (md2->model)
|
|
|
|
{
|
|
|
|
md2_printModelInfo(md2->model);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//CONS_Debug(DBG_RENDER, " FAILED\n");
|
2016-11-03 21:06:23 +00:00
|
|
|
md2->error = true; // prevent endless fail
|
2014-03-15 16:59:03 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-03-19 23:10:37 +00:00
|
|
|
//HWD.pfnSetBlend(blend); // This seems to actually break translucency?
|
2014-03-15 16:59:03 +00:00
|
|
|
//Hurdler: arf, I don't like that implementation at all... too much crappy
|
|
|
|
gpatch = md2->grpatch;
|
|
|
|
if (!gpatch || !gpatch->mipmap.grInfo.format || !gpatch->mipmap.downloaded)
|
|
|
|
md2_loadTexture(md2);
|
2014-03-30 16:45:58 +00:00
|
|
|
gpatch = md2->grpatch; // Load it again, because it isn't being loaded into gpatch after md2_loadtexture...
|
|
|
|
|
2015-07-26 19:14:47 +00:00
|
|
|
if ((gpatch && gpatch->mipmap.grInfo.format) // don't load the blend texture if the base texture isn't available
|
|
|
|
&& (!md2->blendgrpatch || !((GLPatch_t *)md2->blendgrpatch)->mipmap.grInfo.format || !((GLPatch_t *)md2->blendgrpatch)->mipmap.downloaded))
|
|
|
|
md2_loadBlendTexture(md2);
|
|
|
|
|
2014-03-19 23:10:37 +00:00
|
|
|
if (gpatch && gpatch->mipmap.grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2015-07-26 19:14:47 +00:00
|
|
|
if ((skincolors_t)spr->mobj->color != SKINCOLOR_NONE &&
|
|
|
|
md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap.grInfo.format
|
|
|
|
&& gpatch->width == ((GLPatch_t *)md2->blendgrpatch)->width && gpatch->height == ((GLPatch_t *)md2->blendgrpatch)->height)
|
|
|
|
{
|
|
|
|
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, spr->colormap, (skincolors_t)spr->mobj->color);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This is safe, since we know the texture has been downloaded
|
|
|
|
HWD.pfnSetTexture(&gpatch->mipmap);
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Sprite
|
|
|
|
gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
|
|
|
|
HWR_GetMappedPatch(gpatch, spr->colormap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif //HWRENDER
|