Paranoia2_original/utils/hlsv/GlWindow.cpp

535 lines
14 KiB
C++

//
// MD2 Viewer (c) 1999 by Mete Ciragan
//
// file: GlWindow.cpp
// last modified: Apr 29 1999, Mete Ciragan
// copyright: The programs and associated files contained in this
// distribution were developed by Mete Ciragan. The programs
// are not in the public domain, but they are freely
// distributable without licensing fees. These programs are
// provided without guarantee or warrantee expressed or
// implied.
//
// version: 1.4
//
// email: mete@swissquake.ch
// web: http://www.swissquake.ch/chumbalum-soft/
//
#include <mx.h>
#include <mxMessageBox.h>
#include <mxTga.h>
#include <mxPcx.h>
#include <mxBmp.h>
#include <gl.h>
#include <GL/glu.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stringlib.h>
#include "ViewerSettings.h"
#include "GlWindow.h"
#include "SpriteModel.h"
extern bool g_bStopPlaying;
extern bool bUseWeaponOrigin;
extern bool bUseWeaponLeftHand;
GlWindow *g_GlWindow = 0;
GlWindow::GlWindow( mxWindow *parent, int x, int y, int w, int h, const char *label, int style ) : mxGlWindow( parent, x, y, w, h, label, style )
{
d_textureNames[0] = 0;
d_textureNames[1] = 0;
d_textureNames[2] = 0;
setFrameInfo (0, 0);
setRenderMode (SPR_NORMAL);
setOrientType (SPR_FWD_PARALLEL);
d_pol = 0.0f;
glDepthFunc( GL_LEQUAL );
glCullFace (GL_FRONT);
mx::setIdleWindow (this);
}
GlWindow::~GlWindow ()
{
mx::setIdleWindow (0);
loadTexture (0, TEXTURE_BACKGROUND);
loadTexture (0, TEXTURE_GROUND);
loadSprite (0);
}
int GlWindow::handleEvent (mxEvent *event)
{
static float oldrx, oldry, oldtz, oldtx, oldty;
static int oldx, oldy;
static double lastupdate;
switch (event->event)
{
case mxEvent::MouseUp:
{
g_viewerSettings.pause = false;
}
break;
case mxEvent::MouseDown:
oldrx = g_viewerSettings.rot[0];
oldry = g_viewerSettings.rot[1];
oldtx = g_viewerSettings.trans[0];
oldty = g_viewerSettings.trans[1];
oldtz = g_viewerSettings.trans[2];
oldx = event->x;
oldy = event->y;
// HACKHACK: reset focus to main window to catch hot-keys again
if( g_SPRViewer ) SetFocus( (HWND) g_SPRViewer->getHandle ());
g_viewerSettings.pause = true;
break;
case mxEvent::MouseDrag:
if( event->buttons & mxEvent::MouseLeftButton )
{
if( event->modifiers & mxEvent::KeyShift )
{
g_viewerSettings.trans[0] = oldtx - (float)(event->x - oldx) * g_viewerSettings.movementScale;
g_viewerSettings.trans[1] = oldty + (float)(event->y - oldy) * g_viewerSettings.movementScale;
}
else
{
g_viewerSettings.rot[0] = oldrx + (float)(event->y - oldy);
g_viewerSettings.rot[1] = oldry + (float)(event->x - oldx);
}
}
else if( event->buttons & mxEvent::MouseRightButton )
{
g_viewerSettings.trans[2] = oldtz + (float)(event->y - oldy) * g_viewerSettings.movementScale;
}
redraw ();
break;
case mxEvent::Idle:
{
static double prev;
double curr = (double) mx::getTickCount () / 1000.0;
double dt = (curr - prev);
#if 1
// clamp to 100fps
if( dt >= 0.0 && dt < 0.01 )
{
Sleep( max( 10 - dt * 1000.0, 0 ) );
return 1;
}
#endif
g_spriteModel.updateTimings( curr, dt );
if( !g_bStopPlaying && !g_viewerSettings.pause && prev != 0.0 )
{
d_pol += (dt / 0.1) * g_viewerSettings.speedScale;
if( d_pol >= 1.0f )
{
if( d_startFrame == d_endFrame )
g_spriteModel.setFrame( d_startFrame );
else g_spriteModel.setFrame( d_currFrame++ );
d_pol = 0.0f;
if( d_currFrame > d_endFrame )
d_currFrame = d_startFrame;
}
}
if( !g_viewerSettings.pause )
redraw ();
prev = curr;
}
break;
case mxEvent::KeyDown:
switch (event->key)
{
case 27:
if( !getParent( )) // fullscreen mode ?
mx::quit();
break;
}
}
return 1;
}
void GlWindow :: setupRenderMode( void )
{
glDisable( GL_MULTISAMPLE );
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glShadeModel( GL_SMOOTH );
glEnable( GL_DEPTH_TEST );
glEnable( GL_TEXTURE_2D );
glEnable( GL_CULL_FACE );
glDisable( GL_BLEND );
glDisable( GL_ALPHA_TEST );
glDepthMask( GL_TRUE );
switch( g_viewerSettings.renderMode )
{
case SPR_NORMAL:
break;
case SPR_ADDITIVE:
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
glDepthMask( GL_FALSE );
break;
case SPR_INDEXALPHA:
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glDepthMask( GL_FALSE );
break;
case SPR_ALPHTEST:
#if 0
glEnable( GL_ALPHA_TEST );
glAlphaFunc( GL_GREATER, 0.25f );
#else
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glDepthMask( GL_FALSE );
#endif
break;
}
}
void GlWindow :: drawFloor( int texture )
{
float scale = 5.0f;
float dist = -100.0f;
glEnable( GL_MULTISAMPLE );
if( texture )
{
static Vector tMap( 0, 0, 0 );
static Vector dxMap( 1, 0, 0 );
static Vector dyMap( 0, 1, 0 );
vec3_t deltaPos;
g_spriteModel.GetMovement( deltaPos );
float dpdd = scale / dist;
tMap[0] = tMap[0] + dxMap[0] * deltaPos[0] * dpdd + dxMap[1] * deltaPos[1] * dpdd;
tMap[1] = tMap[1] + dyMap[0] * deltaPos[0] * dpdd + dyMap[1] * deltaPos[1] * dpdd;
while (tMap[0] < 0.0) tMap[0] += 1.0f;
while (tMap[0] > 1.0) tMap[0] += -1.0f;
while (tMap[1] < 0.0) tMap[1] += 1.0f;
while (tMap[1] > 1.0) tMap[1] += -1.0f;
glBegin( GL_QUADS );
glTexCoord2f( tMap[0] - (dxMap[0] - dyMap[0]) * scale, tMap[1] - (-dxMap[1] + dyMap[1]) * scale );
glVertex3f( -dist, -dist, 0 );
glTexCoord2f( tMap[0] + (dxMap[0] + dyMap[0]) * scale, tMap[1] + (-dxMap[1] - dyMap[1]) * scale );
glVertex3f( dist, -dist, 0 );
glTexCoord2f( tMap[0] + (dxMap[0] - dyMap[0]) * scale, tMap[1] + (-dxMap[1] + dyMap[1]) * scale );
glVertex3f( dist, dist, 0 );
glTexCoord2f( tMap[0] + (-dxMap[0] - dyMap[0]) * scale, tMap[1] + (dxMap[1] + dyMap[1]) * scale );
glVertex3f( -dist, dist, 0 );
glEnd();
}
else
{
glBegin( GL_QUADS );
glTexCoord2f( 0.0f, 1.0f );
glVertex3f( -dist, -dist, 0 );
glTexCoord2f( 1.0f, 1.0f );
glVertex3f( dist, -dist, 0 );
glTexCoord2f( 1.0f, 0.0f );
glVertex3f( dist, dist, 0 );
glTexCoord2f( 0.0f, 0.0f );
glVertex3f( -dist, dist, 0 );
glEnd();
}
glDisable( GL_MULTISAMPLE );
}
void GlWindow::draw ()
{
glClearColor( g_viewerSettings.bgColor[0], g_viewerSettings.bgColor[1], g_viewerSettings.bgColor[2], 0.0f );
glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
glViewport( 0, 0, w2(), h2() );
glDisable( GL_MULTISAMPLE );
//
// draw background
//
if( g_viewerSettings.showBackground && d_textureNames[TEXTURE_BACKGROUND] )
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f );
glMatrixMode( GL_MODELVIEW );
glPushMatrix ();
glLoadIdentity ();
glDisable( GL_CULL_FACE );
glEnable( GL_TEXTURE_2D );
glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glBindTexture( GL_TEXTURE_2D, d_textureNames[TEXTURE_BACKGROUND] );
glBegin( GL_TRIANGLE_STRIP );
glTexCoord2f( 0, 0 );
glVertex2f( 0, 0 );
glTexCoord2f( 1, 0 );
glVertex2f( 1, 0 );
glTexCoord2f( 0, 1 );
glVertex2f( 0, 1 );
glTexCoord2f( 1, 1 );
glVertex2f( 1, 1 );
glEnd();
glClear( GL_DEPTH_BUFFER_BIT );
glBindTexture( GL_TEXTURE_2D, 0 );
glPopMatrix ();
}
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (65.0f, (GLfloat) w () / (GLfloat) h (), 0.1f, 131072.0f );
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
if( bUseWeaponOrigin )
{
glRotatef( -90, 1, 0, 0 ); // put Z going up
glRotatef( 90, 0, 0, 1 ); // put Z going up
glTranslatef( 0.0f, 0.0f, 1.0f ); // shift back like in HL
}
else
{
glTranslatef (-g_viewerSettings.trans[0], -g_viewerSettings.trans[1], -g_viewerSettings.trans[2]);
glRotatef( g_viewerSettings.rot[0], 1, 0, 0 );
glRotatef( g_viewerSettings.rot[1], 0, 0, 1 );
}
setupRenderMode();
glCullFace( GL_FRONT );
g_spriteModel.DrawSprite();
//
// draw ground
//
if( g_viewerSettings.showGround && !bUseWeaponOrigin )
{
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glEnable( GL_DEPTH_TEST );
glEnable( GL_CULL_FACE );
glDisable( GL_CULL_FACE );
glEnable( GL_BLEND );
if( !d_textureNames[TEXTURE_GROUND] )
{
glDisable( GL_TEXTURE_2D );
glColor4f( g_viewerSettings.gColor[0], g_viewerSettings.gColor[1], g_viewerSettings.gColor[2], 0.7f );
glBindTexture( GL_TEXTURE_2D, 0 );
}
else
{
glEnable( GL_TEXTURE_2D );
glColor4f( 1.0f, 1.0f, 1.0f, 0.6f );
glBindTexture( GL_TEXTURE_2D, d_textureNames[TEXTURE_GROUND] );
}
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
drawFloor( d_textureNames[TEXTURE_GROUND] );
glDisable( GL_BLEND );
glEnable( GL_CULL_FACE );
}
glPopMatrix ();
}
int GlWindow :: loadSprite( const char *filename, bool centering )
{
g_spriteModel.FreeSprite ();
if( g_spriteModel.LoadSprite( filename ))
{
char str[256], basename[64];
if( centering )
g_spriteModel.centerView (false);
g_viewerSettings.speedScale = 1.0f;
mx_setcwd( mx_getpath( filename ));
COM_FileBase( filename, basename );
Q_snprintf( str, sizeof( str ), "%s - %s.spr", g_appTitle, basename );
g_SPRViewer->setLabel( str );
ListDirectory();
return 1;
}
return 0;
}
int GlWindow :: loadTextureImage( mxImage *image, int name )
{
if( image )
{
d_textureNames[name] = name;
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
if( image->bpp == 8 )
{
g_spriteModel.UploadTexture( (byte *)image->data, image->width, image->height, (byte *)image->palette, name );
}
else if( image->bpp == 24 )
{
glBindTexture( GL_TEXTURE_2D, d_textureNames[name] );
glHint( GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST );
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
glTexImage2D( GL_TEXTURE_2D, 0, 3, image->width, image->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
const char *extensions = (const char *)glGetString( GL_EXTENSIONS );
// check for anisotropy support
if( Q_strstr( extensions, "GL_EXT_texture_filter_anisotropic" ))
{
float anisotropy = 1.0f;
glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy );
}
}
else if( image->bpp == 32 )
{
glBindTexture( GL_TEXTURE_2D, d_textureNames[name] );
glHint( GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST );
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
glTexImage2D( GL_TEXTURE_2D, 0, 4, image->width, image->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->data );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
const char *extensions = (const char *)glGetString( GL_EXTENSIONS );
// check for anisotropy support
if( Q_strstr( extensions, "GL_EXT_texture_filter_anisotropic" ))
{
float anisotropy = 1.0f;
glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy );
}
}
delete image;
return name;
}
return TEXTURE_UNUSED;
}
int GlWindow :: loadTexture( const char *filename, int name )
{
if( !filename || !Q_strlen( filename ))
{
if( d_textureNames[name] )
{
glDeleteTextures( 1, (const GLuint *)&d_textureNames[name] );
d_textureNames[name] = TEXTURE_UNUSED;
if( name == TEXTURE_BACKGROUND )
strcpy( g_viewerSettings.backgroundTexFile, "" );
else if( name == TEXTURE_GROUND )
strcpy( g_viewerSettings.groundTexFile, "" );
}
return TEXTURE_UNUSED;
}
mxImage *image = NULL;
char ext[16];
strcpy( ext, mx_getextension( filename ));
if( !mx_strcasecmp( ext, ".tga" ))
image = mxTgaRead( filename );
else if( !mx_strcasecmp( ext, ".pcx" ))
image = mxPcxRead( filename );
else if( !mx_strcasecmp( ext, ".bmp" ))
image = mxBmpRead( filename );
if( image )
{
if( name == TEXTURE_BACKGROUND )
strcpy( g_viewerSettings.backgroundTexFile, filename );
else if( name == TEXTURE_GROUND )
strcpy( g_viewerSettings.groundTexFile, filename );
}
return loadTextureImage( image, name );
}
void GlWindow :: setRenderMode( int mode )
{
g_viewerSettings.renderMode = mode;
}
void GlWindow :: setOrientType( int mode )
{
g_viewerSettings.orientType = mode;
}
void GlWindow::setFrameInfo (int startFrame, int endFrame)
{
msprite_t *phdr = g_spriteModel.getSpriteHeader();
if (phdr)
{
d_startFrame = startFrame;
d_endFrame = endFrame;
if (d_startFrame >= phdr->numframes)
d_startFrame = phdr->numframes - 1;
else if (d_startFrame < 0)
d_startFrame = 0;
if (d_endFrame >= phdr->numframes)
d_endFrame = phdr->numframes - 1;
else if (d_endFrame < 0)
d_endFrame = 0;
d_currFrame = d_startFrame;
if (d_currFrame >= phdr->numframes)
d_currFrame = phdr->numframes - 1;
}
else
{
d_startFrame = d_endFrame = d_currFrame = 0;
}
d_pol = 0;
}