This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/client/r_util.cpp

819 lines
20 KiB
C++

/***
*
* Copyright (c) 2001-2006, Chain Studios. All rights reserved.
*
* This product contains software technology that is a part of Half-Life FX (R)
* from Chain Studios ("HLFX Technology"). All rights reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Chain Studios.
*
****/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "hud.h"
#include "r_main.h"
#include "r_util.h"
#include <string.h>
vec3_t vec3_origin( 0, 0, 0 );
double sqrt(double x);
HSPRITE m_hHudFont;
int *GetRect( void )
{
RECT wrect;
static int extent[4];
if(GetWindowRect( GetActiveWindow(), &wrect ))
{
if(!wrect.left)
{
extent[0] = wrect.left; //+4
extent[1] = wrect.top; //+30
extent[2] = wrect.right; //-4
extent[3] = wrect.bottom; //-4
}
else
{
extent[0] = wrect.left + 4; //+4
extent[1] = wrect.top + 30; //+30
extent[2] = wrect.right - 4; //-4
extent[3] = wrect.bottom - 4; //-4
}
}
return extent;
}
void ScaleColors( int &r, int &g, int &b, int a )
{
float x = (float)a / 255;
r = (int)(r * x);
g = (int)(g * x);
b = (int)(b * x);
}
unsigned int nextpow2(unsigned int x)
{
unsigned int y = 1;
while (x > y) y = y << 1;
return y;
}
float Length(const float *v)
{
int i;
float length;
length = 0;
for (i=0 ; i< 3 ; i++)
length += v[i]*v[i];
length = sqrt (length); // FIXME
return length;
}
float Distance(const vec3_t v1, const vec3_t v2)
{
vec3_t d;
VectorSubtract(v2,v1,d);
return Length(d);
}
void VectorAngles( const float *forward, float *angles )
{
float tmp, yaw, pitch;
if (forward[1] == 0 && forward[0] == 0)
{
yaw = 0;
if (forward[2] > 0)
pitch = 90;
else
pitch = 270;
}
else
{
yaw = (atan2(forward[1], forward[0]) * 180 / M_PI);
if (yaw < 0)
yaw += 360;
tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]);
pitch = (atan2(forward[2], tmp) * 180 / M_PI);
if (pitch < 0)
pitch += 360;
}
angles[0] = pitch;
angles[1] = yaw;
angles[2] = 0;
}
float VectorNormalize (float *v)
{
float length, ilength;
length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
length = sqrt (length); // FIXME
if (length)
{
ilength = 1/length;
v[0] *= ilength;
v[1] *= ilength;
v[2] *= ilength;
}
return length;
}
void VectorInverse ( float *v )
{
v[0] = -v[0];
v[1] = -v[1];
v[2] = -v[2];
}
void VectorScale (const float *in, float scale, float *out)
{
out[0] = in[0]*scale;
out[1] = in[1]*scale;
out[2] = in[2]*scale;
}
void VectorMA (const float *veca, float scale, const float *vecb, float *vecc)
{
vecc[0] = veca[0] + scale*vecb[0];
vecc[1] = veca[1] + scale*vecb[1];
vecc[2] = veca[2] + scale*vecb[2];
}
HSPRITE LoadSprite(const char *pszName)
{
int i;
char sz[256];
if (ScreenWidth < 640)
i = 320;
else
i = 640;
sprintf(sz, pszName, i);
return SPR_Load(sz);
}
float TransformColor ( float color )
{
float trns_clr;
if(color >= 0 ) trns_clr = color / 255.0f;
else trns_clr = 1.0;//default value
return trns_clr;
}
#define NOISE_SIZE 64
inline float fade ( float t )
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
inline float lerp ( float t, float a, float b )
{
return a + t * (b - a);
}
inline float grad ( int hash, float x, float y, float z )
{
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
float u = h<8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.
v = h<4 ? y : h==12 || h==14 ? x : z;
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
}
int permutation [256] =
{
151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
int p[512];
void InitImprovedNoise()
{
for ( int i = 0; i < 256; i++ )
p [ 256 + i ] = p [ i ] = permutation [i];
}
float noise( float vx, float vy, float vz )
{
float fx = floor ( vx ); // get floor values of coords
float fy = floor ( vy );
float fz = floor ( vz );
int X = ((int) fx) & 255, // FIND UNIT CUBE THAT
Y = ((int) fy) & 255, // CONTAINS POINT.
Z = ((int) fz) & 255;
float x = vx - fx; // FIND RELATIVE X,Y,Z
float y = vy - fy; // OF POINT IN CUBE.
float z = vz - fz;
float u = fade ( x ), // COMPUTE FADE CURVES
v = fade ( y ), // FOR EACH OF X,Y,Z.
w = fade ( z );
int a = p [X ]+Y, aa = p [a]+Z, ab = p [a+1]+Z, // HASH COORDINATES OF
b = p [X+1]+Y, ba = p [b]+Z, bb = p [b+1]+Z; // THE 8 CUBE CORNERS,
return lerp(w, lerp(v, lerp(u, grad(p[aa ], x , y , z ), // AND ADD
grad(p[ba ], x-1, y , z )), // BLENDED
lerp(u, grad(p[ab ], x , y-1, z ), // RESULTS
grad(p[bb ], x-1, y-1, z ))),// FROM 8
lerp(v, lerp(u, grad(p[aa+1], x , y , z-1 ), // CORNERS
grad(p[ba+1], x-1, y , z-1 )), // OF CUBE
lerp(u, grad(p[ab+1], x , y-1, z-1 ),
grad(p[bb+1], x-1, y-1, z-1 ))));
}
void CreateNoiseTexture3D (float scale)
{
int i;
GLfloat *img = new GLfloat[NOISE_SIZE * NOISE_SIZE * NOISE_SIZE * 3];
GLfloat *p = img;
InitImprovedNoise();
for (i=0; i < NOISE_SIZE*NOISE_SIZE*NOISE_SIZE*3 ; i++)
{
float x = i + sin(i);
float y = i + cos(i);
*p++ = noise(x, y, i);
}
g_uiNoiseTex = pTexId++;
glBindTexture(GL_TEXTURE_3D, g_uiNoiseTex);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage3DEXT(GL_TEXTURE_3D, 0, 3, NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, 0,
GL_RGB, GL_FLOAT, img);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT );
delete [] img;
}
//
// R_SphereInFrustum
//
// Purpose: sphere visibility test
//
extern float frustumPlanes[6][4];
float R_SphereInFrustum( vec3_t o, float radius )
{
int p;
float d;
for( p = 0; p < 6; p++ )
{
d = frustumPlanes[p][0] * o[0] + frustumPlanes[p][1] * o[1] + frustumPlanes[p][2] * o[2] + frustumPlanes[p][3];
if( d <= -radius )
return 0;
}
return d + radius;
}
//
// UTIL_GetClientEntityWithServerIndex
//
// Purpose: searches for the server entity on client
// Assumes: colormap has server entity index
//
cl_entity_t *UTIL_GetClientEntityWithServerIndex( int sv_index )
{
cl_entity_t *e;
for (int ic=1;ic<MAX_EDICTS;ic++)
{
e = gEngfuncs.GetEntityByIndex( ic );
if (!e)
break;
if (!e->model)
continue;
if (e->curstate.colormap == sv_index)
return e;
}
return NULL;
}
/*
====================
AngleMatrix
====================
*/
void AngleMatrix (const float *angles, float (*matrix)[4] )
{
float angle;
float sr, sp, sy, cr, cp, cy;
angle = angles[YAW] * (M_PI*2 / 360);
sy = sin(angle);
cy = cos(angle);
angle = angles[PITCH] * (M_PI*2 / 360);
sp = sin(angle);
cp = cos(angle);
angle = angles[ROLL] * (M_PI*2 / 360);
sr = sin(angle);
cr = cos(angle);
// matrix = (YAW * PITCH) * ROLL
matrix[0][0] = cp*cy;
matrix[1][0] = cp*sy;
matrix[2][0] = -sp;
matrix[0][1] = sr*sp*cy+cr*-sy;
matrix[1][1] = sr*sp*sy+cr*cy;
matrix[2][1] = sr*cp;
matrix[0][2] = (cr*sp*cy+-sr*-sy);
matrix[1][2] = (cr*sp*sy+-sr*cy);
matrix[2][2] = cr*cp;
matrix[0][3] = 0.0;
matrix[1][3] = 0.0;
matrix[2][3] = 0.0;
}
/*
====================
VectorCompare
====================
*/
int VectorCompare (const float *v1, const float *v2)
{
int i;
for (i=0 ; i<3 ; i++)
if (v1[i] != v2[i]) return 0;
return 1;
}
/*
====================
CrossProduct
====================
*/
void CrossProduct (const float *v1, const float *v2, float *cross)
{
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
/*
====================
VectorTransform
====================
*/
void VectorTransform (const float *in1, float in2[3][4], float *out)
{
out[0] = DotProduct(in1, in2[0]) + in2[0][3];
out[1] = DotProduct(in1, in2[1]) + in2[1][3];
out[2] = DotProduct(in1, in2[2]) + in2[2][3];
}
/*
================
ConcatTransforms
================
*/
void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
{
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
in1[0][2] * in2[2][2];
out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
in1[0][2] * in2[2][3] + in1[0][3];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
in1[1][2] * in2[2][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
in1[1][2] * in2[2][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
in1[1][2] * in2[2][2];
out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
in1[1][2] * in2[2][3] + in1[1][3];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
in1[2][2] * in2[2][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
in1[2][2] * in2[2][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
in1[2][2] * in2[2][3] + in1[2][3];
}
// angles index are not the same as ROLL, PITCH, YAW
/*
====================
AngleQuaternion
====================
*/
void AngleQuaternion( float *angles, vec4_t quaternion )
{
float angle;
float sr, sp, sy, cr, cp, cy;
// FIXME: rescale the inputs to 1/2 angle
angle = angles[2] * 0.5;
sy = sin(angle);
cy = cos(angle);
angle = angles[1] * 0.5;
sp = sin(angle);
cp = cos(angle);
angle = angles[0] * 0.5;
sr = sin(angle);
cr = cos(angle);
quaternion[0] = sr*cp*cy-cr*sp*sy; // X
quaternion[1] = cr*sp*cy+sr*cp*sy; // Y
quaternion[2] = cr*cp*sy-sr*sp*cy; // Z
quaternion[3] = cr*cp*cy+sr*sp*sy; // W
}
/*
====================
QuaternionSlerp
====================
*/
void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt )
{
int i;
float omega, cosom, sinom, sclp, sclq;
// decide if one of the quaternions is backwards
float a = 0;
float b = 0;
for (i = 0; i < 4; i++)
{
a += (p[i]-q[i])*(p[i]-q[i]);
b += (p[i]+q[i])*(p[i]+q[i]);
}
if (a > b)
{
for (i = 0; i < 4; i++)
{
q[i] = -q[i];
}
}
cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];
if ((1.0 + cosom) > 0.000001)
{
if ((1.0 - cosom) > 0.000001)
{
omega = acos( cosom );
sinom = sin( omega );
sclp = sin( (1.0 - t)*omega) / sinom;
sclq = sin( t*omega ) / sinom;
}
else
{
sclp = 1.0 - t;
sclq = t;
}
for (i = 0; i < 4; i++) {
qt[i] = sclp * p[i] + sclq * q[i];
}
}
else
{
qt[0] = -q[1];
qt[1] = q[0];
qt[2] = -q[3];
qt[3] = q[2];
sclp = sin( (1.0 - t) * (0.5 * M_PI));
sclq = sin( t * (0.5 * M_PI));
for (i = 0; i < 3; i++)
{
qt[i] = sclp * p[i] + sclq * qt[i];
}
}
}
/*
====================
QuaternionMatrix
====================
*/
void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] )
{
matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2];
matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2];
matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1];
matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2];
matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2];
matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0];
matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1];
matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0];
matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1];
}
/*
====================
MatrixCopy
====================
*/
void MatrixCopy( float in[3][4], float out[3][4] )
{
memcpy( out, in, sizeof( float ) * 3 * 4 );
}
/*
====================
VectorIRotate
====================
*/
void VectorIRotate (const vec3_t in1, const float in2[3][4], vec3_t out)
{
out[0] = in1[0]*in2[0][0] + in1[1]*in2[1][0] + in1[2]*in2[2][0];
out[1] = in1[0]*in2[0][1] + in1[1]*in2[1][1] + in1[2]*in2[2][1];
out[2] = in1[0]*in2[0][2] + in1[1]*in2[1][2] + in1[2]*in2[2][2];
}
/*
====================
VectorRotateByMatrix
VectorTransformByMatrix
====================
*/
void VectorRotateByMatrix (const vec3_t &in1, const float *in2, vec3_t &out)
{
out[0] = in1[0]*in2[0] + in1[1]*in2[4] + in1[2]*in2[8];
out[1] = in1[0]*in2[1] + in1[1]*in2[5] + in1[2]*in2[9];
out[2] = in1[0]*in2[2] + in1[1]*in2[6] + in1[2]*in2[10];
}
void VectorTransformByMatrix (const vec3_t &in1, const float *in2, vec3_t &out)
{
out[0] = in1[0]*in2[0] + in1[1]*in2[4] + in1[2]*in2[8] + in2[12];
out[1] = in1[0]*in2[1] + in1[1]*in2[5] + in1[2]*in2[9] + in2[13];
out[2] = in1[0]*in2[2] + in1[1]*in2[6] + in1[2]*in2[10] + in2[14];
}
void VectorRotateByMatrix (const float *in1, const float *in2, float *out)
{
out[0] = in1[0]*in2[0] + in1[1]*in2[4] + in1[2]*in2[8];
out[1] = in1[0]*in2[1] + in1[1]*in2[5] + in1[2]*in2[9];
out[2] = in1[0]*in2[2] + in1[1]*in2[6] + in1[2]*in2[10];
}
void VectorTransformByMatrix (const float *in1, const float *in2, float *out)
{
out[0] = in1[0]*in2[0] + in1[1]*in2[4] + in1[2]*in2[8] + in2[12];
out[1] = in1[0]*in2[1] + in1[1]*in2[5] + in1[2]*in2[9] + in2[13];
out[2] = in1[0]*in2[2] + in1[1]*in2[6] + in1[2]*in2[10] + in2[14];
}
/*
====================
ObjectToWorldMatrix
====================
*/
void ObjectToWorldMatrix(cl_entity_t *e, float *result)
{
glPushMatrix();
glLoadIdentity();
glTranslatef(e->origin[0], e->origin[1], e->origin[2]);
glRotatef ( e->angles[1], 0, 0, 1);
glRotatef ( e->angles[0], 0, 1, 0);
glRotatef ( e->angles[2], 1, 0, 0);
glGetFloatv (GL_MODELVIEW_MATRIX, result);
glPopMatrix();
}
/*
====================
SPRITE_GetList
====================
*/
char *ParseHudSprite( char *pfile, char *psz, client_sprite_t *result )
{
char token[256];
client_sprite_t *p = new client_sprite_t;
int x = 0, y = 0, width = 0, height = 0;
int section = 0;
memset( p, 0, sizeof(client_sprite_t) );
while( pfile )
{
pfile = gEngfuncs.COM_ParseFile( pfile, token );
if( !stricmp( token, psz ))
{
pfile = gEngfuncs.COM_ParseFile( pfile, token );
if( !stricmp( token, "{" )) section = 1;
}
if(section)//parse section
{
if( !stricmp( token, "}" )) break;//end section
if ( !stricmp( token, "file" ))
{
pfile = gEngfuncs.COM_ParseFile(pfile, token);
strcpy(p->szSprite, token );
if( !gEngfuncs.COM_LoadFile( p->szSprite, 5, NULL )) return pfile;
else
{
gEngfuncs.COM_FreeFile( p->szSprite);
//fill structure at default
HSPRITE m_hSprite = SPR_Load(p->szSprite);
x = y = 0;
width = SPR_Width( m_hSprite, 0 );
height = SPR_Height( m_hSprite, 0 );
}
}
else if ( !stricmp( token, "name" ))
{
pfile = gEngfuncs.COM_ParseFile(pfile, token);
strcpy(p->szName, token );
}
else if ( !stricmp( token, "x" ))
{
pfile = gEngfuncs.COM_ParseFile(pfile, token);
x = atoi(token);
}
else if ( !stricmp( token, "y" ))
{
pfile = gEngfuncs.COM_ParseFile(pfile, token);
y = atoi(token);
}
else if ( !stricmp( token, "width" ))
{
pfile = gEngfuncs.COM_ParseFile(pfile, token);
width = atoi(token);
}
else if ( !stricmp( token, "height" ))
{
pfile = gEngfuncs.COM_ParseFile(pfile, token);
height = atoi(token);
}
}
}
if(!section) return pfile;//data not found
//calculate sprite position
p->rc.left = x;
p->rc.right = x + width;
p->rc.top = y;
p->rc.bottom = y + height;
//write resolution for backward compatibility
if (ScreenWidth < 640) p->iRes = 320;
else p->iRes = 640;
memcpy( result, p, sizeof(client_sprite_t));
return pfile;
}
client_sprite_t *SPR_GetList( char *psz, int *piCount )
{
int iSprCount = 0;
char *pfile = (char *)gEngfuncs.COM_LoadFile( psz, 5, NULL);
if (!pfile)
{
*piCount = iSprCount;
return NULL;
}
char token[256];
char *plist = pfile;
while ( pfile ) //calculate count of sprites
{
pfile = gEngfuncs.COM_ParseFile(pfile, token);
if ( !stricmp( token, "hudsprite" )) iSprCount++;
}
client_sprite_t *phud = new client_sprite_t[iSprCount];
for(int i = 0; i < iSprCount; i++ ) //parse structures
{
plist = ParseHudSprite( plist, "hudsprite", &phud[i] );
}
if(!iSprCount)Msg("SPR_GetList: %s don't have sprites\n", psz );
gEngfuncs.COM_FreeFile( pfile );
*piCount = iSprCount;
return phud;
}
/*
====================
Sys LoadGameDLL
====================
*/
bool Sys_LoadLibrary (const char* dllname, dllhandle_t* handle, const dllfunction_t *fcts)
{
const dllfunction_t *gamefunc;
char dllpath[128];
dllhandle_t dllhandle = 0;
if (handle == NULL) return false;
// Initializations
for (gamefunc = fcts; gamefunc && gamefunc->name != NULL; gamefunc++)
*gamefunc->funcvariable = NULL;
// Try every possible name
sprintf(dllpath, "%s/cl_dlls/%s", gEngfuncs.pfnGetGameDirectory(), dllname);
dllhandle = LoadLibrary (dllpath);
// No DLL found
if (! dllhandle) return false;
// Get the function adresses
for (gamefunc = fcts; gamefunc && gamefunc->name != NULL; gamefunc++)
if (!(*gamefunc->funcvariable = (void *) Sys_GetProcAddress (dllhandle, gamefunc->name)))
{
Sys_UnloadLibrary (&dllhandle);
return false;
}
Msg("%s loaded succesfully!\n", dllname);
*handle = dllhandle;
return true;
}
void Sys_UnloadLibrary (dllhandle_t* handle)
{
if (handle == NULL || *handle == NULL)
return;
FreeLibrary (*handle);
*handle = NULL;
}
void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
{
return (void *)GetProcAddress (handle, name);
}