670 lines
19 KiB
C
670 lines
19 KiB
C
#include <SDL.h>
|
|
#include <SDL_image.h>
|
|
#include <ft2build.h>
|
|
#include <freetype/freetype.h>
|
|
#include <freetype/ftglyph.h>
|
|
#include <math.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "main.h"
|
|
#include "log.h"
|
|
#include "pack.h"
|
|
#include "opengl.h"
|
|
|
|
#define SCREEN_W gl_screen.w
|
|
#define SCREEN_H gl_screen.h
|
|
|
|
#define FONT_DEF "../gfx/fonts/FreeSans.ttf"
|
|
|
|
// offsets to Adjust the pilot's place onscreen to be in the middle, even with the GUI.
|
|
extern double gui_xoff;
|
|
extern double gui_yoff;
|
|
|
|
// The screen info, gives data of current opengl settings.
|
|
gl_info gl_screen;
|
|
|
|
// Our precious camera.
|
|
Vec2* gl_camera;
|
|
|
|
// Default font.
|
|
gl_font gl_defFont;
|
|
|
|
// Misc.
|
|
static int SDL_VFlipSurface(SDL_Surface* surface);
|
|
static int SDL_IsTrans(SDL_Surface* s, int x, int y);
|
|
static uint8_t* SDL_MapTrans(SDL_Surface* s);
|
|
static int pot(int n);
|
|
// gl_texture.
|
|
static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh);
|
|
// Gl font.
|
|
static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* tex_base);
|
|
|
|
// ================
|
|
// MISC!
|
|
// ================
|
|
|
|
// Get me the closest power of two plox.
|
|
static int pot(int n) {
|
|
int i = 1;
|
|
while(i < n)
|
|
i<<=1;
|
|
return i;
|
|
}
|
|
|
|
// Flips the surface vertically. Return 0 on success.
|
|
static int SDL_VFlipSurface(SDL_Surface* surface) {
|
|
// Flip the image.
|
|
Uint8* rowhi, *rowlo, *tmpbuf;
|
|
int y;
|
|
|
|
tmpbuf = malloc(surface->pitch);
|
|
if(tmpbuf == NULL) {
|
|
WARN("Out of memory");
|
|
return -1;
|
|
}
|
|
|
|
rowhi = (Uint8*)surface->pixels;
|
|
rowlo = rowhi + (surface->h * surface->pitch) - surface->pitch;
|
|
for(y = 0; y < surface->h / 2; ++y) {
|
|
memcpy(tmpbuf, rowhi, surface->pitch);
|
|
memcpy(rowhi, rowlo, surface->pitch);
|
|
memcpy(rowlo, tmpbuf, surface->pitch);
|
|
rowhi += surface->pitch;
|
|
rowlo -= surface->pitch;
|
|
}
|
|
free(tmpbuf);
|
|
// Might be obvious, but I'm done flipping.
|
|
return 0;
|
|
}
|
|
|
|
// Return true if position (x,y) of s is transparent.
|
|
static int SDL_IsTrans(SDL_Surface* s, int x, int y) {
|
|
int bpp = s->format->BytesPerPixel;
|
|
// p is the address to the pixel we want to retrieve.
|
|
Uint8* p = (Uint8*)s->pixels + y * s->pitch + x*bpp;
|
|
|
|
Uint32 pixelcolor = 0;
|
|
|
|
switch(bpp) {
|
|
case 1:
|
|
pixelcolor = *p;
|
|
break;
|
|
case 2:
|
|
pixelcolor = *(Uint16*)p;
|
|
break;
|
|
case 3:
|
|
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
|
pixelcolor = p[0] << 16 | p[1] << 8 | p[2];
|
|
else
|
|
pixelcolor = p[0] | p[1] << 8 | p[2] << 16;
|
|
break;
|
|
case 4:
|
|
pixelcolor = *(Uint32*)p;
|
|
break;
|
|
}
|
|
// Test whetehr the pixels color is equal to color of
|
|
//transparent pixels for that surface.
|
|
return (pixelcolor == s->format->colorkey);
|
|
}
|
|
|
|
// Map the surface transparancy.
|
|
// Return 0 on success.
|
|
static uint8_t* SDL_MapTrans(SDL_Surface* s) {
|
|
// Allocate memory for just enough bits to hold all the data we need.
|
|
int size = s->w*s->h/8 + ((s->w*s->h%8)?1:0);
|
|
uint8_t* t = malloc(size);
|
|
bzero(t, size); // *must* be set to zero.
|
|
|
|
if(t == NULL) {
|
|
WARN("Out of memeory");
|
|
return NULL;
|
|
}
|
|
|
|
int i, j;
|
|
for(i = 0; i < s->h; i++)
|
|
for(j = 0; j < s->w; j++) // Set each bit to be 1 if not transparent or 0 if it is.
|
|
t[(i*s->w+j)/8] |= (SDL_IsTrans(s,j,i)) ? 0 : (1<<((i*s->w+j)%8));
|
|
|
|
return t;
|
|
}
|
|
|
|
// ================
|
|
// TEXTURE!
|
|
// ================
|
|
|
|
// Returns the texture ID.
|
|
// Stores real sizes in rw/rh (from POT padding).
|
|
static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh) {
|
|
GLuint texture;
|
|
SDL_Surface* tmp;
|
|
Uint32 saved_flags;
|
|
Uint8 saved_alpha;
|
|
int potw, poth;
|
|
|
|
// Make size power of two.
|
|
potw = pot(surface->w);
|
|
poth = pot(surface->h);
|
|
if(rw)*rw = potw;
|
|
if(rh)*rh = poth;
|
|
|
|
if(surface->w != potw || surface->h != poth) {
|
|
// Size isn't original.
|
|
SDL_Rect rtemp;
|
|
rtemp.x = rtemp.y = 0;
|
|
rtemp.w = surface->w;
|
|
rtemp.h = surface->h;
|
|
|
|
// Save alpha.
|
|
saved_flags = surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
|
|
saved_alpha = surface->format->alpha;
|
|
if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
|
|
SDL_SetAlpha(surface, 0, 0);
|
|
|
|
// Create the temp POT surface.
|
|
tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY,
|
|
potw, poth, surface->format->BytesPerPixel*8, RGBMASK);
|
|
if(tmp == NULL) {
|
|
WARN("Unable to create POT surface %s", SDL_GetError());
|
|
return 0;
|
|
}
|
|
if(SDL_FillRect(tmp, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, SDL_ALPHA_TRANSPARENT))) {
|
|
WARN("Unable to fill rect: %s", SDL_GetError());
|
|
return 0;
|
|
}
|
|
|
|
SDL_BlitSurface(surface, &rtemp, tmp, &rtemp);
|
|
SDL_FreeSurface(surface);
|
|
|
|
surface = tmp;
|
|
|
|
// Set saved alpha.
|
|
if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
|
|
SDL_SetAlpha(surface, 0, 0);
|
|
|
|
// Create the temp POT surface.
|
|
tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY,
|
|
potw, poth, surface->format->BytesPerPixel*8, RGBMASK);
|
|
if(tmp == NULL) {
|
|
WARN("Unable to create POT surface %s", SDL_GetError());
|
|
return 0;
|
|
}
|
|
if(SDL_FillRect(tmp, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, SDL_ALPHA_TRANSPARENT))) {
|
|
WARN("Unable to fill rect: %s", SDL_GetError());
|
|
return 0;
|
|
}
|
|
|
|
SDL_BlitSurface(surface, &rtemp, tmp, &rtemp);
|
|
SDL_FreeSurface(surface);
|
|
|
|
surface = tmp;
|
|
|
|
// Set saved alpha.
|
|
if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
|
|
SDL_SetAlpha(surface, saved_flags, saved_alpha);
|
|
}
|
|
|
|
glGenTextures(1, &texture); // Create the texure.
|
|
glBindTexture(GL_TEXTURE_2D, texture); // Load the texture.
|
|
|
|
// Filtering, LINEAR is better for scaling, nearest looks nicer, LINEAR
|
|
// also seems to create a bit of artifacts around the edges.
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
SDL_LockSurface(surface);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, surface->format->BytesPerPixel,
|
|
surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
|
|
|
|
SDL_UnlockSurface(surface);
|
|
SDL_FreeSurface(surface);
|
|
|
|
return texture;
|
|
}
|
|
|
|
// Load the SDL_Surface to an openGL texture.
|
|
gl_texture* gl_loadImage(SDL_Surface* surface) {
|
|
int rw, rh;
|
|
|
|
// Set up the texture defaults.
|
|
gl_texture* texture = MALLOC_L(gl_texture);
|
|
texture->w = (double)surface->w;
|
|
texture->h = (double)surface->h;
|
|
texture->sx = 1.;
|
|
texture->sy = 1.;
|
|
|
|
texture->texture = gl_loadSurface(surface, &rw, &rh);
|
|
|
|
texture->rw = (double)rw;
|
|
texture->rh = (double)rh;
|
|
texture->sw = texture->w;
|
|
texture->sh = texture->h;
|
|
|
|
texture->trans = NULL;
|
|
|
|
return texture;
|
|
}
|
|
|
|
// Load the image directly as an opengl texture.
|
|
gl_texture* gl_newImage(const char* path) {
|
|
SDL_Surface* tmp, *surface;
|
|
gl_texture* t;
|
|
uint8_t* trans = NULL;
|
|
uint32_t filesize;
|
|
char* buf = pack_readfile(DATA, (char*)path, &filesize);
|
|
if(buf == NULL) {
|
|
ERR("Loading surface from packfile.");
|
|
return NULL;
|
|
}
|
|
SDL_RWops* rw = SDL_RWFromMem(buf, filesize);
|
|
tmp = IMG_Load_RW(rw, 1);
|
|
free(buf);
|
|
|
|
if(tmp == 0) {
|
|
ERR("'%s' could not be opened: %s", path, IMG_GetError());
|
|
return NULL;
|
|
}
|
|
|
|
surface = SDL_DisplayFormatAlpha(tmp); // Sets the surface to what we use.
|
|
if(surface == 0) {
|
|
WARN("Error converting image to screen format: %s", SDL_GetError());
|
|
return NULL;
|
|
}
|
|
|
|
SDL_FreeSurface(tmp); // Free the temp surface.
|
|
|
|
SDL_LockSurface(surface);
|
|
trans = SDL_MapTrans(surface);
|
|
SDL_UnlockSurface(surface);
|
|
|
|
if(SDL_VFlipSurface(surface)) {
|
|
WARN("Error flipping surface");
|
|
return NULL;
|
|
}
|
|
t = gl_loadImage(surface);
|
|
t->trans = trans;
|
|
|
|
return t;
|
|
}
|
|
|
|
// Load the texture immediately, but also set is as a sprite.
|
|
gl_texture* gl_newSprite(const char* path, const int sx, const int sy) {
|
|
gl_texture* texture;
|
|
if((texture = gl_newImage(path)) == NULL)
|
|
return NULL;
|
|
texture->sx = (double)sx;
|
|
texture->sy = (double)sy;
|
|
texture->sw = texture->w/texture->sx;
|
|
texture->sh = texture->h/texture->sy;
|
|
return texture;
|
|
}
|
|
|
|
// Free the texture.
|
|
void gl_freeTexture(gl_texture* texture) {
|
|
glDeleteTextures(1, &texture->texture);
|
|
if(texture->trans) free(texture->trans);
|
|
free(texture);
|
|
}
|
|
|
|
// Return true if pixel at pos (x,y) is transparent.
|
|
int gl_isTrans(const gl_texture* t, const int x, const int y) {
|
|
return !(t->trans[(y*(int)(t->w)+x)/8] & (1<<((y*(int)(t->w)+x)%8)));
|
|
}
|
|
|
|
// Set x and y to be the appropriate sprite for gl_texture using dir.
|
|
void gl_getSpriteFromDir(int* x, int* y, const gl_texture* t, const double dir) {
|
|
int s = (int)(dir / (2.0*M_PI / (t->sy*t->sx)));
|
|
|
|
// Make sure the sprite is "in range".
|
|
if(s > (int)(t->sy*t->sx)-1) s = s % (int)(t->sy*t->sx);
|
|
|
|
*x = s % (int)t->sx;
|
|
*y = s / (int)t->sy;
|
|
}
|
|
|
|
// ================
|
|
// BLITTING!
|
|
// ================
|
|
|
|
// Blit the sprite at given position.
|
|
void gl_blitSprite(const gl_texture* sprite, const Vec2* pos, const int sx, const int sy) {
|
|
// Don't bother drawing if offscreen -- waste of cycles.
|
|
if(fabs(VX(*pos) -VX(*gl_camera)) > gl_screen.w / 2 + sprite->sw / 2 ||
|
|
fabs(VY(*pos) -VY(*gl_camera)) > gl_screen.h / 2 + sprite->sh / 2)
|
|
return;
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
glMatrixMode(GL_TEXTURE);
|
|
glPushMatrix();
|
|
glTranslated(sprite->sw * (double)(sx)/sprite->rw,
|
|
sprite->sh*(sprite->sy-(double)sy-1)/sprite->rh, 0.);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix(); // Projection translation matrix.
|
|
glTranslated(VX(*pos) - VX(*gl_camera) - sprite->sw/2. + gui_xoff,
|
|
VY(*pos) -VY(*gl_camera) - sprite->sh/2. + gui_yoff, 0.);
|
|
glScalef((double)gl_screen.w/SCREEN_W, (double)gl_screen.h/SCREEN_H, 0.);
|
|
|
|
// Actual blitting....
|
|
glBindTexture(GL_TEXTURE_2D, sprite->texture);
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
glColor4d(1., 1., 1., 1.);
|
|
glTexCoord2d(0., 0.);
|
|
glVertex2d(0., 0.);
|
|
glTexCoord2d(sprite->sw/sprite->rw, 0.);
|
|
glVertex2d(sprite->sw, 0.);
|
|
glTexCoord2d(0., sprite->sh/sprite->rh);
|
|
glVertex2d(0., sprite->sh);
|
|
glTexCoord2d(sprite->sw/sprite->rw, sprite->sh/sprite->rh);
|
|
glVertex2d(sprite->sw, sprite->sh);
|
|
glEnd();
|
|
|
|
glPopMatrix(); // Projection translation matrix.
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
glPopMatrix(); // Sprite translation matrix.
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
// Just straight out blit the thing at position.
|
|
void gl_blitStatic(const gl_texture* texture, const Vec2* pos) {
|
|
glEnable(GL_TEXTURE_2D);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix(); // Set up translation matrix.
|
|
glTranslated(VX(*pos) - (double)gl_screen.w/2., VY(*pos) - (double)gl_screen.h/2., 0);
|
|
glScaled((double)gl_screen.w/SCREEN_W, (double)gl_screen.h/SCREEN_H, 0.);
|
|
|
|
// Actual blitting..
|
|
glBindTexture(GL_TEXTURE_2D, texture->texture);
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
glColor4d(1., 1., 1., 1.);
|
|
glTexCoord2d(0., 0.);
|
|
glVertex2d(0., 0.);
|
|
glTexCoord2d(texture->sw/texture->rw, 0.);
|
|
glVertex2d(texture->sw, 0.);
|
|
glTexCoord2d(0., texture->sh/texture->rh);
|
|
glVertex2d(0., texture->sh);
|
|
glTexCoord2d(texture->sw/texture->rw, texture->sh/texture->rh);
|
|
glVertex2d(texture->sw, texture->h);
|
|
glEnd();
|
|
|
|
glPopMatrix(); // Pop the translation matrix.
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
// Bind our precious camera to a vector.
|
|
void gl_bindCamera(const Vec2* pos) {
|
|
gl_camera = (Vec2*)pos;
|
|
}
|
|
|
|
// Print text on screen! YES!!!! Just like printf! But different!
|
|
// Defaults ft_font to gl_defFont if NULL.
|
|
void gl_print(const gl_font* ft_font, const Vec2* pos, const char* fmt, ...) {
|
|
//float h = ft_font->h / .63; // Slightly increases font size.
|
|
char text[256];
|
|
va_list ap;
|
|
|
|
if(ft_font == NULL) ft_font = &gl_defFont;
|
|
|
|
if(fmt == NULL) return;
|
|
else {
|
|
// convert the symbols to text.
|
|
va_start(ap, fmt);
|
|
vsprintf(text, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glListBase(ft_font->list_base);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPushMatrix(); // Translation matrix.
|
|
glTranslated(VX(*pos) - (double)gl_screen.w/2., VY(*pos) - (double)gl_screen.h/2., 0);
|
|
|
|
glColor4d(1., 1., 1., 1.);
|
|
glCallLists(strlen(text), GL_UNSIGNED_BYTE, &text);
|
|
|
|
glPopMatrix(); // Translation matrix.
|
|
glDisable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
// ================
|
|
// FONT!
|
|
// ================
|
|
static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* tex_base) {
|
|
FT_Glyph glyph;
|
|
FT_Bitmap bitmap;
|
|
GLubyte* expanded_data;
|
|
int w, h;
|
|
int i, j;
|
|
|
|
if(FT_Load_Glyph(face, FT_Get_Char_Index(face, ch), FT_LOAD_DEFAULT))
|
|
WARN("FT_Load_Glyph failed");
|
|
|
|
if(FT_Get_Glyph(face->glyph, &glyph))
|
|
WARN("FT_Ge_Glyph failed");
|
|
|
|
// Convert your glyph to a bitmap.
|
|
FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1);
|
|
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
|
|
|
|
bitmap = bitmap_glyph->bitmap; // To simplify.
|
|
|
|
// Need the POT wrapping for GL.
|
|
w = pot(bitmap.width);
|
|
h = pot(bitmap.rows);
|
|
|
|
// Memory for textured data.
|
|
// Bitmap is useing two channels, one for luminosity and one for alpha.
|
|
expanded_data = (GLubyte*)malloc(sizeof(GLubyte)*2*w*h);
|
|
for(j = 0; j < h; j++) {
|
|
for(i = 0; i < w; i++) {
|
|
expanded_data[2*(i+j*w)] = expanded_data[2*(i+j*w)+1] =
|
|
(i >= bitmap.width || j >= bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j];
|
|
}
|
|
}
|
|
// Create the GL texture.
|
|
glBindTexture(GL_TEXTURE_2D, tex_base[(int)ch]);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data);
|
|
|
|
free(expanded_data); // No need for this now.
|
|
|
|
// Create the display lists.
|
|
glNewList(list_base+ch, GL_COMPILE);
|
|
|
|
// Corrects a spacing flaw between letters and
|
|
// downwards correction for letters like g or y.
|
|
glPushMatrix();
|
|
glTranslated(bitmap_glyph->left, bitmap_glyph->top-bitmap.rows, 0);
|
|
|
|
// Take the opengl POT wrapping into account.
|
|
double x = (double)bitmap.width/(double)w;
|
|
double y = (double)bitmap.rows/(double)h;
|
|
|
|
// Draw the texture mapped quad.
|
|
glBindTexture(GL_TEXTURE_2D, tex_base[(int)ch]);
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
glTexCoord2d(0, 0);
|
|
glVertex2d(0, bitmap.rows);
|
|
glTexCoord2d(x, 0);
|
|
glVertex2d(bitmap.width, bitmap.rows);
|
|
glTexCoord2d(0, y);
|
|
glVertex2d(0, 0);
|
|
glTexCoord2d(x, y);
|
|
glVertex2d(bitmap.width, 0);
|
|
glEnd();
|
|
|
|
glPopMatrix();
|
|
glTranslated(face->glyph->advance.x >> 6, 0,0);
|
|
|
|
// End of the display list.
|
|
glEndList();
|
|
|
|
FT_Done_Glyph(glyph);
|
|
}
|
|
|
|
void gl_fontInit(gl_font* font, const char* fname, unsigned int h) {
|
|
if(font == NULL) font = &gl_defFont;
|
|
|
|
uint32_t bufsize;
|
|
FT_Byte* buf = pack_readfile(DATA, (fname) ? fname : FONT_DEF, &bufsize);
|
|
|
|
font->textures = malloc(sizeof(GLuint)*128);
|
|
font->h = h;
|
|
|
|
// Create a FreeType font library.
|
|
FT_Library library;
|
|
if(FT_Init_FreeType(&library)) {
|
|
WARN("FT_Init_FreeType failed");
|
|
}
|
|
|
|
// Objects that freetype uses to store font info.
|
|
FT_Face face;
|
|
if(FT_New_Memory_Face(library, buf, bufsize, 0, &face))
|
|
WARN("FT_New_Memory_Face failed loading library from %s", fname);
|
|
|
|
// FreeType is pretty nice and measures using 1/64 of a pixel, therfore expand.
|
|
FT_Set_Char_Size(face, h << 6, h << 6, 96, 96);
|
|
|
|
// Have OpenGL allocate space for the textures / display lists.
|
|
font->list_base = glGenLists(128);
|
|
glGenTextures(128, font->textures);
|
|
|
|
// Create each of the font display lists.
|
|
unsigned char i;
|
|
for(i = 0; i < 128; i++)
|
|
gl_fontMakeDList(face, i, font->list_base, font->textures);
|
|
|
|
// We can now free the face and library.
|
|
FT_Done_Face(face);
|
|
FT_Done_FreeType(library);
|
|
free(buf);
|
|
}
|
|
|
|
void gl_freeFont(gl_font* font) {
|
|
if(font == NULL) font = &gl_defFont;
|
|
glDeleteLists(font->list_base, 128);
|
|
glDeleteTextures(128, font->textures);
|
|
free(font->textures);
|
|
}
|
|
|
|
// ================
|
|
// GLOBAL.
|
|
// ================
|
|
|
|
// Initialize SDL/OpenGL etc.
|
|
int gl_init(void) {
|
|
int depth, i, supported = 0;
|
|
SDL_Rect** modes;
|
|
int flags = SDL_OPENGL;
|
|
flags |= SDL_FULLSCREEN * gl_screen.fullscreen;
|
|
|
|
// Initializes video.
|
|
if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
|
|
WARN("Unable to initialize SDL: %s", SDL_GetError());
|
|
return -1;
|
|
}
|
|
|
|
// FFUUUU Ugly cursor thing.
|
|
// -- Ok, Maybe for now.
|
|
//SDL_ShowCursor(SDL_DISABLE);
|
|
|
|
// Get available fullscreen modes.
|
|
if(gl_screen.fullscreen) {
|
|
modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN);
|
|
if(modes == NULL) {
|
|
WARN("No fullscreen modes available");
|
|
if(flags & SDL_FULLSCREEN) {
|
|
WARN("Disabling fullscreen mode");
|
|
flags ^= SDL_FULLSCREEN;
|
|
}
|
|
}
|
|
else if(modes == (SDL_Rect**)-1)
|
|
DEBUG("All fullscreen modes available");
|
|
else {
|
|
DEBUG("Available fullscreen modes:");
|
|
for(i = 0; modes[i]; ++i) {
|
|
DEBUG("\t%dx%d", modes[i]->w, modes[i]->h);
|
|
if(flags & SDL_FULLSCREEN && modes[i]->w == gl_screen.w && modes[i]->h == gl_screen.h)
|
|
supported = 1;
|
|
}
|
|
}
|
|
|
|
// Make sure fullscreen mode is supported.
|
|
if(flags & SDL_FULLSCREEN && !supported) {
|
|
WARN("Fullscreen mode %dx%d is not supported by your current setup, switching to another mode",
|
|
gl_screen.w, gl_screen.h);
|
|
gl_screen.w = modes[0]->w;
|
|
gl_screen.h = modes[0]->h;
|
|
}
|
|
// Free the video modes.
|
|
for(i = 0; modes[i]; ++i)
|
|
free(modes[i]);
|
|
free(modes);
|
|
}
|
|
|
|
// Test the setup.
|
|
depth = SDL_VideoModeOK(gl_screen.w, gl_screen.h, gl_screen.depth, flags);
|
|
if(depth != gl_screen.depth)
|
|
WARN("Depth: %d bpp unavailable, will use %d bpp", gl_screen.depth, depth);
|
|
|
|
gl_screen.depth = depth;
|
|
|
|
// Actually creating the screen.
|
|
if(SDL_SetVideoMode(gl_screen.w, gl_screen.h, gl_screen.depth, flags) == NULL) {
|
|
WARN("Unable to create OpenGL window: %s", SDL_GetError());
|
|
SDL_Quit();
|
|
return -1;
|
|
}
|
|
|
|
// Grab some info.
|
|
SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &gl_screen.r);
|
|
SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gl_screen.g);
|
|
SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &gl_screen.b);
|
|
SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &gl_screen.a);
|
|
SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &gl_screen.doublebuf);
|
|
gl_screen.depth = gl_screen.r + gl_screen.g + gl_screen.b + gl_screen.a;
|
|
|
|
// Debug heaven.
|
|
DEBUG("OpenGL Window Created: %dx%d@%dbpp %s", gl_screen.w, gl_screen.h, gl_screen.depth,
|
|
gl_screen.fullscreen ? "fullscreen" : "window");
|
|
DEBUG("r: %d, g: %d, b: %d, a: %d, doublebuffer: %s", gl_screen.r, gl_screen.g, gl_screen.b, gl_screen.a,
|
|
gl_screen.doublebuf ? "yes" : "no");
|
|
DEBUG("Renderer: %s", glGetString(GL_RENDERER));
|
|
|
|
// Some openGL options.
|
|
glClearColor(0., 0., 0., 1.);
|
|
glDisable(GL_DEPTH_TEST); // Set for doing 2D shidazles.
|
|
//glEnable(GL_TEXTURE_2D); // Don't enable globally, it will break non-texture blits.
|
|
glDisable(GL_LIGHTING); // No lighting, it is done when rendered.
|
|
glMatrixMode(GL_PROJECTION);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(-SCREEN_W /2, // Left edge.
|
|
SCREEN_W /2, // Right edge.
|
|
-SCREEN_H /2, // Bottom edge.
|
|
SCREEN_H /2, // Top edge.
|
|
-1., // Near.
|
|
1.); // Far.
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Alpha.
|
|
glEnable(GL_BLEND);
|
|
|
|
glPointSize(1.); // Default is 1.
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Clean up our mess.
|
|
void gl_exit(void) {
|
|
//SDL_ShowCursor(SDL_ENABLE);
|
|
SDL_Quit();
|
|
}
|
|
|