404 lines
12 KiB
C++
Executable File
404 lines
12 KiB
C++
Executable File
/************************************************************************
|
|
* Copyright (c) 2005-2007 tok@openlinux.org.uk *
|
|
* *
|
|
* This software is provided as-is, without any express or implied *
|
|
* warranty. In no event will the authors be held liable for any *
|
|
* damages arising from the use of this software. *
|
|
* *
|
|
* Permission is granted to anyone to use this software for any purpose, *
|
|
* including commercial applications, and to alter it and redistribute *
|
|
* it freely, subject to the following restrictions: *
|
|
* *
|
|
* 1. The origin of this software must not be misrepresented; you must *
|
|
* not claim that you wrote the original software. If you use this *
|
|
* software in a product, an acknowledgment in the product documentation *
|
|
* would be appreciated but is not required. *
|
|
* *
|
|
* 2. Altered source versions must be plainly marked as such, and must *
|
|
* not be misrepresented as being the original software. *
|
|
* *
|
|
* 3. This notice may not be removed or altered from any source *
|
|
* distribution. *
|
|
************************************************************************/
|
|
#include <string>
|
|
#include "gl_screen.h"
|
|
#include "log.h"
|
|
#include "buffercache.h"
|
|
#include "m_exceptions.h"
|
|
#include "image_loader.h"
|
|
|
|
|
|
namespace OpenGL {
|
|
#ifndef DEFAULT_SCREEN_WIDTH
|
|
#define DEFAULT_SCREEN_WIDTH 640
|
|
#endif
|
|
#ifndef DEFAULT_SCREEN_HEIGHT
|
|
#define DEFAULT_SCREEN_HEIGHT 480
|
|
#endif
|
|
#ifndef DEFAULT_SCREEN_VSYNC
|
|
#define DEFAULT_SCREEN_VSYNC 0
|
|
#endif
|
|
|
|
Screen::Screen() {
|
|
surface = NULL;
|
|
videoFlags = defaultVideoFlags;
|
|
width = DEFAULT_SCREEN_WIDTH;
|
|
height = DEFAULT_SCREEN_HEIGHT;
|
|
bpp = 32;
|
|
fieldOfView = 60.0f;
|
|
nearPlane = 0.1f;
|
|
farPlane = 250.0f;
|
|
// 0: no vsync, 1: sdl, 2 native
|
|
useVsync = DEFAULT_SCREEN_VSYNC;
|
|
}
|
|
|
|
void Screen::activate(Uint32 w, Uint32 h) {
|
|
if (w)
|
|
width = w;
|
|
if (h)
|
|
height = h;
|
|
initSDL();
|
|
resize(width, height);
|
|
INFO << "activating screen: " << width << "x" << height << std::endl;
|
|
initGL();
|
|
setSystemMouseCursor(false);
|
|
}
|
|
|
|
void Screen::setupGlVars( float fov, float near_p, float far_p) {
|
|
fieldOfView = fov;
|
|
nearPlane = near_p;
|
|
farPlane = far_p;
|
|
}
|
|
|
|
void Screen::setupVsync(size_t mode) {
|
|
useVsync = mode;
|
|
}
|
|
|
|
void Screen::setSystemMouseCursor(bool visible) {
|
|
SDL_ShowCursor((visible ? SDL_ENABLE : SDL_DISABLE));
|
|
}
|
|
|
|
Uint32 Screen::getWidth() {
|
|
return width;
|
|
}
|
|
|
|
Uint32 Screen::getHeight() {
|
|
return height;
|
|
}
|
|
|
|
bool Screen::getFullscreen() {
|
|
return (videoFlags & SDL_WINDOW_FULLSCREEN);
|
|
}
|
|
|
|
void Screen::setFullScreenFlag(bool v) {
|
|
if (v && getFullscreen())
|
|
return;
|
|
else if (!v && !getFullscreen())
|
|
return;
|
|
if (v)
|
|
videoFlags |= SDL_WINDOW_FULLSCREEN;
|
|
else
|
|
videoFlags ^= SDL_WINDOW_FULLSCREEN;
|
|
}
|
|
|
|
Screen::~Screen() {
|
|
setSystemMouseCursor(true);
|
|
if (SDL_WasInit(SDL_INIT_VIDEO))
|
|
SDL_Quit();
|
|
surface = NULL;
|
|
}
|
|
|
|
void Screen::toggleFullscreen() {
|
|
if (videoFlags & SDL_WINDOW_FULLSCREEN)
|
|
videoFlags ^= SDL_WINDOW_FULLSCREEN;
|
|
else
|
|
videoFlags |= SDL_WINDOW_FULLSCREEN;
|
|
resize(width, height);
|
|
}
|
|
|
|
void Screen::initSDL() {
|
|
|
|
//Xperimental -- Vladislav Khorev vladislav.khorev@fishrungames.com
|
|
|
|
size_t color_depth_triple[3];
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
color_depth_triple[i] = 8;
|
|
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, color_depth_triple[0]);
|
|
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, color_depth_triple[1]);
|
|
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, color_depth_triple[2]);
|
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
#ifdef HAVE_SDL_VSYNC
|
|
if (useVsync == 1) {
|
|
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
|
|
INFO << "enabling vertical sync:" << " SDL" << std::endl;
|
|
}
|
|
#else
|
|
if (useVsync == 1)
|
|
WARN << "Cannot use SDL vsync - option disabled while compiling" << std::endl;
|
|
#endif
|
|
|
|
|
|
/*
|
|
int err = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
|
|
if (err)
|
|
//throw "SDL_Init failed: " + std::string(SDL_GetError());
|
|
throw E_INVALIDFORMAT("SDL_Init failed: " + std::string(SDL_GetError()));
|
|
|
|
const char* sdl_err = SDL_GetError();
|
|
if (strlen(sdl_err) > 0)
|
|
WARN << "SDL_Init complained: " << sdl_err << std::endl;
|
|
SDL_ClearError();
|
|
|
|
const SDL_VideoInfo *vInfo = SDL_GetVideoInfo();
|
|
|
|
if (vInfo == NULL)
|
|
throw E_NOTSUPPORTED("SDL_GetVideoInfo failed: " + std::string(SDL_GetError()));
|
|
|
|
if (vInfo->hw_available == 1)
|
|
videoFlags |= SDL_HWSURFACE;
|
|
else
|
|
videoFlags |= SDL_SWSURFACE;
|
|
|
|
if (vInfo->blit_hw)
|
|
videoFlags |= SDL_HWACCEL;
|
|
|
|
bpp = vInfo->vfmt->BitsPerPixel;
|
|
|
|
INFO << "video-probe:" << std::endl <<
|
|
" hw-surface: " << (vInfo->hw_available == 1 ? "on" : "off") << std::endl <<
|
|
" hw-blit: " << (vInfo->blit_hw ? "on" : "off") << std::endl <<
|
|
" bpp: " << int (bpp) << std::endl;
|
|
|
|
size_t color_depth_triple[3];
|
|
switch(bpp) {
|
|
case 32:
|
|
case 24:
|
|
for (int i=0; i < 3; ++i)
|
|
color_depth_triple[i] = 8;
|
|
break;
|
|
case 16:
|
|
color_depth_triple[0] = 5;
|
|
color_depth_triple[1] = 6;
|
|
color_depth_triple[2] = 5;
|
|
break;
|
|
case 15:
|
|
for (int i=0; i < 3; ++i)
|
|
color_depth_triple[i] = 5;
|
|
break;
|
|
case 8:
|
|
color_depth_triple[0] = 2;
|
|
color_depth_triple[1] = 3;
|
|
color_depth_triple[2] = 3;
|
|
break;
|
|
default:
|
|
throw E_NOTSUPPORTED("Invalid bit-per-pixel setting");
|
|
}
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, color_depth_triple[0]);
|
|
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, color_depth_triple[1]);
|
|
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, color_depth_triple[2]);
|
|
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16);
|
|
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1);
|
|
#ifdef HAVE_SDL_VSYNC
|
|
if (useVsync == 1) {
|
|
SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1);
|
|
INFO << "enabling vertical sync:" << " SDL" << std::endl;
|
|
}
|
|
#else
|
|
if (useVsync == 1)
|
|
WARN << "Cannot use SDL vsync - option disabled while compiling" << std::endl;
|
|
#endif
|
|
|
|
sdl_err = SDL_GetError();
|
|
if (strlen(sdl_err) > 0)
|
|
ERROR << "setting sdl_gl attributes: " << sdl_err << std::endl;
|
|
*/
|
|
}
|
|
|
|
void Screen::initGL() {
|
|
GL_CHECKERROR;
|
|
if (useVsync == 2) {
|
|
#ifdef LINUX
|
|
int (*fp)(int) = (int(*)(int)) SDL_GL_GetProcAddress("glXSwapIntervalMESA");
|
|
if (fp) {
|
|
fp(1);
|
|
INFO << "enabling vertical sync:" << " GLX" << std::endl;
|
|
}
|
|
else
|
|
ERROR << "No symbol 'glXSwapIntervalMESA' found - cannot use GLX vsync" << std::endl;
|
|
#else
|
|
typedef void (APIENTRY * WGLSWAPINTERVALEXT) (int);
|
|
WGLSWAPINTERVALEXT wglSwapIntervalEXT =
|
|
(WGLSWAPINTERVALEXT) wglGetProcAddress("wglSwapIntervalEXT");
|
|
if (wglSwapIntervalEXT)
|
|
{
|
|
wglSwapIntervalEXT(1); // set vertical synchronisation
|
|
INFO << "enabling vertical sync:" << " WGL" << std::endl;
|
|
}
|
|
else
|
|
ERROR << "No symbol 'wglSwapIntervalEXT' found - cannot use WGL vsync" << std::endl;
|
|
#endif
|
|
}
|
|
|
|
GLfloat LightAmbient[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
GLfloat LightDiffuse[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
GLfloat LightPosition[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
|
|
//glShadeModel( GL_SMOOTH );
|
|
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
|
glEnable( GL_DEPTH_TEST );
|
|
|
|
glEnable( GL_LIGHTING );
|
|
glEnable(GL_LIGHT0);
|
|
//glDisable(GL_LIGHT0);
|
|
glEnable(GL_LIGHT1);
|
|
//glDisable(GL_LIGHT1);
|
|
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
|
|
glLightfv( GL_LIGHT0, GL_AMBIENT, LightAmbient );
|
|
glLightfv( GL_LIGHT0, GL_DIFFUSE, LightDiffuse );
|
|
glLightfv( GL_LIGHT0, GL_POSITION, LightPosition );
|
|
|
|
GLfloat LightAmbient2[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
|
|
|
|
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient2);
|
|
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
|
|
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
|
|
|
|
|
|
//glColorMaterial(GL_BACK, GL_AMBIENT_AND_DIFFUSE);
|
|
glCullFace(GL_BACK);
|
|
//glPolygonMode(GL_FRONT, GL_FILL);
|
|
//glPolygonMode(GL_BACK, GL_LINE);
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
GLfloat MaterialAmbient[] = { 0.0f, 0.0f, 1.0f, 1.0f };
|
|
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
|
|
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, MaterialAmbient);
|
|
|
|
|
|
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, MaterialAmbient);
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialAmbient);
|
|
glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, MaterialAmbient);
|
|
|
|
|
|
//glEnable(GL_COLOR_MATERIAL);
|
|
|
|
if (queryExtension("GL_EXT_texture_filter_anisotropic")) {
|
|
GLfloat maxAniso = 1.0f;
|
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso);
|
|
//if (maxAniso >= 2.0f)
|
|
ImageUtil::supportedMaxAnisoDegree = maxAniso;
|
|
INFO << "GL supports anisotropic filtering with degree: " << maxAniso << std::endl;
|
|
}
|
|
|
|
GL_CHECKERROR;
|
|
}
|
|
|
|
void Screen::resize(Uint32 w, Uint32 h) {
|
|
|
|
//Xperimental -- Vladislav Khorev vladislav.khorev@fishrungames.com
|
|
|
|
if (h == 0)
|
|
h = 1;
|
|
|
|
surface = SDL_CreateWindow(
|
|
"OpenGTA", 0, 0, w, h,
|
|
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
|
|
|
// Create an OpenGL context associated with the window.
|
|
glcontext = SDL_GL_CreateContext(surface);
|
|
|
|
glViewport(0, 0, w, h);
|
|
width = w;
|
|
height = h;
|
|
GL_CHECKERROR;
|
|
|
|
/*
|
|
if (h == 0)
|
|
h = 1;
|
|
surface = SDL_SetVideoMode(w, h, bpp, videoFlags);
|
|
if (surface == NULL) {
|
|
ERROR << "vide-mode: " << w << ", " << h << " bpp: " << bpp <<
|
|
" hw-surface: " << (videoFlags & SDL_HWSURFACE == SDL_HWSURFACE ? "on" : "off") <<
|
|
" hw-blit: " << (videoFlags & SDL_HWACCEL == SDL_HWACCEL ? "on" : "off") << std::endl;
|
|
throw E_NOTSUPPORTED(SDL_GetError());
|
|
}
|
|
|
|
glViewport(0, 0, w, h);
|
|
width = w;
|
|
height = h;
|
|
GL_CHECKERROR;*/
|
|
}
|
|
|
|
void Screen::set3DProjection() {
|
|
float ratio = float(width) / float(height);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
gluPerspective( fieldOfView, ratio, nearPlane, farPlane);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
}
|
|
|
|
void Screen::setFlatProjection() {
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0, width, 0, height, -1, 1);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
}
|
|
|
|
void Screen::makeScreenshot(const char* filename) {
|
|
INFO << "saving screen as: " << filename << std::endl;
|
|
uint8_t *pixels = Util::BufferCacheHolder::Instance().requestBuffer(width * height * 3);
|
|
|
|
glReadBuffer(GL_FRONT);
|
|
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
|
|
|
|
SDL_Surface* image = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24,
|
|
255U << (0),
|
|
255U << (8),
|
|
255U << (16),
|
|
0);
|
|
SDL_LockSurface(image);
|
|
|
|
uint8_t *imagepixels = reinterpret_cast<uint8_t*>(image->pixels);
|
|
for (int y = (height - 1); y >= 0; --y) {
|
|
uint8_t *row_begin = pixels + y * width * 3;
|
|
uint8_t *row_end = row_begin + width * 3;
|
|
|
|
std::copy(row_begin, row_end, imagepixels);
|
|
imagepixels += image->pitch;
|
|
}
|
|
SDL_UnlockSurface(image);
|
|
SDL_SaveBMP(image, filename);
|
|
SDL_FreeSurface( image );
|
|
}
|
|
|
|
GLboolean Screen::queryExtension(const char *extName) {
|
|
// from the 'Red Book'
|
|
char *p = (char *) glGetString(GL_EXTENSIONS);
|
|
char *end = p + strlen(p);
|
|
while (p < end) {
|
|
size_t n = strcspn(p, " ");
|
|
if ((strlen(extName)==n) && (strncmp(extName,p,n)==0)) {
|
|
return GL_TRUE;
|
|
}
|
|
p += (n + 1);
|
|
}
|
|
return GL_FALSE;
|
|
}
|
|
}
|