2007-01-15 12:09:25 -08:00
|
|
|
/*
|
|
|
|
This file is part of Warzone 2100.
|
|
|
|
Copyright (C) 1999-2004 Eidos Interactive
|
|
|
|
Copyright (C) 2005-2007 Warzone Resurrection Project
|
|
|
|
|
|
|
|
Warzone 2100 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.
|
|
|
|
|
|
|
|
Warzone 2100 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.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Warzone 2100; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
2007-06-28 10:47:08 -07:00
|
|
|
/*
|
|
|
|
* Screen.c
|
|
|
|
*
|
|
|
|
* Basic double buffered display using direct draw.
|
|
|
|
*
|
|
|
|
*/
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-04-11 07:21:45 -07:00
|
|
|
#include "lib/framework/frame.h"
|
|
|
|
|
2007-11-24 03:49:51 -08:00
|
|
|
#include <SDL.h>
|
|
|
|
#include <SDL_opengl.h>
|
2007-04-11 07:21:45 -07:00
|
|
|
#include <physfs.h>
|
2007-04-17 09:53:28 -07:00
|
|
|
#include <png.h>
|
2007-04-30 07:09:33 -07:00
|
|
|
#include "lib/ivis_common/png_util.h"
|
2007-05-01 13:34:54 -07:00
|
|
|
#include "lib/ivis_common/tex.h"
|
2007-04-17 09:53:28 -07:00
|
|
|
|
2006-06-02 12:34:58 -07:00
|
|
|
#include "lib/framework/frameint.h"
|
|
|
|
#include "lib/ivis_common/piestate.h"
|
2007-02-25 04:34:18 -08:00
|
|
|
#include "lib/ivis_common/pieblitfunc.h"
|
2007-06-28 10:47:08 -07:00
|
|
|
#include "screen.h"
|
|
|
|
|
|
|
|
/* The Current screen size and bit depth */
|
|
|
|
UDWORD screenWidth = 0;
|
|
|
|
UDWORD screenHeight = 0;
|
|
|
|
UDWORD screenDepth = 0;
|
|
|
|
|
2007-03-28 08:08:57 -07:00
|
|
|
/* global used to indicate preferred internal OpenGL format */
|
|
|
|
int wz_texture_compression;
|
|
|
|
|
2007-11-14 14:29:19 -08:00
|
|
|
static SDL_Surface *screen = NULL;
|
|
|
|
static BOOL bBackDrop = FALSE;
|
|
|
|
static char screendump_filename[PATH_MAX];
|
|
|
|
static BOOL screendump_required = FALSE;
|
|
|
|
static GLuint backDropTexture = ~0;
|
2006-12-31 10:19:19 -08:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
/* Initialise the double buffered display */
|
2006-11-03 17:11:26 -08:00
|
|
|
BOOL screenInitialise(
|
|
|
|
UDWORD width, // Display width
|
2007-06-28 10:47:08 -07:00
|
|
|
UDWORD height, // Display height
|
|
|
|
UDWORD bitDepth, // Display bit depth
|
2006-11-03 17:11:26 -08:00
|
|
|
BOOL fullScreen // Whether to start windowed
|
|
|
|
// or full screen
|
|
|
|
)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2006-11-03 17:11:26 -08:00
|
|
|
static int video_flags = 0;
|
2007-02-21 12:20:26 -08:00
|
|
|
int bpp = 0, value;
|
2006-11-03 17:11:26 -08:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
/* Store the screen information */
|
|
|
|
screenWidth = width;
|
|
|
|
screenHeight = height;
|
2006-11-03 17:11:26 -08:00
|
|
|
screenDepth = bitDepth;
|
|
|
|
|
|
|
|
// Calculate the common flags for windowed and fullscreen modes.
|
|
|
|
if (video_flags == 0) {
|
|
|
|
// Fetch the video info.
|
|
|
|
const SDL_VideoInfo* video_info = SDL_GetVideoInfo();
|
|
|
|
|
|
|
|
if (!video_info) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The flags to pass to SDL_SetVideoMode.
|
|
|
|
video_flags = SDL_OPENGL; // Enable OpenGL in SDL.
|
|
|
|
video_flags |= SDL_ANYFORMAT; // Don't emulate requested BPP if not available.
|
|
|
|
video_flags |= SDL_HWPALETTE; // Store the palette in hardware.
|
|
|
|
|
|
|
|
// This checks to see if surfaces can be stored in memory.
|
|
|
|
if (video_info->hw_available) {
|
|
|
|
video_flags |= SDL_HWSURFACE;
|
|
|
|
} else {
|
|
|
|
video_flags |= SDL_SWSURFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This checks if hardware blits can be done.
|
|
|
|
if (video_info->blit_hw) {
|
|
|
|
video_flags |= SDL_HWACCEL;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fullScreen) {
|
|
|
|
video_flags |= SDL_FULLSCREEN;
|
|
|
|
}
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2006-11-03 17:11:26 -08:00
|
|
|
// Set the double buffer OpenGL attribute.
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
|
|
|
|
|
|
bpp = SDL_VideoModeOK(width, height, bitDepth, video_flags);
|
|
|
|
if (!bpp) {
|
|
|
|
debug( LOG_ERROR, "Error: Video mode %dx%d@%dbpp is not supported!\n", width, height, bitDepth );
|
2007-06-28 10:47:08 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
2006-11-03 17:11:26 -08:00
|
|
|
switch ( bpp )
|
|
|
|
{
|
|
|
|
case 32:
|
|
|
|
case 24:
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8 );
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
debug( LOG_ERROR, "Warning: Using colour depth of %i instead of %i.", bpp, screenDepth );
|
|
|
|
debug( LOG_ERROR, " You will experience graphics glitches!" );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 6 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8 );
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
debug( LOG_ERROR, "Error: You don't want to play Warzone with a bit depth of %i, do you?", bpp );
|
|
|
|
exit( 1 );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
debug( LOG_ERROR, "Error: Unsupported bit depth: %i", bpp );
|
|
|
|
exit( 1 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
screen = SDL_SetVideoMode(width, height, bpp, video_flags);
|
2007-02-21 12:20:26 -08:00
|
|
|
if ( !screen ) {
|
|
|
|
debug( LOG_ERROR, "Error: SDL_SetVideoMode failed (%s).", SDL_GetError() );
|
2006-11-03 17:11:26 -08:00
|
|
|
return FALSE;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
2007-03-16 09:20:16 -07:00
|
|
|
if ( SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &value) == -1)
|
2007-02-21 12:20:26 -08:00
|
|
|
{
|
|
|
|
debug( LOG_ERROR, "OpenGL initialization did not give double buffering!" );
|
|
|
|
}
|
2007-10-27 06:58:01 -07:00
|
|
|
debug(LOG_3D, "OpenGL extensions supported:");
|
|
|
|
if (check_extension("GL_ARB_texture_compression"))
|
|
|
|
{
|
|
|
|
debug(LOG_3D, " * Texture compression supported.");
|
|
|
|
}
|
|
|
|
if (check_extension("GL_EXT_stencil_two_side"))
|
|
|
|
{
|
|
|
|
debug(LOG_3D, " * Two side stencil supported.");
|
|
|
|
}
|
|
|
|
if (check_extension("GL_EXT_stencil_wrap"))
|
|
|
|
{
|
|
|
|
debug(LOG_3D, " * Stencil wrap supported.");
|
|
|
|
}
|
|
|
|
if (check_extension("GL_EXT_texture_filter_anisotropic"))
|
|
|
|
{
|
|
|
|
debug(LOG_3D, " * Anisotropic filtering supported.");
|
|
|
|
}
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
glViewport(0, 0, width, height);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPushMatrix();
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, width, height, 0, 1, -1);
|
2007-05-01 13:34:54 -07:00
|
|
|
|
2007-07-30 13:20:06 -07:00
|
|
|
glMatrixMode(GL_TEXTURE);
|
2007-11-09 09:43:50 -08:00
|
|
|
glScalef(1.0f/OLD_TEXTURE_SIZE_FIX, 1.0f/OLD_TEXTURE_SIZE_FIX, 1.0f); // FIXME Scaling texture coords to 256x256!
|
2007-07-30 13:20:06 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glCullFace(GL_FRONT);
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Release the DD objects */
|
|
|
|
void screenShutDown(void)
|
|
|
|
{
|
|
|
|
if (screen != NULL)
|
|
|
|
{
|
|
|
|
SDL_FreeSurface(screen);
|
2007-11-14 14:29:19 -08:00
|
|
|
screen = NULL;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-16 12:22:01 -07:00
|
|
|
void screen_SetBackDropFromFile(const char* filename)
|
2006-12-31 10:19:19 -08:00
|
|
|
{
|
2007-02-20 16:10:03 -08:00
|
|
|
// HACK : We should use a resource handler here!
|
2007-04-16 12:22:01 -07:00
|
|
|
const char *extension = strrchr(filename, '.');// determine the filetype
|
2007-05-01 13:34:54 -07:00
|
|
|
iV_Image image;
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-02-20 16:10:03 -08:00
|
|
|
if(!extension)
|
2007-02-07 07:27:17 -08:00
|
|
|
{
|
2007-02-20 16:10:03 -08:00
|
|
|
debug(LOG_ERROR, "Image without extension: \"%s\"!", filename);
|
|
|
|
return; // filename without extension... don't bother
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure the current texture page is reloaded after we are finished
|
|
|
|
// Otherwise WZ will think it is still loaded and not load it again
|
|
|
|
pie_SetTexturePage(-1);
|
2007-02-10 06:34:12 -08:00
|
|
|
|
2007-04-17 11:24:31 -07:00
|
|
|
if( strcmp(extension,".png") == 0 )
|
2007-02-10 06:34:12 -08:00
|
|
|
{
|
2007-05-01 13:34:54 -07:00
|
|
|
if (iV_loadImage_PNG( filename, &image ) )
|
2007-02-20 16:10:03 -08:00
|
|
|
{
|
|
|
|
if (~backDropTexture == 0)
|
|
|
|
glGenTextures(1, &backDropTexture);
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, backDropTexture);
|
2007-06-02 16:01:29 -07:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
|
2007-05-01 13:34:54 -07:00
|
|
|
image.width, image.height,
|
|
|
|
0, iV_getPixelFormat(&image), GL_UNSIGNED_BYTE, image.bmp);
|
2007-02-20 16:10:03 -08:00
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
|
|
|
2007-05-01 13:34:54 -07:00
|
|
|
iV_unloadImage(&image);
|
2007-02-20 16:10:03 -08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2007-02-10 06:34:12 -08:00
|
|
|
else
|
2007-02-20 16:10:03 -08:00
|
|
|
debug(LOG_ERROR, "Unknown extension \"%s\" for image \"%s\"!", extension, filename);
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
//===================================================================
|
|
|
|
|
|
|
|
void screen_StopBackDrop(void)
|
|
|
|
{
|
|
|
|
bBackDrop = FALSE; //checking [movie]
|
|
|
|
}
|
|
|
|
|
|
|
|
void screen_RestartBackDrop(void)
|
|
|
|
{
|
|
|
|
bBackDrop = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL screen_GetBackDrop(void)
|
|
|
|
{
|
|
|
|
return bBackDrop;
|
|
|
|
}
|
2007-11-14 14:29:19 -08:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
//******************************************************************
|
|
|
|
//slight hack to display maps (or whatever) in background.
|
2007-02-25 04:57:04 -08:00
|
|
|
//bitmap MUST be (BACKDROP_HACK_WIDTH * BACKDROP_HACK_HEIGHT) for now.
|
2007-04-16 12:22:01 -07:00
|
|
|
void screen_Upload(const char *newBackDropBmp)
|
2006-06-02 12:34:58 -07:00
|
|
|
{
|
2007-02-07 07:27:17 -08:00
|
|
|
if(newBackDropBmp != NULL)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-02-07 07:27:17 -08:00
|
|
|
glGenTextures(1, &backDropTexture);
|
|
|
|
pie_SetTexturePage(-1);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, backDropTexture);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
|
2007-02-25 04:57:04 -08:00
|
|
|
BACKDROP_HACK_WIDTH, BACKDROP_HACK_HEIGHT,
|
2006-03-27 03:03:10 -08:00
|
|
|
0, GL_RGB, GL_UNSIGNED_BYTE, newBackDropBmp);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-02-07 07:27:17 -08:00
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
2007-02-20 15:46:34 -08:00
|
|
|
|
2007-02-20 16:10:03 -08:00
|
|
|
// Make sure the current texture page is reloaded after we are finished
|
|
|
|
// Otherwise WZ will think it is still loaded and not load it again
|
2007-02-20 15:46:34 -08:00
|
|
|
pie_SetTexturePage(-1);
|
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, backDropTexture);
|
2007-02-07 07:27:17 -08:00
|
|
|
glColor3f(1, 1, 1);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
2007-07-30 13:20:06 -07:00
|
|
|
glTexCoord2f(0, 0);
|
|
|
|
glVertex2f(0, 0);
|
|
|
|
glTexCoord2f(255, 0);
|
|
|
|
glVertex2f(screenWidth, 0);
|
|
|
|
glTexCoord2f(0, 255);
|
|
|
|
glVertex2f(0, screenHeight);
|
|
|
|
glTexCoord2f(255, 255);
|
2007-02-07 07:27:17 -08:00
|
|
|
glVertex2f(screenWidth, screenHeight);
|
2007-06-28 10:47:08 -07:00
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Swap between windowed and full screen mode */
|
|
|
|
void screenToggleMode(void)
|
|
|
|
{
|
2006-08-08 13:58:32 -07:00
|
|
|
(void) SDL_WM_ToggleFullScreen(screen);
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
2007-04-17 09:53:28 -07:00
|
|
|
// Screenshot code goes below this
|
|
|
|
static const unsigned int channelsPerPixel = 3;
|
|
|
|
|
2007-04-29 16:00:38 -07:00
|
|
|
void screenDoDumpToDiskIfRequired(void)
|
2007-04-17 09:53:28 -07:00
|
|
|
{
|
2007-04-29 16:00:38 -07:00
|
|
|
const char* fileName = screendump_filename;
|
2007-05-01 13:34:54 -07:00
|
|
|
static iV_Image image = { 0, 0, 0, NULL };
|
2007-04-17 09:53:28 -07:00
|
|
|
|
2007-04-29 16:00:38 -07:00
|
|
|
if (!screendump_required) return;
|
|
|
|
debug( LOG_3D, "Saving screenshot %s\n", fileName );
|
2007-05-01 13:34:54 -07:00
|
|
|
|
2007-04-29 16:00:38 -07:00
|
|
|
// Dump the currently displayed screen in a buffer
|
|
|
|
if (image.width != screen->w || image.height != screen->h)
|
2007-04-17 09:53:28 -07:00
|
|
|
{
|
2007-04-29 16:00:38 -07:00
|
|
|
if (image.bmp != NULL)
|
2007-04-23 07:28:04 -07:00
|
|
|
{
|
2007-04-29 16:00:38 -07:00
|
|
|
free(image.bmp);
|
2007-04-23 07:28:04 -07:00
|
|
|
}
|
2007-05-01 13:34:54 -07:00
|
|
|
|
2007-04-29 16:00:38 -07:00
|
|
|
image.width = screen->w;
|
|
|
|
image.height = screen->h;
|
2007-05-01 13:34:54 -07:00
|
|
|
image.bmp = malloc(channelsPerPixel * image.width * image.height);
|
2007-04-29 16:00:38 -07:00
|
|
|
if (image.bmp == NULL)
|
2007-04-17 09:53:28 -07:00
|
|
|
{
|
2007-04-29 16:00:38 -07:00
|
|
|
image.width = 0; image.height = 0;
|
|
|
|
debug(LOG_ERROR, "screenDoDumpToDiskIfRequired: Couldn't allocate memory\n");
|
|
|
|
return;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
}
|
2007-04-29 16:00:38 -07:00
|
|
|
glReadPixels(0, 0, image.width, image.height, GL_RGB, GL_UNSIGNED_BYTE, image.bmp);
|
2007-04-16 12:22:01 -07:00
|
|
|
|
2007-04-17 11:24:31 -07:00
|
|
|
// Write the screen to a PNG
|
2007-05-01 13:34:54 -07:00
|
|
|
iV_saveImage_PNG(fileName, &image);
|
2007-04-16 12:22:01 -07:00
|
|
|
|
|
|
|
screendump_required = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void screenDumpToDisk(const char* path) {
|
|
|
|
static unsigned int screendump_num = 0;
|
|
|
|
|
|
|
|
while (++screendump_num != 0) {
|
|
|
|
// We can safely use '/' as path separator here since PHYSFS uses that as its default separator
|
2007-08-21 05:59:05 -07:00
|
|
|
snprintf(screendump_filename, PATH_MAX, "%s/wz2100_shot_%03i.png", path, screendump_num);
|
2007-04-16 12:22:01 -07:00
|
|
|
if (!PHYSFS_exists(screendump_filename)) {
|
|
|
|
// Found a usable filename, so we'll stop searching.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-16 13:07:56 -07:00
|
|
|
ASSERT( screendump_num != 0, "screenDumpToDisk: integer overflow; no more filenumbers available.\n" );
|
2007-04-16 13:00:12 -07:00
|
|
|
|
|
|
|
// If we have an integer overflow, we don't want to go about and overwrite files
|
|
|
|
if (screendump_num != 0)
|
|
|
|
screendump_required = TRUE;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|