diff options
| author | Magnus Auvinen <magnus.auvinen@gmail.com> | 2009-10-27 14:38:53 +0000 |
|---|---|---|
| committer | Magnus Auvinen <magnus.auvinen@gmail.com> | 2009-10-27 14:38:53 +0000 |
| commit | 878ede3080ab2cfb627aca505c397d9765052996 (patch) | |
| tree | 98bff371070e1dca0295f0ca58d64ac4ee8042ce /src/engine/client/ec_gfx.cpp | |
| parent | 9b99ec0e60b60134e46f2f71d707230948f7db03 (diff) | |
| download | zcatch-878ede3080ab2cfb627aca505c397d9765052996.tar.gz zcatch-878ede3080ab2cfb627aca505c397d9765052996.zip | |
major update with stuff
Diffstat (limited to 'src/engine/client/ec_gfx.cpp')
| -rw-r--r-- | src/engine/client/ec_gfx.cpp | 992 |
1 files changed, 992 insertions, 0 deletions
diff --git a/src/engine/client/ec_gfx.cpp b/src/engine/client/ec_gfx.cpp new file mode 100644 index 00000000..5632581a --- /dev/null +++ b/src/engine/client/ec_gfx.cpp @@ -0,0 +1,992 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ + +#include <base/detect.h> + +#include "SDL.h" + +#ifdef CONF_FAMILY_WINDOWS + #define WIN32_LEAN_AND_MEAN + #include <windows.h> +#endif + +#ifdef CONF_PLATFORM_MACOSX + #include <OpenGL/gl.h> + #include <OpenGL/glu.h> +#else + #include <GL/gl.h> + #include <GL/glu.h> +#endif + +#include <base/system.h> +#include <engine/external/pnglite/pnglite.h> + +#include <engine/e_client_interface.h> +#include <engine/e_engine.h> +#include <engine/e_config.h> +#include <engine/e_keys.h> + +#include <string.h> +#include <stdio.h> +#include <math.h> + +/* compressed textures */ +#define GL_COMPRESSED_RGB_ARB 0x84ED +#define GL_COMPRESSED_RGBA_ARB 0x84EE +#define GL_COMPRESSED_ALPHA_ARB 0x84E9 + +#define TEXTURE_MAX_ANISOTROPY_EXT 0x84FE + + +void gfx_font_init(); + +VIDEO_MODE fakemodes[] = { + {320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8}, + {720,400,8,8,8}, {768,576,8,8,8}, {800,600,8,8,8}, + {1024,600,8,8,8}, {1024,768,8,8,8}, {1152,864,8,8,8}, + {1280,768,8,8,8}, {1280,800,8,8,8}, {1280,960,8,8,8}, + {1280,1024,8,8,8}, {1368,768,8,8,8}, {1400,1050,8,8,8}, + {1440,900,8,8,8}, {1440,1050,8,8,8}, {1600,1000,8,8,8}, + {1600,1200,8,8,8}, {1680,1050,8,8,8}, {1792,1344,8,8,8}, + {1800,1440,8,8,8}, {1856,1392,8,8,8}, {1920,1080,8,8,8}, + {1920,1200,8,8,8}, {1920,1440,8,8,8}, {1920,2400,8,8,8}, + {2048,1536,8,8,8}, + + {320,240,5,6,5}, {400,300,5,6,5}, {640,480,5,6,5}, + {720,400,5,6,5}, {768,576,5,6,5}, {800,600,5,6,5}, + {1024,600,5,6,5}, {1024,768,5,6,5}, {1152,864,5,6,5}, + {1280,768,5,6,5}, {1280,800,5,6,5}, {1280,960,5,6,5}, + {1280,1024,5,6,5}, {1368,768,5,6,5}, {1400,1050,5,6,5}, + {1440,900,5,6,5}, {1440,1050,5,6,5}, {1600,1000,5,6,5}, + {1600,1200,5,6,5}, {1680,1050,5,6,5}, {1792,1344,5,6,5}, + {1800,1440,5,6,5}, {1856,1392,5,6,5}, {1920,1080,5,6,5}, + {1920,1200,5,6,5}, {1920,1440,5,6,5}, {1920,2400,5,6,5}, + {2048,1536,5,6,5} +}; + +int gfx_get_video_modes(VIDEO_MODE *list, int maxcount) +{ + int num_modes = sizeof(fakemodes)/sizeof(VIDEO_MODE); + SDL_Rect **modes; + + if(config.gfx_display_all_modes) + { + int count = sizeof(fakemodes)/sizeof(VIDEO_MODE); + mem_copy(list, fakemodes, sizeof(fakemodes)); + if(maxcount < count) + count = maxcount; + return count; + } + + /* TODO: fix this code on osx or windows */ + + modes = SDL_ListModes(NULL, SDL_OPENGL|SDL_GL_DOUBLEBUFFER|SDL_FULLSCREEN); + if(modes == NULL) + { + /* no modes */ + num_modes = 0; + } + else if(modes == (SDL_Rect**)-1) + { + /* all modes */ + } + else + { + int i; + num_modes = 0; + for(i = 0; modes[i]; ++i) + { + if(num_modes == maxcount) + break; + list[num_modes].width = modes[i]->w; + list[num_modes].height = modes[i]->h; + list[num_modes].red = 8; + list[num_modes].green = 8; + list[num_modes].blue = 8; + num_modes++; + } + } + + return num_modes; +} + + +#include "graphics.h" + +class CGraphics_OpenGL : public IEngineGraphics +{ +protected: + /* */ + typedef struct { float x, y, z; } CPoint; + typedef struct { float u, v; } CTexCoord; + typedef struct { float r, g, b, a; } CColor; + + typedef struct + { + CPoint m_Pos; + CTexCoord m_Tex; + CColor m_Color; + } CVertex; + + enum + { + MAX_VERTICES = 32*1024, + MAX_TEXTURES = 1024*4, + + DRAWING_QUADS=1, + DRAWING_LINES=2 + }; + + CVertex m_aVertices[MAX_VERTICES]; + int m_NumVertices; + + CColor m_aColor[4]; + CTexCoord m_aTexture[4]; + + bool m_RenderEnable; + + float m_Rotation; + int m_Drawing; + bool m_DoScreenshot; + + float m_ScreenX0; + float m_ScreenY0; + float m_ScreenX1; + float m_ScreenY1; + + int m_InvalidTexture; + + struct CTexture + { + GLuint tex; + int memsize; + int flags; + int next; + }; + + enum + { + + }; + + CTexture m_aTextures[MAX_TEXTURES]; + int m_FirstFreeTexture; + int m_TextureMemoryUsage; + + + void Flush() + { + if(m_NumVertices == 0) + return; + + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glVertexPointer(3, GL_FLOAT, + sizeof(CVertex), + (char*)m_aVertices); + glTexCoordPointer(2, GL_FLOAT, + sizeof(CVertex), + (char*)m_aVertices + sizeof(float)*3); + glColorPointer(4, GL_FLOAT, + sizeof(CVertex), + (char*)m_aVertices + sizeof(float)*5); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + if(m_RenderEnable) + { + if(m_Drawing == DRAWING_QUADS) + glDrawArrays(GL_QUADS, 0, m_NumVertices); + else if(m_Drawing == DRAWING_LINES) + glDrawArrays(GL_LINES, 0, m_NumVertices); + } + + /* Reset pointer */ + m_NumVertices = 0; + } + + void AddVertices(int count) + { + m_NumVertices += count; + if((m_NumVertices + count) >= MAX_VERTICES) + Flush(); + } + + void Rotate(CPoint *pCenter, CPoint *pPoint) + { + float x = pPoint->x - pCenter->x; + float y = pPoint->y - pCenter->y; + pPoint->x = x * cosf(m_Rotation) - y * sinf(m_Rotation) + pCenter->x; + pPoint->y = x * sinf(m_Rotation) + y * cosf(m_Rotation) + pCenter->y; + } + + + + + static unsigned char sample(int w, int h, const unsigned char *data, int u, int v, int offset) + { + return (data[(v*w+u)*4+offset]+ + data[(v*w+u+1)*4+offset]+ + data[((v+1)*w+u)*4+offset]+ + data[((v+1)*w+u+1)*4+offset])/4; + } +public: + CGraphics_OpenGL() + { + m_NumVertices = 0; + + m_ScreenX0 = 0; + m_ScreenY0 = 0; + m_ScreenX1 = 0; + m_ScreenY1 = 0; + + m_ScreenWidth = -1; + m_ScreenHeight = -1; + + m_Rotation = 0; + m_Drawing = 0; + m_InvalidTexture = 0; + + m_TextureMemoryUsage = 0; + + m_RenderEnable = true; + m_DoScreenshot = false; + } + + + virtual void ClipEnable(int x, int y, int w, int h) + { + //if(no_gfx) return; + glScissor(x, ScreenHeight()-(y+h), w, h); + glEnable(GL_SCISSOR_TEST); + } + + virtual void ClipDisable() + { + //if(no_gfx) return; + glDisable(GL_SCISSOR_TEST); + } + + + virtual void BlendNone() + { + glDisable(GL_BLEND); + } + + virtual void BlendNormal() + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + virtual void BlendAdditive() + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } + + //int gfx_memory_usage() { return m_MemoryUsage; } + + virtual void MapScreen(float tl_x, float tl_y, float br_x, float br_y) + { + m_ScreenX0 = tl_x; + m_ScreenY0 = tl_y; + m_ScreenX1 = br_x; + m_ScreenY1 = br_y; + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(tl_x, br_x, br_y, tl_y, 1.0f, 10.f); + } + + virtual void GetScreen(float *tl_x, float *tl_y, float *br_x, float *br_y) + { + *tl_x = m_ScreenX0; + *tl_y = m_ScreenY0; + *br_x = m_ScreenX1; + *br_y = m_ScreenY1; + } + + virtual void LinesBegin() + { + dbg_assert(m_Drawing == 0, "called begin twice"); + m_Drawing = DRAWING_LINES; + SetColor(1,1,1,1); + } + + virtual void LinesEnd() + { + dbg_assert(m_Drawing == DRAWING_LINES, "called end without begin"); + Flush(); + m_Drawing = 0; + } + + virtual void LinesDraw(float x0, float y0, float x1, float y1) + { + dbg_assert(m_Drawing == DRAWING_LINES, "called draw without begin"); + + m_aVertices[m_NumVertices].m_Pos.x = x0; + m_aVertices[m_NumVertices].m_Pos.y = y0; + m_aVertices[m_NumVertices].m_Tex = m_aTexture[0]; + m_aVertices[m_NumVertices].m_Color = m_aColor[0]; + + m_aVertices[m_NumVertices + 1].m_Pos.x = x1; + m_aVertices[m_NumVertices + 1].m_Pos.y = y1; + m_aVertices[m_NumVertices + 1].m_Tex = m_aTexture[1]; + m_aVertices[m_NumVertices + 1].m_Color = m_aColor[1]; + + AddVertices(2); + } + + + + virtual int UnloadTexture(int Index) + { + if(Index == m_InvalidTexture) + return 0; + + if(Index < 0) + return 0; + + glDeleteTextures(1, &m_aTextures[Index].tex); + m_aTextures[Index].next = m_FirstFreeTexture; + m_TextureMemoryUsage -= m_aTextures[Index].memsize; + m_FirstFreeTexture = Index; + return 0; + } + + + virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags) + { + int mipmap = 1; + unsigned char *texdata = (unsigned char *)pData; + unsigned char *tmpdata = 0; + int oglformat = 0; + int store_oglformat = 0; + int tex = 0; + + /* don't waste memory on texture if we are stress testing */ + if(config.dbg_stress) + return m_InvalidTexture; + + /* grab texture */ + tex = m_FirstFreeTexture; + m_FirstFreeTexture = m_aTextures[tex].next; + m_aTextures[tex].next = -1; + + /* resample if needed */ + if(!(Flags&TEXLOAD_NORESAMPLE) && config.gfx_texture_quality==0) + { + if(Width > 16 && Height > 16 && Format == IMG_RGBA) + { + unsigned char *tmpdata; + int c = 0; + int x, y; + + tmpdata = (unsigned char *)mem_alloc(Width*Height*4, 1); + + Width/=2; + Height/=2; + + for(y = 0; y < Height; y++) + for(x = 0; x < Width; x++, c++) + { + tmpdata[c*4] = sample(Width*2, Height*2, texdata, x*2,y*2, 0); + tmpdata[c*4+1] = sample(Width*2, Height*2, texdata, x*2,y*2, 1); + tmpdata[c*4+2] = sample(Width*2, Height*2, texdata, x*2,y*2, 2); + tmpdata[c*4+3] = sample(Width*2, Height*2, texdata, x*2,y*2, 3); + } + texdata = tmpdata; + } + } + + oglformat = GL_RGBA; + if(Format == IMG_RGB) + oglformat = GL_RGB; + else if(Format == IMG_ALPHA) + oglformat = GL_ALPHA; + + /* upload texture */ + if(config.gfx_texture_compression) + { + store_oglformat = GL_COMPRESSED_RGBA_ARB; + if(StoreFormat == IMG_RGB) + store_oglformat = GL_COMPRESSED_RGB_ARB; + else if(StoreFormat == IMG_ALPHA) + store_oglformat = GL_COMPRESSED_ALPHA_ARB; + } + else + { + store_oglformat = GL_RGBA; + if(StoreFormat == IMG_RGB) + store_oglformat = GL_RGB; + else if(StoreFormat == IMG_ALPHA) + store_oglformat = GL_ALPHA; + } + + glGenTextures(1, &m_aTextures[tex].tex); + glBindTexture(GL_TEXTURE_2D, m_aTextures[tex].tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + gluBuild2DMipmaps(GL_TEXTURE_2D, store_oglformat, Width, Height, oglformat, GL_UNSIGNED_BYTE, texdata); + + /* calculate memory usage */ + { + int pixel_size = 4; + if(StoreFormat == IMG_RGB) + pixel_size = 3; + else if(StoreFormat == IMG_ALPHA) + pixel_size = 1; + + m_aTextures[tex].memsize = Width*Height*pixel_size; + if(mipmap) + { + while(Width > 2 && Height > 2) + { + Width>>=1; + Height>>=1; + m_aTextures[tex].memsize += Width*Height*pixel_size; + } + } + } + + m_TextureMemoryUsage += m_aTextures[tex].memsize; + mem_free(tmpdata); + return tex; + } + + /* simple uncompressed RGBA loaders */ + virtual int LoadTexture(const char *pFilename, int StoreFormat, int Flags) + { + int l = strlen(pFilename); + int id; + IMAGE_INFO img; + + if(l < 3) + return -1; + if(LoadPNG(&img, pFilename)) + { + if (StoreFormat == IMG_AUTO) + StoreFormat = img.format; + + id = LoadTextureRaw(img.width, img.height, img.format, img.data, StoreFormat, Flags); + mem_free(img.data); + return id; + } + + return m_InvalidTexture; + } + + virtual int LoadPNG(IMAGE_INFO *pImg, const char *pFilename) + { + char aCompleteFilename[512]; + unsigned char *pBuffer; + png_t png; + + /* open file for reading */ + png_init(0,0); + + engine_getpath(aCompleteFilename, sizeof(aCompleteFilename), pFilename, IOFLAG_READ); + + if(png_open_file(&png, aCompleteFilename) != PNG_NO_ERROR) + { + dbg_msg("game/png", "failed to open file. filename='%s'", aCompleteFilename); + return 0; + } + + if(png.depth != 8 || (png.color_type != PNG_TRUECOLOR && png.color_type != PNG_TRUECOLOR_ALPHA)) + { + dbg_msg("game/png", "invalid format. filename='%s'", aCompleteFilename); + png_close_file(&png); + return 0; + } + + pBuffer = (unsigned char *)mem_alloc(png.width * png.height * png.bpp, 1); + png_get_data(&png, pBuffer); + png_close_file(&png); + + pImg->width = png.width; + pImg->height = png.height; + if(png.color_type == PNG_TRUECOLOR) + pImg->format = IMG_RGB; + else if(png.color_type == PNG_TRUECOLOR_ALPHA) + pImg->format = IMG_RGBA; + pImg->data = pBuffer; + return 1; + } + + void ScreenshotDirect(const char *filename) + { + /* fetch image data */ + int y; + int w = m_ScreenWidth; + int h = m_ScreenHeight; + unsigned char *pixel_data = (unsigned char *)mem_alloc(w*(h+1)*4, 1); + unsigned char *temp_row = pixel_data+w*h*4; + glReadPixels(0,0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data); + + /* flip the pixel because opengl works from bottom left corner */ + for(y = 0; y < h/2; y++) + { + mem_copy(temp_row, pixel_data+y*w*4, w*4); + mem_copy(pixel_data+y*w*4, pixel_data+(h-y-1)*w*4, w*4); + mem_copy(pixel_data+(h-y-1)*w*4, temp_row,w*4); + } + + /* find filename */ + { + char wholepath[1024]; + png_t png; + + engine_savepath(filename, wholepath, sizeof(wholepath)); + + /* save png */ + dbg_msg("client", "saved screenshot to '%s'", wholepath); + png_open_file_write(&png, wholepath); + png_set_data(&png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pixel_data); + png_close_file(&png); + } + + /* clean up */ + mem_free(pixel_data); + } + + virtual void TextureSet(int TextureID) + { + dbg_assert(m_Drawing == 0, "called Graphics()->TextureSet within begin"); + if(TextureID == -1) + { + glDisable(GL_TEXTURE_2D); + } + else + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_aTextures[TextureID].tex); + } + } + + virtual void Clear(float r, float g, float b) + { + glClearColor(r,g,b,0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + virtual void QuadsBegin() + { + dbg_assert(m_Drawing == 0, "called quads_begin twice"); + m_Drawing = DRAWING_QUADS; + + QuadsSetSubset(0,0,1,1); + QuadsSetRotation(0); + SetColor(1,1,1,1); + } + + virtual void QuadsEnd() + { + dbg_assert(m_Drawing == DRAWING_QUADS, "called quads_end without begin"); + Flush(); + m_Drawing = 0; + } + + virtual void QuadsSetRotation(float Angle) + { + dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetRotation without begin"); + m_Rotation = Angle; + } + + virtual void SetColorVertex(int i, float r, float g, float b, float a) + { + dbg_assert(m_Drawing != 0, "called gfx_quads_setcolorvertex without begin"); + m_aColor[i].r = r; + m_aColor[i].g = g; + m_aColor[i].b = b; + m_aColor[i].a = a; + } + + virtual void SetColor(float r, float g, float b, float a) + { + dbg_assert(m_Drawing != 0, "called gfx_quads_setcolor without begin"); + SetColorVertex(0, r, g, b, a); + SetColorVertex(1, r, g, b, a); + SetColorVertex(2, r, g, b, a); + SetColorVertex(3, r, g, b, a); + } + + virtual void QuadsSetSubset(float tl_u, float tl_v, float br_u, float br_v) + { + dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetSubset without begin"); + + m_aTexture[0].u = tl_u; m_aTexture[1].u = br_u; + m_aTexture[0].v = tl_v; m_aTexture[1].v = tl_v; + + m_aTexture[3].u = tl_u; m_aTexture[2].u = br_u; + m_aTexture[3].v = br_v; m_aTexture[2].v = br_v; + } + + virtual void QuadsSetSubsetFree( + float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3) + { + m_aTexture[0].u = x0; m_aTexture[0].v = y0; + m_aTexture[1].u = x1; m_aTexture[1].v = y1; + m_aTexture[2].u = x2; m_aTexture[2].v = y2; + m_aTexture[3].u = x3; m_aTexture[3].v = y3; + } + + virtual void QuadsDraw(float x, float y, float w, float h) + { + QuadsDrawTL(x-w/2, y-h/2,w,h); + } + + virtual void QuadsDrawTL(float x, float y, float w, float h) + { + CPoint Center; + + dbg_assert(m_Drawing == DRAWING_QUADS, "called quads_draw without begin"); + + Center.x = x + w/2; + Center.y = y + h/2; + Center.z = 0; + + m_aVertices[m_NumVertices].m_Pos.x = x; + m_aVertices[m_NumVertices].m_Pos.y = y; + m_aVertices[m_NumVertices].m_Tex = m_aTexture[0]; + m_aVertices[m_NumVertices].m_Color = m_aColor[0]; + Rotate(&Center, &m_aVertices[m_NumVertices].m_Pos); + + m_aVertices[m_NumVertices + 1].m_Pos.x = x+w; + m_aVertices[m_NumVertices + 1].m_Pos.y = y; + m_aVertices[m_NumVertices + 1].m_Tex = m_aTexture[1]; + m_aVertices[m_NumVertices + 1].m_Color = m_aColor[1]; + Rotate(&Center, &m_aVertices[m_NumVertices + 1].m_Pos); + + m_aVertices[m_NumVertices + 2].m_Pos.x = x + w; + m_aVertices[m_NumVertices + 2].m_Pos.y = y+h; + m_aVertices[m_NumVertices + 2].m_Tex = m_aTexture[2]; + m_aVertices[m_NumVertices + 2].m_Color = m_aColor[2]; + Rotate(&Center, &m_aVertices[m_NumVertices + 2].m_Pos); + + m_aVertices[m_NumVertices + 3].m_Pos.x = x; + m_aVertices[m_NumVertices + 3].m_Pos.y = y+h; + m_aVertices[m_NumVertices + 3].m_Tex = m_aTexture[3]; + m_aVertices[m_NumVertices + 3].m_Color = m_aColor[3]; + Rotate(&Center, &m_aVertices[m_NumVertices + 3].m_Pos); + + AddVertices(4); + } + + void QuadsDrawFreeform( + float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3) + { + dbg_assert(m_Drawing == DRAWING_QUADS, "called quads_draw_freeform without begin"); + + m_aVertices[m_NumVertices].m_Pos.x = x0; + m_aVertices[m_NumVertices].m_Pos.y = y0; + m_aVertices[m_NumVertices].m_Tex = m_aTexture[0]; + m_aVertices[m_NumVertices].m_Color = m_aColor[0]; + + m_aVertices[m_NumVertices + 1].m_Pos.x = x1; + m_aVertices[m_NumVertices + 1].m_Pos.y = y1; + m_aVertices[m_NumVertices + 1].m_Tex = m_aTexture[1]; + m_aVertices[m_NumVertices + 1].m_Color = m_aColor[1]; + + m_aVertices[m_NumVertices + 2].m_Pos.x = x3; + m_aVertices[m_NumVertices + 2].m_Pos.y = y3; + m_aVertices[m_NumVertices + 2].m_Tex = m_aTexture[3]; + m_aVertices[m_NumVertices + 2].m_Color = m_aColor[3]; + + m_aVertices[m_NumVertices + 3].m_Pos.x = x2; + m_aVertices[m_NumVertices + 3].m_Pos.y = y2; + m_aVertices[m_NumVertices + 3].m_Tex = m_aTexture[2]; + m_aVertices[m_NumVertices + 3].m_Color = m_aColor[2]; + + AddVertices(4); + } + + virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText) + { + float startx = x; + + QuadsBegin(); + SetColor(r,g,b,a); + + while(*pText) + { + char c = *pText; + pText++; + + if(c == '\n') + { + x = startx; + y += Size; + } + else + { + QuadsSetSubset( + (c%16)/16.0f, + (c/16)/16.0f, + (c%16)/16.0f+1.0f/16.0f, + (c/16)/16.0f+1.0f/16.0f); + + QuadsDrawTL(x,y,Size,Size); + x += Size/2; + } + } + + QuadsEnd(); + } + + virtual bool Init() + { + /* Set all z to -5.0f */ + for(int i = 0; i < MAX_VERTICES; i++) + m_aVertices[i].m_Pos.z = -5.0f; + + /* init textures */ + m_FirstFreeTexture = 0; + for(int i = 0; i < MAX_TEXTURES; i++) + m_aTextures[i].next = i+1; + m_aTextures[MAX_TEXTURES-1].next = -1; + + /* set some default settings */ + glEnable(GL_BLEND); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glAlphaFunc(GL_GREATER, 0); + glEnable(GL_ALPHA_TEST); + glDepthMask(0); + + /* create null texture, will get id=0 */ + static const unsigned char aNullTextureData[] = { + 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, + 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, + }; + + m_InvalidTexture = LoadTextureRaw(4,4,IMG_RGBA,aNullTextureData,IMG_RGBA,TEXLOAD_NORESAMPLE); + dbg_msg("", "invalid texture id: %d %d", m_InvalidTexture, m_aTextures[m_InvalidTexture].tex); + + return true; + } +}; + +class CGraphics_SDL : public CGraphics_OpenGL +{ + SDL_Surface *m_pScreenSurface; + + int TryInit() + { + const SDL_VideoInfo *pInfo; + int Flags = SDL_OPENGL; + + m_ScreenWidth = config.gfx_screen_width; + m_ScreenHeight = config.gfx_screen_height; + + pInfo = SDL_GetVideoInfo(); + + /* set flags */ + Flags = SDL_OPENGL; + Flags |= SDL_GL_DOUBLEBUFFER; + Flags |= SDL_HWPALETTE; + if(config.dbg_resizable) + Flags |= SDL_RESIZABLE; + + if(pInfo->hw_available) + Flags |= SDL_HWSURFACE; + else + Flags |= SDL_SWSURFACE; + + if(pInfo->blit_hw) + Flags |= SDL_HWACCEL; + + if(config.gfx_fullscreen) + Flags |= SDL_FULLSCREEN; + + /* set gl attributes */ + if(config.gfx_fsaa_samples) + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, config.gfx_fsaa_samples); + } + else + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + } + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, config.gfx_vsync); + + /* set caption */ + SDL_WM_SetCaption("Teeworlds", "Teeworlds"); + + /* create window */ + m_pScreenSurface = SDL_SetVideoMode(m_ScreenWidth, m_ScreenHeight, 0, Flags); + if(m_pScreenSurface == NULL) + { + dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); + return -1; + } + + return 0; + } + + + int InitWindow() + { + if(TryInit() == 0) + return 0; + + /* try disabling fsaa */ + while(config.gfx_fsaa_samples) + { + config.gfx_fsaa_samples--; + + if(config.gfx_fsaa_samples) + dbg_msg("gfx", "lowering FSAA to %d and trying again", config.gfx_fsaa_samples); + else + dbg_msg("gfx", "disabling FSAA and trying again"); + + if(TryInit() == 0) + return 0; + } + + /* try lowering the resolution */ + if(config.gfx_screen_width != 640 || config.gfx_screen_height != 480) + { + dbg_msg("gfx", "setting resolution to 640x480 and trying again"); + config.gfx_screen_width = 640; + config.gfx_screen_height = 480; + + if(TryInit() == 0) + return 0; + } + + dbg_msg("gfx", "out of ideas. failed to init graphics"); + + return -1; + } + + +public: + CGraphics_SDL() + { + m_pScreenSurface = 0; + } + + virtual bool Init() + { + { + int Systems = SDL_INIT_VIDEO; + + if(config.snd_enable) + Systems |= SDL_INIT_AUDIO; + + if(config.cl_eventthread) + Systems |= SDL_INIT_EVENTTHREAD; + + if(SDL_Init(Systems) < 0) + { + dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError()); + return -1; + } + } + + atexit(SDL_Quit); + + #ifdef CONF_FAMILY_WINDOWS + if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) + putenv("SDL_VIDEO_WINDOW_POS=8,27"); + #endif + + if(InitWindow() != 0) + return -1; + + SDL_ShowCursor(0); + + CGraphics_OpenGL::Init(); + + MapScreen(0,0,config.gfx_screen_width, config.gfx_screen_height); + + /* init input */ + inp_init(); + + /* font init */ + gfx_font_init(); + + return 0; + } + + virtual void Shutdown() + { + /* TODO: SDL, is this correct? */ + SDL_Quit(); + } + + virtual void Minimize() + { + SDL_WM_IconifyWindow(); + } + + virtual void Maximize() + { + /* TODO: SDL */ + } + + virtual int WindowActive() + { + return SDL_GetAppState()&SDL_APPINPUTFOCUS; + } + + virtual int WindowOpen() + { + return SDL_GetAppState()&SDL_APPACTIVE; + + } + + virtual void TakeScreenshot() + { + m_DoScreenshot = true; + } + + virtual void Swap() + { + if(m_DoScreenshot) + { + /* find filename */ + char filename[128]; + static int index = 1; + + for(; index < 1000; index++) + { + IOHANDLE io; + str_format(filename, sizeof(filename), "screenshots/screenshot%04d.png", index); + io = engine_openfile(filename, IOFLAG_READ); + if(io) + io_close(io); + else + break; + } + + ScreenshotDirect(filename); + m_DoScreenshot = false; + } + + { + static PERFORMACE_INFO pscope = {"glfwSwapBuffers", 0}; + perf_start(&pscope); + SDL_GL_SwapBuffers(); + perf_end(); + } + + if(config.gfx_finish) + glFinish(); + } +}; + +extern IEngineGraphics *CreateEngineGraphics() { return new CGraphics_SDL(); } |