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-02-05 02:11:17 +00:00
# include "../r_draw.h"
# include "../p_tick.h"
2018-07-04 23:06:45 +00:00
# include "../k_kart.h" // colortranslations
2014-03-15 16:59:03 +00:00
# include "hw_main.h"
2016-07-06 04:09:17 +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
# define NUMVERTEXNORMALS 162
float avertexnormals [ NUMVERTEXNORMALS ] [ 3 ] = {
{ - 0.525731f , 0.000000f , 0.850651f } ,
{ - 0.442863f , 0.238856f , 0.864188f } ,
{ - 0.295242f , 0.000000f , 0.955423f } ,
{ - 0.309017f , 0.500000f , 0.809017f } ,
{ - 0.162460f , 0.262866f , 0.951056f } ,
{ 0.000000f , 0.000000f , 1.000000f } ,
{ 0.000000f , 0.850651f , 0.525731f } ,
{ - 0.147621f , 0.716567f , 0.681718f } ,
{ 0.147621f , 0.716567f , 0.681718f } ,
{ 0.000000f , 0.525731f , 0.850651f } ,
{ 0.309017f , 0.500000f , 0.809017f } ,
{ 0.525731f , 0.000000f , 0.850651f } ,
{ 0.295242f , 0.000000f , 0.955423f } ,
{ 0.442863f , 0.238856f , 0.864188f } ,
{ 0.162460f , 0.262866f , 0.951056f } ,
{ - 0.681718f , 0.147621f , 0.716567f } ,
{ - 0.809017f , 0.309017f , 0.500000f } ,
{ - 0.587785f , 0.425325f , 0.688191f } ,
{ - 0.850651f , 0.525731f , 0.000000f } ,
{ - 0.864188f , 0.442863f , 0.238856f } ,
{ - 0.716567f , 0.681718f , 0.147621f } ,
{ - 0.688191f , 0.587785f , 0.425325f } ,
{ - 0.500000f , 0.809017f , 0.309017f } ,
{ - 0.238856f , 0.864188f , 0.442863f } ,
{ - 0.425325f , 0.688191f , 0.587785f } ,
{ - 0.716567f , 0.681718f , - 0.147621f } ,
{ - 0.500000f , 0.809017f , - 0.309017f } ,
{ - 0.525731f , 0.850651f , 0.000000f } ,
{ 0.000000f , 0.850651f , - 0.525731f } ,
{ - 0.238856f , 0.864188f , - 0.442863f } ,
{ 0.000000f , 0.955423f , - 0.295242f } ,
{ - 0.262866f , 0.951056f , - 0.162460f } ,
{ 0.000000f , 1.000000f , 0.000000f } ,
{ 0.000000f , 0.955423f , 0.295242f } ,
{ - 0.262866f , 0.951056f , 0.162460f } ,
{ 0.238856f , 0.864188f , 0.442863f } ,
{ 0.262866f , 0.951056f , 0.162460f } ,
{ 0.500000f , 0.809017f , 0.309017f } ,
{ 0.238856f , 0.864188f , - 0.442863f } ,
{ 0.262866f , 0.951056f , - 0.162460f } ,
{ 0.500000f , 0.809017f , - 0.309017f } ,
{ 0.850651f , 0.525731f , 0.000000f } ,
{ 0.716567f , 0.681718f , 0.147621f } ,
{ 0.716567f , 0.681718f , - 0.147621f } ,
{ 0.525731f , 0.850651f , 0.000000f } ,
{ 0.425325f , 0.688191f , 0.587785f } ,
{ 0.864188f , 0.442863f , 0.238856f } ,
{ 0.688191f , 0.587785f , 0.425325f } ,
{ 0.809017f , 0.309017f , 0.500000f } ,
{ 0.681718f , 0.147621f , 0.716567f } ,
{ 0.587785f , 0.425325f , 0.688191f } ,
{ 0.955423f , 0.295242f , 0.000000f } ,
{ 1.000000f , 0.000000f , 0.000000f } ,
{ 0.951056f , 0.162460f , 0.262866f } ,
{ 0.850651f , - 0.525731f , 0.000000f } ,
{ 0.955423f , - 0.295242f , 0.000000f } ,
{ 0.864188f , - 0.442863f , 0.238856f } ,
{ 0.951056f , - 0.162460f , 0.262866f } ,
{ 0.809017f , - 0.309017f , 0.500000f } ,
{ 0.681718f , - 0.147621f , 0.716567f } ,
{ 0.850651f , 0.000000f , 0.525731f } ,
{ 0.864188f , 0.442863f , - 0.238856f } ,
{ 0.809017f , 0.309017f , - 0.500000f } ,
{ 0.951056f , 0.162460f , - 0.262866f } ,
{ 0.525731f , 0.000000f , - 0.850651f } ,
{ 0.681718f , 0.147621f , - 0.716567f } ,
{ 0.681718f , - 0.147621f , - 0.716567f } ,
{ 0.850651f , 0.000000f , - 0.525731f } ,
{ 0.809017f , - 0.309017f , - 0.500000f } ,
{ 0.864188f , - 0.442863f , - 0.238856f } ,
{ 0.951056f , - 0.162460f , - 0.262866f } ,
{ 0.147621f , 0.716567f , - 0.681718f } ,
{ 0.309017f , 0.500000f , - 0.809017f } ,
{ 0.425325f , 0.688191f , - 0.587785f } ,
{ 0.442863f , 0.238856f , - 0.864188f } ,
{ 0.587785f , 0.425325f , - 0.688191f } ,
{ 0.688191f , 0.587785f , - 0.425325f } ,
{ - 0.147621f , 0.716567f , - 0.681718f } ,
{ - 0.309017f , 0.500000f , - 0.809017f } ,
{ 0.000000f , 0.525731f , - 0.850651f } ,
{ - 0.525731f , 0.000000f , - 0.850651f } ,
{ - 0.442863f , 0.238856f , - 0.864188f } ,
{ - 0.295242f , 0.000000f , - 0.955423f } ,
{ - 0.162460f , 0.262866f , - 0.951056f } ,
{ 0.000000f , 0.000000f , - 1.000000f } ,
{ 0.295242f , 0.000000f , - 0.955423f } ,
{ 0.162460f , 0.262866f , - 0.951056f } ,
{ - 0.442863f , - 0.238856f , - 0.864188f } ,
{ - 0.309017f , - 0.500000f , - 0.809017f } ,
{ - 0.162460f , - 0.262866f , - 0.951056f } ,
{ 0.000000f , - 0.850651f , - 0.525731f } ,
{ - 0.147621f , - 0.716567f , - 0.681718f } ,
{ 0.147621f , - 0.716567f , - 0.681718f } ,
{ 0.000000f , - 0.525731f , - 0.850651f } ,
{ 0.309017f , - 0.500000f , - 0.809017f } ,
{ 0.442863f , - 0.238856f , - 0.864188f } ,
{ 0.162460f , - 0.262866f , - 0.951056f } ,
{ 0.238856f , - 0.864188f , - 0.442863f } ,
{ 0.500000f , - 0.809017f , - 0.309017f } ,
{ 0.425325f , - 0.688191f , - 0.587785f } ,
{ 0.716567f , - 0.681718f , - 0.147621f } ,
{ 0.688191f , - 0.587785f , - 0.425325f } ,
{ 0.587785f , - 0.425325f , - 0.688191f } ,
{ 0.000000f , - 0.955423f , - 0.295242f } ,
{ 0.000000f , - 1.000000f , 0.000000f } ,
{ 0.262866f , - 0.951056f , - 0.162460f } ,
{ 0.000000f , - 0.850651f , 0.525731f } ,
{ 0.000000f , - 0.955423f , 0.295242f } ,
{ 0.238856f , - 0.864188f , 0.442863f } ,
{ 0.262866f , - 0.951056f , 0.162460f } ,
{ 0.500000f , - 0.809017f , 0.309017f } ,
{ 0.716567f , - 0.681718f , 0.147621f } ,
{ 0.525731f , - 0.850651f , 0.000000f } ,
{ - 0.238856f , - 0.864188f , - 0.442863f } ,
{ - 0.500000f , - 0.809017f , - 0.309017f } ,
{ - 0.262866f , - 0.951056f , - 0.162460f } ,
{ - 0.850651f , - 0.525731f , 0.000000f } ,
{ - 0.716567f , - 0.681718f , - 0.147621f } ,
{ - 0.716567f , - 0.681718f , 0.147621f } ,
{ - 0.525731f , - 0.850651f , 0.000000f } ,
{ - 0.500000f , - 0.809017f , 0.309017f } ,
{ - 0.238856f , - 0.864188f , 0.442863f } ,
{ - 0.262866f , - 0.951056f , 0.162460f } ,
{ - 0.864188f , - 0.442863f , 0.238856f } ,
{ - 0.809017f , - 0.309017f , 0.500000f } ,
{ - 0.688191f , - 0.587785f , 0.425325f } ,
{ - 0.681718f , - 0.147621f , 0.716567f } ,
{ - 0.442863f , - 0.238856f , 0.864188f } ,
{ - 0.587785f , - 0.425325f , 0.688191f } ,
{ - 0.309017f , - 0.500000f , 0.809017f } ,
{ - 0.147621f , - 0.716567f , 0.681718f } ,
{ - 0.425325f , - 0.688191f , 0.587785f } ,
{ - 0.162460f , - 0.262866f , 0.951056f } ,
{ 0.442863f , - 0.238856f , 0.864188f } ,
{ 0.162460f , - 0.262866f , 0.951056f } ,
{ 0.309017f , - 0.500000f , 0.809017f } ,
{ 0.147621f , - 0.716567f , 0.681718f } ,
{ 0.000000f , - 0.525731f , 0.850651f } ,
{ 0.425325f , - 0.688191f , 0.587785f } ,
{ 0.587785f , - 0.425325f , 0.688191f } ,
{ 0.688191f , - 0.587785f , 0.425325f } ,
{ - 0.955423f , 0.295242f , 0.000000f } ,
{ - 0.951056f , 0.162460f , 0.262866f } ,
{ - 1.000000f , 0.000000f , 0.000000f } ,
{ - 0.850651f , 0.000000f , 0.525731f } ,
{ - 0.955423f , - 0.295242f , 0.000000f } ,
{ - 0.951056f , - 0.162460f , 0.262866f } ,
{ - 0.864188f , 0.442863f , - 0.238856f } ,
{ - 0.951056f , 0.162460f , - 0.262866f } ,
{ - 0.809017f , 0.309017f , - 0.500000f } ,
{ - 0.864188f , - 0.442863f , - 0.238856f } ,
{ - 0.951056f , - 0.162460f , - 0.262866f } ,
{ - 0.809017f , - 0.309017f , - 0.500000f } ,
{ - 0.681718f , 0.147621f , - 0.716567f } ,
{ - 0.681718f , - 0.147621f , - 0.716567f } ,
{ - 0.850651f , 0.000000f , - 0.525731f } ,
{ - 0.688191f , 0.587785f , - 0.425325f } ,
{ - 0.587785f , 0.425325f , - 0.688191f } ,
{ - 0.425325f , 0.688191f , - 0.587785f } ,
{ - 0.425325f , - 0.688191f , - 0.587785f } ,
{ - 0.587785f , - 0.425325f , - 0.688191f } ,
{ - 0.688191f , - 0.587785f , - 0.425325f } ,
} ;
md2_t md2_models [ NUMSPRITES ] ;
md2_t md2_playermodels [ MAXSKINS ] ;
/*
* free model
*/
static void md2_freeModel ( md2_model_t * model )
{
if ( model )
{
if ( model - > skins )
free ( model - > skins ) ;
if ( model - > texCoords )
free ( model - > texCoords ) ;
if ( model - > triangles )
free ( model - > triangles ) ;
if ( model - > frames )
{
size_t i ;
for ( i = 0 ; i < model - > header . numFrames ; i + + )
{
if ( model - > frames [ i ] . vertices )
free ( model - > frames [ i ] . vertices ) ;
}
free ( model - > frames ) ;
}
if ( model - > glCommandBuffer )
free ( model - > glCommandBuffer ) ;
free ( model ) ;
}
}
//
// load model
//
// Hurdler: the current path is the Legacy.exe path
static md2_model_t * md2_readModel ( const char * filename )
{
FILE * file ;
md2_model_t * model ;
UINT8 buffer [ MD2_MAX_FRAMESIZE ] ;
size_t i ;
model = calloc ( 1 , sizeof ( * model ) ) ;
if ( model = = NULL )
return 0 ;
2018-05-13 19:19:36 +00:00
//Filename checking fixed ~Monster Iestyn and Golden
file = fopen ( va ( " %s " PATHSEP " %s " , srb2home , filename ) , " rb " ) ;
2014-03-15 16:59:03 +00:00
if ( ! file )
{
2019-01-09 21:53:59 +00:00
file = fopen ( va ( " %s " PATHSEP " %s " , srb2path , filename ) , " rb " ) ;
if ( ! file )
{
free ( model ) ;
return 0 ;
}
2014-03-15 16:59:03 +00:00
}
// initialize model and read header
if ( fread ( & model - > header , sizeof ( model - > header ) , 1 , file ) ! = 1
2016-11-05 20:40:48 +00:00
| | model - > header . magic ! = MD2_IDENT
| | model - > header . version ! = MD2_VERSION )
2014-03-15 16:59:03 +00:00
{
fclose ( file ) ;
free ( model ) ;
return 0 ;
}
model - > header . numSkins = 1 ;
2016-11-03 20:40:17 +00:00
# define MD2LIMITCHECK(field, max, msgname) \
2016-11-05 17:38:36 +00:00
if ( field > max ) \
2016-11-03 20:40:17 +00:00
{ \
CONS_Alert ( CONS_ERROR , " md2_readModel: %s has too many " msgname " (# found: %d, maximum: %d) \n " , filename , field , max ) ; \
md2_freeModel ( model ) ; \
2016-11-05 20:51:48 +00:00
fclose ( file ) ; \
2016-11-03 20:40:17 +00:00
return 0 ; \
}
// Uncomment if these are actually needed
// MD2LIMITCHECK(model->header.numSkins, MD2_MAX_SKINS, "skins")
// MD2LIMITCHECK(model->header.numTexCoords, MD2_MAX_TEXCOORDS, "texture coordinates")
2016-11-03 22:53:49 +00:00
MD2LIMITCHECK ( model - > header . numTriangles , MD2_MAX_TRIANGLES , " triangles " )
MD2LIMITCHECK ( model - > header . numFrames , MD2_MAX_FRAMES , " frames " )
2016-11-03 20:40:17 +00:00
MD2LIMITCHECK ( model - > header . numVertices , MD2_MAX_VERTICES , " vertices " )
# undef MD2LIMITCHECK
2014-03-15 16:59:03 +00:00
// read skins
fseek ( file , model - > header . offsetSkins , SEEK_SET ) ;
if ( model - > header . numSkins > 0 )
{
model - > skins = calloc ( sizeof ( md2_skin_t ) , model - > header . numSkins ) ;
if ( ! model - > skins | | model - > header . numSkins ! =
fread ( model - > skins , sizeof ( md2_skin_t ) , model - > header . numSkins , file ) )
{
md2_freeModel ( model ) ;
2016-11-05 20:51:48 +00:00
fclose ( file ) ;
2014-03-15 16:59:03 +00:00
return 0 ;
}
}
// read texture coordinates
fseek ( file , model - > header . offsetTexCoords , SEEK_SET ) ;
if ( model - > header . numTexCoords > 0 )
{
model - > texCoords = calloc ( sizeof ( md2_textureCoordinate_t ) , model - > header . numTexCoords ) ;
if ( ! model - > texCoords | | model - > header . numTexCoords ! =
fread ( model - > texCoords , sizeof ( md2_textureCoordinate_t ) , model - > header . numTexCoords , file ) )
{
md2_freeModel ( model ) ;
2016-11-05 20:51:48 +00:00
fclose ( file ) ;
2014-03-15 16:59:03 +00:00
return 0 ;
}
}
// read triangles
fseek ( file , model - > header . offsetTriangles , SEEK_SET ) ;
if ( model - > header . numTriangles > 0 )
{
model - > triangles = calloc ( sizeof ( md2_triangle_t ) , model - > header . numTriangles ) ;
if ( ! model - > triangles | | model - > header . numTriangles ! =
fread ( model - > triangles , sizeof ( md2_triangle_t ) , model - > header . numTriangles , file ) )
{
md2_freeModel ( model ) ;
2016-11-05 20:51:48 +00:00
fclose ( file ) ;
2014-03-15 16:59:03 +00:00
return 0 ;
}
}
// read alias frames
fseek ( file , model - > header . offsetFrames , SEEK_SET ) ;
if ( model - > header . numFrames > 0 )
{
model - > frames = calloc ( sizeof ( md2_frame_t ) , model - > header . numFrames ) ;
if ( ! model - > frames )
{
md2_freeModel ( model ) ;
2016-11-05 20:51:48 +00:00
fclose ( file ) ;
2014-03-15 16:59:03 +00:00
return 0 ;
}
for ( i = 0 ; i < model - > header . numFrames ; i + + )
{
md2_alias_frame_t * frame = ( md2_alias_frame_t * ) ( void * ) buffer ;
size_t j ;
model - > frames [ i ] . vertices = calloc ( sizeof ( md2_triangleVertex_t ) , model - > header . numVertices ) ;
if ( ! model - > frames [ i ] . vertices | | model - > header . frameSize ! =
fread ( frame , 1 , model - > header . frameSize , file ) )
{
md2_freeModel ( model ) ;
2016-11-05 20:51:48 +00:00
fclose ( file ) ;
2014-03-15 16:59:03 +00:00
return 0 ;
}
strcpy ( model - > frames [ i ] . name , frame - > name ) ;
for ( j = 0 ; j < model - > header . numVertices ; j + + )
{
model - > frames [ i ] . vertices [ j ] . vertex [ 0 ] = ( float ) ( ( INT32 ) frame - > alias_vertices [ j ] . vertex [ 0 ] ) * frame - > scale [ 0 ] + frame - > translate [ 0 ] ;
model - > frames [ i ] . vertices [ j ] . vertex [ 2 ] = - 1 * ( ( float ) ( ( INT32 ) frame - > alias_vertices [ j ] . vertex [ 1 ] ) * frame - > scale [ 1 ] + frame - > translate [ 1 ] ) ;
model - > frames [ i ] . vertices [ j ] . vertex [ 1 ] = ( float ) ( ( INT32 ) frame - > alias_vertices [ j ] . vertex [ 2 ] ) * frame - > scale [ 2 ] + frame - > translate [ 2 ] ;
model - > frames [ i ] . vertices [ j ] . normal [ 0 ] = avertexnormals [ frame - > alias_vertices [ j ] . lightNormalIndex ] [ 0 ] ;
model - > frames [ i ] . vertices [ j ] . normal [ 1 ] = avertexnormals [ frame - > alias_vertices [ j ] . lightNormalIndex ] [ 1 ] ;
model - > frames [ i ] . vertices [ j ] . normal [ 2 ] = avertexnormals [ frame - > alias_vertices [ j ] . lightNormalIndex ] [ 2 ] ;
}
}
}
// read gl commands
fseek ( file , model - > header . offsetGlCommands , SEEK_SET ) ;
if ( model - > header . numGlCommands )
{
model - > glCommandBuffer = calloc ( sizeof ( INT32 ) , model - > header . numGlCommands ) ;
if ( ! model - > glCommandBuffer | | model - > header . numGlCommands ! =
fread ( model - > glCommandBuffer , sizeof ( INT32 ) , model - > header . numGlCommands , file ) )
{
md2_freeModel ( model ) ;
2016-11-05 20:51:48 +00:00
fclose ( file ) ;
2014-03-15 16:59:03 +00:00
return 0 ;
}
}
fclose ( file ) ;
return model ;
}
static inline void md2_printModelInfo ( md2_model_t * model )
{
#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
2019-01-19 02:28:31 +00:00
volatile 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 )
{
2019-01-09 21:53:59 +00:00
pngfilename = va ( " %s " PATHSEP " md2 " PATHSEP " %s " , srb2path , filename ) ;
FIL_ForceExtension ( pngfilename , " .png " ) ;
png_FILE = fopen ( pngfilename , " rb " ) ;
2014-03-15 16:59:03 +00:00
//CONS_Debug(DBG_RENDER, "M_SavePNG: Error on opening %s for loading\n", filename);
2019-01-09 21:53:59 +00:00
if ( ! png_FILE )
return 0 ;
2014-03-15 16:59:03 +00:00
}
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 )
2019-01-09 21:53:59 +00:00
{
pcxfilename = va ( " %s " PATHSEP " md2 " PATHSEP " %s " , srb2path , filename ) ;
FIL_ForceExtension ( pcxfilename , " .pcx " ) ;
file = fopen ( pcxfilename , " rb " ) ;
if ( ! file )
return 0 ;
}
2014-03-15 16:59:03 +00:00
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 ) ;
}
2016-07-06 04:09:17 +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
2018-08-07 20:20:27 +00:00
f = fopen ( va ( " %s " PATHSEP " %s " , srb2home , " kmd2.dat " ) , " rt " ) ;
2014-04-14 05:14:58 +00:00
2014-03-15 16:59:03 +00:00
if ( ! f )
{
2019-01-09 21:35:51 +00:00
f = fopen ( va ( " %s " PATHSEP " %s " , srb2path , " kmd2.dat " ) , " rt " ) ;
if ( ! f )
{
CONS_Printf ( " %s %s \n " , M_GetText ( " Error while loading kmd2.dat: " ) , strerror ( errno ) ) ;
nomd2s = true ;
return ;
}
2014-03-15 16:59:03 +00:00
}
while ( fscanf ( f , " %19s %31s %f %f " , name , filename , & scale , & offset ) = = 4 )
{
2019-01-08 17:57:10 +00:00
/*if (stricmp(name, "PLAY") == 0)
2016-07-06 04:09:17 +00:00
{
2017-10-12 01:26:34 +00:00
CONS_Printf ( " MD2 for sprite PLAY detected in kmd2.dat, use a player skin instead! \n " ) ;
2016-07-06 04:09:17 +00:00
continue ;
2019-01-08 17:57:10 +00:00
} */
// 8/1/19: Allow PLAY to load for default MD2.
2016-07-06 04:09:17 +00:00
2014-03-15 16:59:03 +00:00
for ( i = 0 ; i < NUMSPRITES ; i + + )
{
if ( stricmp ( name , sprnames [ i ] ) = = 0 )
{
2016-07-06 04:09: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 ) ;
2016-07-06 04:09: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 ) ;
2016-07-06 04:09:17 +00:00
goto md2found ;
2014-03-15 16:59:03 +00:00
}
}
2016-07-06 04:09:17 +00:00
// no sprite/player skin name found?!?
2017-10-12 01:26:34 +00:00
CONS_Printf ( " Unknown sprite/player skin %s detected in kmd2.dat \n " , name ) ;
2016-07-06 04:09:17 +00:00
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
2018-08-07 20:20:27 +00:00
f = fopen ( va ( " %s " PATHSEP " %s " , srb2home , " kmd2.dat " ) , " rt " ) ;
2014-04-14 05:14:58 +00:00
2014-03-15 16:59:03 +00:00
if ( ! f )
{
2019-01-09 21:35:51 +00:00
f = fopen ( va ( " %s " PATHSEP " %s " , srb2path , " kmd2.dat " ) , " rt " ) ;
if ( ! f )
{
CONS_Printf ( " %s %s \n " , M_GetText ( " Error while loading kmd2.dat: " ) , strerror ( errno ) ) ;
nomd2s = true ;
return ;
}
2014-03-15 16:59:03 +00:00
}
// 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 ) ;
2016-07-06 04:09:17 +00:00
goto playermd2found ;
2014-03-15 16:59:03 +00:00
}
}
2016-07-06 04:09: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 ;
2017-10-12 01:26:34 +00:00
// name[18] is used to check for names in the kmd2.dat file that match with sprites or player skins
2014-03-15 16:59:03 +00:00
// 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
2016-07-06 04:09: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
2018-08-07 20:20:27 +00:00
f = fopen ( va ( " %s " PATHSEP " %s " , srb2home , " kmd2.dat " ) , " rt " ) ;
2014-03-15 16:59:03 +00:00
if ( ! f )
{
2019-01-09 21:35:51 +00:00
f = fopen ( va ( " %s " PATHSEP " %s " , srb2path , " kmd2.dat " ) , " rt " ) ;
if ( ! f )
{
CONS_Printf ( " %s %s \n " , M_GetText ( " Error while loading kmd2.dat: " ) , strerror ( errno ) ) ;
nomd2s = true ;
return ;
}
2014-03-15 16:59:03 +00:00
}
// Check for any MD2s that match the names of player skins!
while ( fscanf ( f , " %19s %31s %f %f " , name , filename , & scale , & offset ) = = 4 )
{
2016-07-06 04:09:17 +00:00
if ( stricmp ( name , sprnames [ spritenum ] ) = = 0 )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09: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 ;
}
}
//CONS_Printf("MD2 for sprite %s not found\n", sprnames[spritenum]);
md2_models [ spritenum ] . notfound = true ;
spritemd2found :
fclose ( f ) ;
}
2018-09-17 03:28:10 +00:00
// Define for getting accurate color brightness readings according to how the human eye sees them.
// https://en.wikipedia.org/wiki/Relative_luminance
// 0.2126 to red
// 0.7152 to green
// 0.0722 to blue
// (See this same define in k_kart.c!)
# define SETBRIGHTNESS(brightness,r,g,b) \
brightness = ( UINT8 ) ( ( ( 1063 * ( ( UINT16 ) r ) / 5000 ) + ( 3576 * ( ( UINT16 ) g ) / 5000 ) + ( 361 * ( ( UINT16 ) b ) / 5000 ) ) / 3 )
2018-11-26 00:17:34 +00:00
2018-02-05 02:11:17 +00:00
static void HWR_CreateBlendedTexture ( GLPatch_t * gpatch , GLPatch_t * blendgpatch , GLMipmap_t * grmip , INT32 skinnum , skincolors_t color )
2016-07-06 04:09:17 +00:00
{
2018-07-04 23:06:45 +00:00
UINT8 i ;
2016-07-06 04:09:17 +00:00
UINT16 w = gpatch - > width , h = gpatch - > height ;
UINT32 size = w * h ;
RGBA_t * image , * blendimage , * cur , blendcolor ;
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 ;
2018-07-04 23:06:45 +00:00
// Average all of the translation's colors
2016-07-06 04:09:17 +00:00
{
2018-09-17 03:39:18 +00:00
const UINT8 div = 6 ;
const UINT8 start = 4 ;
UINT32 r , g , b ;
2018-07-04 23:06:45 +00:00
2018-09-17 03:39:18 +00:00
blendcolor = V_GetColor ( colortranslations [ color ] [ start ] ) ;
r = ( UINT32 ) ( blendcolor . s . red * blendcolor . s . red ) ;
g = ( UINT32 ) ( blendcolor . s . green * blendcolor . s . green ) ;
b = ( UINT32 ) ( blendcolor . s . blue * blendcolor . s . blue ) ;
2018-07-04 23:06:45 +00:00
2018-09-17 03:39:18 +00:00
for ( i = 1 ; i < div ; i + + )
2018-07-04 23:06:45 +00:00
{
2018-09-17 03:39:18 +00:00
RGBA_t nextcolor = V_GetColor ( colortranslations [ color ] [ start + i ] ) ;
r + = ( UINT32 ) ( nextcolor . s . red * nextcolor . s . red ) ;
g + = ( UINT32 ) ( nextcolor . s . green * nextcolor . s . green ) ;
b + = ( UINT32 ) ( nextcolor . s . blue * nextcolor . s . blue ) ;
2018-07-04 23:06:45 +00:00
}
2018-09-17 03:39:18 +00:00
blendcolor . s . red = ( UINT8 ) ( FixedSqrt ( ( r / div ) < < FRACBITS ) > > FRACBITS ) ;
blendcolor . s . green = ( UINT8 ) ( FixedSqrt ( ( g / div ) < < FRACBITS ) > > FRACBITS ) ;
blendcolor . s . blue = ( UINT8 ) ( FixedSqrt ( ( b / div ) < < FRACBITS ) > > FRACBITS ) ;
2016-07-06 04:09:17 +00:00
}
2018-06-08 04:02:28 +00:00
// rainbow support, could theoretically support boss ones too
if ( skinnum = = TC_RAINBOW )
2016-07-06 04:09:17 +00:00
{
2018-02-05 02:11:17 +00:00
while ( size - - )
2016-07-06 04:09:17 +00:00
{
2018-02-05 02:11:17 +00:00
if ( image - > s . alpha = = 0 & & 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
{
UINT32 tempcolor ;
UINT16 imagebright , blendbright , finalbright , colorbright ;
2018-09-17 03:28:10 +00:00
SETBRIGHTNESS ( imagebright , image - > s . red , image - > s . green , image - > s . blue ) ;
SETBRIGHTNESS ( blendbright , blendimage - > s . red , blendimage - > s . green , blendimage - > s . blue ) ;
2018-02-05 02:11:17 +00:00
// slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway
finalbright = ( imagebright * ( 255 - blendimage - > s . alpha ) ) / 255 + ( blendbright * blendimage - > s . alpha ) / 255 ;
2018-09-17 03:28:10 +00:00
SETBRIGHTNESS ( colorbright , blendcolor . s . red , blendcolor . s . green , blendcolor . s . blue ) ;
2018-02-05 02:11:17 +00:00
tempcolor = ( finalbright * blendcolor . s . red ) / colorbright ;
2018-07-06 23:34:03 +00:00
tempcolor = min ( 255 , tempcolor ) ;
2018-02-05 02:11:17 +00:00
cur - > s . red = ( UINT8 ) tempcolor ;
tempcolor = ( finalbright * blendcolor . s . green ) / colorbright ;
2018-07-06 23:34:03 +00:00
tempcolor = min ( 255 , tempcolor ) ;
2018-02-05 02:11:17 +00:00
cur - > s . green = ( UINT8 ) tempcolor ;
tempcolor = ( finalbright * blendcolor . s . blue ) / colorbright ;
2018-07-06 23:34:03 +00:00
tempcolor = min ( 255 , tempcolor ) ;
2018-02-05 02:11:17 +00:00
cur - > s . blue = ( UINT8 ) tempcolor ;
cur - > s . alpha = image - > s . alpha ;
}
cur + + ; image + + ; blendimage + + ;
2016-07-06 04:09:17 +00:00
}
2018-02-05 02:11:17 +00:00
}
else
{
while ( size - - )
2016-07-06 04:09:17 +00:00
{
2018-02-05 02:11:17 +00:00
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 ;
}
2016-07-06 04:09:17 +00:00
2018-02-05 02:11:17 +00:00
cur + + ; image + + ; blendimage + + ;
}
2016-07-06 04:09:17 +00:00
}
return ;
}
2018-09-17 03:28:10 +00:00
# undef SETBRIGHTNESS
2018-02-05 02:11:17 +00:00
static void HWR_GetBlendedTexture ( GLPatch_t * gpatch , GLPatch_t * blendgpatch , INT32 skinnum , const UINT8 * colormap , skincolors_t color )
2016-07-06 04:09:17 +00:00
{
// 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 )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
HWD . pfnSetTexture ( grmip ) ; // found the colormap, set it to the correct texture
Z_ChangeTag ( grmip - > grInfo . data , PU_HWRCACHE_UNLOCKED ) ;
return ;
2014-03-15 16:59:03 +00:00
}
}
}
2016-07-06 04:09:17 +00:00
// 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 ;
2018-02-05 02:11:17 +00:00
HWR_CreateBlendedTexture ( gpatch , blendgpatch , newmip , skinnum , color ) ;
2016-07-06 04:09:17 +00:00
HWD . pfnSetTexture ( newmip ) ;
2017-02-17 20:03:10 +00:00
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 ] ;
INT32 frame ;
FTransform p ;
md2_t * md2 ;
UINT8 color [ 4 ] ;
2016-07-06 04:09:17 +00:00
if ( ! cv_grmd2 . value )
return ;
if ( spr - > precip )
return ;
2014-03-15 16:59:03 +00:00
// MD2 colormap fix
// colormap test
2019-01-21 22:48:57 +00:00
if ( spr - > mobj - > subsector )
2014-03-15 16:59:03 +00:00
{
sector_t * sector = spr - > mobj - > subsector - > sector ;
2016-07-06 04:09: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 ) ;
}
2019-01-21 22:48:57 +00:00
else
{
Surf . FlatColor . rgba = 0xFFFFFFFF ;
}
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
// Look at HWR_ProjectSprite for more
2014-03-15 16:59:03 +00:00
{
GLPatch_t * gpatch ;
INT32 * buff ;
2017-10-30 19:12:51 +00:00
INT32 durs = spr - > mobj - > state - > tics ;
INT32 tics = spr - > mobj - > tics ;
2014-03-15 16:59:03 +00:00
md2_frame_t * curr , * next = NULL ;
const UINT8 flip = ( UINT8 ) ( ( spr - > mobj - > eflags & MFE_VERTICALFLIP ) = = MFE_VERTICALFLIP ) ;
spritedef_t * sprdef ;
spriteframe_t * sprframe ;
float finalscale ;
2014-04-17 10:57:10 +00:00
// Apparently people don't like jump frames like that, so back it goes
//if (tics > durs)
//durs = tics;
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,...
2019-01-08 17:57:10 +00:00
if ( spr - > mobj - > skin & & spr - > mobj - > sprite = = SPR_PLAY & & ! md2_playermodels [ ( skin_t * ) spr - > mobj - > skin - skins ] . notfound ) // 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 ;
}
2019-01-08 17:57:10 +00:00
else // if we can't find the player md2, use SPR_PLAY's MD2.
2014-03-15 16:59:03 +00:00
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 )
{
2019-01-08 17:57:10 +00:00
CONS_Debug ( DBG_RENDER , " Loading MD2... (%s, %s) " , sprnames [ spr - > mobj - > sprite ] , md2 - > filename ) ;
2014-03-15 16:59:03 +00:00
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
finalscale = md2 - > scale ;
//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...
2016-07-06 04:09:17 +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
{
2016-07-06 04:09:17 +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 )
{
2019-01-03 00:11:51 +00:00
INT32 skinnum = TC_DEFAULT ;
2018-02-05 02:11:17 +00:00
if ( ( spr - > mobj - > flags & MF_BOSS ) & & ( spr - > mobj - > flags2 & MF2_FRET ) & & ( leveltime & 1 ) ) // Bosses "flash"
{
if ( spr - > mobj - > type = = MT_CYBRAKDEMON )
skinnum = TC_ALLWHITE ;
else if ( spr - > mobj - > type = = MT_METALSONIC_BATTLE )
skinnum = TC_METALSONIC ;
else
skinnum = TC_BOSS ;
}
else if ( spr - > mobj - > color )
{
if ( spr - > mobj - > skin & & spr - > mobj - > sprite = = SPR_PLAY )
{
if ( spr - > mobj - > colorized )
2018-06-08 04:02:28 +00:00
skinnum = TC_RAINBOW ;
2018-02-05 02:11:17 +00:00
else
{
skinnum = ( INT32 ) ( ( skin_t * ) spr - > mobj - > skin - skins ) ;
}
}
else skinnum = TC_DEFAULT ;
}
HWR_GetBlendedTexture ( gpatch , ( GLPatch_t * ) md2 - > blendgrpatch , skinnum , spr - > colormap , ( skincolors_t ) spr - > mobj - > color ) ;
2016-07-06 04:09:17 +00:00
}
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 ) ;
}
2016-07-06 04:09:17 +00:00
if ( spr - > mobj - > frame & FF_ANIMATE )
{
// set duration and tics to be the correct values for FF_ANIMATE states
durs = spr - > mobj - > state - > var2 ;
tics = spr - > mobj - > anim_duration ;
}
2014-03-15 16:59:03 +00:00
//FIXME: this is not yet correct
frame = ( spr - > mobj - > frame & FF_FRAMEMASK ) % md2 - > model - > header . numFrames ;
buff = md2 - > model - > glCommandBuffer ;
curr = & md2 - > model - > frames [ frame ] ;
2018-10-27 20:16:19 +00:00
#if 0
2018-02-06 19:50:08 +00:00
if ( cv_grmd2 . value = = 1 & & tics < = durs )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
// frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation
if ( spr - > mobj - > frame & FF_ANIMATE )
{
UINT32 nextframe = ( spr - > mobj - > frame & FF_FRAMEMASK ) + 1 ;
if ( nextframe > = ( UINT32 ) spr - > mobj - > state - > var1 )
nextframe = ( spr - > mobj - > state - > frame & FF_FRAMEMASK ) ;
nextframe % = md2 - > model - > header . numFrames ;
next = & md2 - > model - > frames [ nextframe ] ;
}
else
{
2017-11-04 17:32:47 +00:00
if ( spr - > mobj - > state - > nextstate ! = S_NULL & & states [ spr - > mobj - > state - > nextstate ] . sprite ! = SPR_NULL )
2016-07-06 04:09:17 +00:00
{
const UINT32 nextframe = ( states [ spr - > mobj - > state - > nextstate ] . frame & FF_FRAMEMASK ) % md2 - > model - > header . numFrames ;
next = & md2 - > model - > frames [ nextframe ] ;
}
}
2014-03-15 16:59:03 +00:00
}
2018-10-27 20:16:19 +00:00
# endif
2014-03-15 16:59:03 +00:00
//Hurdler: it seems there is still a small problem with mobj angle
p . x = FIXED_TO_FLOAT ( spr - > mobj - > x ) ;
p . y = FIXED_TO_FLOAT ( spr - > mobj - > y ) + md2 - > offset ;
if ( spr - > mobj - > eflags & MFE_VERTICALFLIP )
p . z = FIXED_TO_FLOAT ( spr - > mobj - > z + spr - > mobj - > height ) ;
else
p . z = FIXED_TO_FLOAT ( spr - > mobj - > z ) ;
2014-09-09 23:22:39 +00:00
if ( spr - > mobj - > skin & & spr - > mobj - > sprite = = SPR_PLAY )
2014-03-15 16:59:03 +00:00
sprdef = & ( ( skin_t * ) spr - > mobj - > skin ) - > spritedef ;
else
sprdef = & sprites [ spr - > mobj - > sprite ] ;
sprframe = & sprdef - > spriteframes [ spr - > mobj - > frame & FF_FRAMEMASK ] ;
if ( sprframe - > rotate )
{
2017-11-04 14:07:53 +00:00
fixed_t anglef ;
if ( spr - > mobj - > player )
anglef = AngleFixed ( spr - > mobj - > player - > frameangle ) ;
else
anglef = AngleFixed ( spr - > mobj - > angle ) ;
2014-03-15 16:59:03 +00:00
p . angley = FIXED_TO_FLOAT ( anglef ) ;
}
else
{
const fixed_t anglef = AngleFixed ( ( R_PointToAngle ( spr - > mobj - > x , spr - > mobj - > y ) ) - ANGLE_180 ) ;
p . angley = FIXED_TO_FLOAT ( anglef ) ;
}
p . anglex = 0.0f ;
2018-11-26 00:17:34 +00:00
p . anglez = 0.0f ;
if ( spr - > mobj - > standingslope )
{
fixed_t tempz = spr - > mobj - > standingslope - > normal . z ;
fixed_t tempy = spr - > mobj - > standingslope - > normal . y ;
fixed_t tempx = spr - > mobj - > standingslope - > normal . x ;
fixed_t tempangle = AngleFixed ( R_PointToAngle2 ( 0 , 0 , FixedSqrt ( FixedMul ( tempy , tempy ) + FixedMul ( tempz , tempz ) ) , tempx ) ) ;
p . anglez = FIXED_TO_FLOAT ( tempangle ) ;
tempangle = - AngleFixed ( R_PointToAngle2 ( 0 , 0 , tempz , tempy ) ) ;
p . anglex = FIXED_TO_FLOAT ( tempangle ) ;
}
2014-03-15 16:59:03 +00:00
color [ 0 ] = Surf . FlatColor . s . red ;
color [ 1 ] = Surf . FlatColor . s . green ;
color [ 2 ] = Surf . FlatColor . s . blue ;
color [ 3 ] = Surf . FlatColor . s . alpha ;
// SRB2CBTODO: MD2 scaling support
finalscale * = FIXED_TO_FLOAT ( spr - > mobj - > scale ) ;
2016-07-06 04:09:17 +00:00
p . flip = atransform . flip ;
2017-12-29 19:50:16 +00:00
p . mirror = atransform . mirror ;
2014-04-07 16:08:04 +00:00
2014-03-15 16:59:03 +00:00
HWD . pfnDrawMD2i ( buff , curr , durs , tics , next , & p , finalscale , flip , color ) ;
}
}
# endif //HWRENDER