00001 #include <SDL/SDL.h>
00002 #include <SDL/SDL_image.h>
00003 #include <string.h>
00004 #include <iostream>
00005
00006 #include "application.h"
00007 #include "graphics.h"
00008 #include "util.h"
00009
00010 Graphics::Graphics(string title, int w, int h, bool opengl)
00011 {
00012 #ifdef DEBUG
00013 cerr << "Window title: " << title << " (" << w << ", " << h << ")" << endl;
00014 #endif
00015 if(w < 320)
00016 width = 320;
00017 else
00018 width = w;
00019
00020 if(h < 240)
00021 height = 240;
00022 else
00023 height = h;
00024
00025 int flags = SDL_HWSURFACE | SDL_DOUBLEBUF;
00026 if (opengl)
00027 flags |= SDL_OPENGL;
00028
00029 hwSurface = new Surface;
00030
00031 SDL_InitSubSystem(SDL_INIT_VIDEO);
00032
00033 if (opengl)
00034 PreOpenGLInit();
00035
00036 hwSurface->surface = SDL_SetVideoMode(width, height, 16, flags);
00037
00038 hwSurface->w = hwSurface->surface->w;
00039 hwSurface->h = hwSurface->surface->h;
00040
00041 SDL_WM_SetCaption (title.c_str(), title.c_str());
00042
00043 if (opengl)
00044 PostOpenGLInit();
00045 }
00046
00047 Graphics::~Graphics()
00048 {
00049 SDL_FreeSurface(hwSurface->surface);
00050 delete hwSurface;
00051
00052 SDL_QuitSubSystem(SDL_INIT_VIDEO);
00053 }
00054
00055 void Graphics::PreOpenGLInit()
00056 {
00057 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
00058 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
00059 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
00060 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
00061
00062 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, SDL_DOUBLEBUF);
00063 }
00064
00065
00066 void Graphics::PostOpenGLInit()
00067 {
00068 GLint maxtexsize;
00069 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize);
00070
00071 cout << "Maximum texture size is " << maxtexsize << 'x' << maxtexsize << endl;
00072
00073 glDisable(GL_DEPTH_TEST);
00074 glDisable(GL_CULL_FACE);
00075
00076 glViewport (0, 0, hwSurface->w, hwSurface->h);
00077 glMatrixMode(GL_PROJECTION);
00078 glLoadIdentity();
00079 glOrtho (0, hwSurface->w, hwSurface->h, 0, -10.0, 10.0);
00080 glMatrixMode(GL_MODELVIEW);
00081 glLoadIdentity();
00082 glTranslatef(0.0f, 0.0f, 0.0f);
00083
00084 glEnable (GL_BLEND);
00085 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00086 glEnable (GL_TEXTURE_2D);
00087
00088 return;
00089 }
00090
00091
00092 void
00093 Graphics::update(int x, int y, int w, int h)
00094 {
00096 if (hwSurface->surface->flags & SDL_OPENGL)
00097 return;
00098
00099 if(hwSurface && hwSurface->surface) {
00100
00101 if(x < 0) {
00102 w += x;
00103 x = 0;
00104 }
00105
00106
00107 if(x >= width)
00108 return;
00109
00110
00111 if(y < 0) {
00112 h += y;
00113 y = 0;
00114 }
00115
00116 if(y >= height)
00117 return;
00118
00119
00120 if((x+w) >= width)
00121 w = (width - x);
00122
00123
00124 if((y+h) >= height)
00125 h = (height - y);
00126
00127
00128 if(w <= 0 || h <= 0)
00129 return;
00130
00131 SDL_UpdateRect(hwSurface->surface, x, y, w, h);
00132 }
00133 }
00134
00135 void Graphics::update(Rect &r)
00136 {
00137
00139
00140 return;
00141
00142 update(r.x, r.y, r.w, r.h);
00143 }
00144
00145 void Graphics::blitGLtexture (Surface *src, int srx, int sry, int srw, int srh,
00146 int drx, int dry, int drw, int drh)
00147 {
00148 float width = (float)src->w / (float)src->ts;
00149 float height = (float)src->h / (float)src->ts;
00150
00151 glBindTexture (GL_TEXTURE_2D, src->tex);
00152 glBegin(GL_QUADS);
00153 glTexCoord2f (0, 0); glVertex2i (drx, dry);
00154 glTexCoord2f (width, 0); glVertex2i (drx + srw, dry);
00155 glTexCoord2f (width, height); glVertex2i (drx + srw, dry + srh);
00156 glTexCoord2f (0, height); glVertex2i (drx, dry + srh);
00157 glEnd();
00158 }
00159
00160
00161
00162
00163
00164 void Graphics::blitclip(Surface *dest, int drx, int dry, int drw, int drh,
00165 Surface *src, int srx, int sry, int srw, int srh)
00166 {
00168 if (dest && dest->surface && (dest->surface->flags & SDL_OPENGL)) {
00169 blitGLtexture(src, srx, sry, srw, srh, drx, dry, drw, drh);
00170 return;
00171 }
00172
00173
00174 if ( (drx + drw) >= dest->w ) {
00175 int offs = (drx + drw) - dest->w;
00176 drw -= offs;
00177 srw -= offs;
00178 }
00179
00180
00181 if ( (dry + drh) >= dest->h ) {
00182 int offs = (dry + drh) - dest->h;
00183 drh -= offs;
00184 srh -= offs;
00185 }
00186
00187 if ( drx < 0 ) {
00188 int offs = -drx;
00189 drx = 0;
00190 drw -= offs;
00191 if (drw <= 0)
00192 return;
00193
00194 srx += offs;
00195 srw -= offs;
00196 }
00197
00198 if ( dry < 0 ) {
00199 int offs = -dry;
00200 dry = 0;
00201 drh -= offs;
00202 if (drh <= 0)
00203 return;
00204
00205 sry += offs;
00206 srh -= offs;
00207 }
00208
00209 if ( (srx >= src->w) || (sry >= src->h) )
00210 return;
00211
00212
00213 if ( (srw <= 0) || (srh <= 0) || (drw <= 0) || (drh <= 0) )
00214 return;
00215
00216 Rect srcrect = Util_BuildRect(srx, sry, srw, srh);
00217 Rect dstrect = Util_BuildRect(drx, dry, drw, drh);
00218
00219 SDL_LowerBlit(src->surface, &srcrect, dest->surface, &dstrect);
00220 }
00221
00222 void
00223 Graphics::blit(Surface *src, int dx, int dy)
00224 {
00225 blit(hwSurface, dx, dy, src);
00226 return;
00227 }
00228
00229 void
00230 Graphics::blit(Surface *target, int tx, int ty, Surface *src)
00231 {
00232
00233
00234 if (!target || !src || tx >= (signed int)target->w || ty >= (signed int)target->h)
00235 return;
00236
00237
00238 blitclip (target, tx, ty, src->w, src->h,
00239 src, 0, 0, src->w, src->h);
00240 }
00241
00242 void
00243 Graphics::blit(Surface *target, Rect &t, Surface *src, Rect &s)
00244 {
00245 if(t.x == t.y && t.y == -9999)
00246 return;
00247
00248 if(target && src) {
00249 blitclip (target, t.x, t.y, t.w, t.h,
00250 src, s.x, s.y, s.w, s.h);
00251 }
00252 }
00253
00254 Surface *
00255 Graphics::newSurface(int w, int h)
00256 {
00257 if(w < 1 || h < 1) return (Surface *) NULL;
00258
00259 Surface *n = new Surface;
00260 n->surface = SDL_CreateRGBSurface (SDL_SWSURFACE, w, h, 32,
00261 hwSurface->surface->format->Rmask,
00262 hwSurface->surface->format->Gmask,
00263 hwSurface->surface->format->Bmask,
00264 hwSurface->surface->format->Amask);
00265
00266 if(n) {
00267 n->w = w;
00268 n->h = h;
00269 return n;
00270 }
00271
00272 cout << SDL_GetError() << endl;
00273
00274 return (Surface *) NULL;
00275 }
00276
00277 Surface *
00278 Graphics::CreateSurfaceFrom(Surface *s)
00279 {
00280 if (!s)
00281 return (Surface *) NULL;
00282
00283 Surface *n = new Surface;
00284 n->surface = SDL_CreateRGBSurfaceFrom(s->surface->pixels, s->surface->w,
00285 s->surface->h, s->surface->format->BitsPerPixel,
00286 s->surface->pitch, s->surface->format->Rmask,
00287 s->surface->format->Gmask, s->surface->format->Bmask,
00288 s->surface->format->Amask);
00289
00290 if(n) {
00291 n->w = n->surface->w;
00292 n->h = n->surface->h;
00293 return n;
00294 }
00295
00296 cout << __LINE__ << ": " << SDL_GetError() << endl;
00297 return (Surface *) NULL;
00298 }
00299
00300 Surface *
00301 Graphics::CreateSurfaceFrom(Surface *s, int nw, int nh)
00302 {
00303 if (!s)
00304 return (Surface *) NULL;
00305
00306 Surface *n = new Surface;
00307 n->surface = SDL_CreateRGBSurface(s->surface->flags, nw, nh,
00308 s->surface->format->BitsPerPixel,
00309 s->surface->format->Rmask,
00310 s->surface->format->Gmask,
00311 s->surface->format->Bmask,
00312 s->surface->format->Amask);
00313 if(n) {
00314 n->w = n->surface->w;
00315 n->h = n->surface->h;
00316 return n;
00317 }
00318
00319 cout << __LINE__ << ": " << SDL_GetError() << endl;
00320 return (Surface *) NULL;
00321 }
00322
00323 void Graphics::deleteSurface(Surface *n)
00324 {
00325 SDL_FreeSurface(n->surface);
00326 delete n;
00327 }
00328
00329 void Graphics::fillSurface(Surface *n, int color)
00330 {
00331 SDL_FillRect(n->surface, NULL, color);
00332 }
00333
00334 int Graphics::color(int r, int g, int b, Surface * n)
00335 {
00336 if(n) {
00337 return SDL_MapRGB(n->surface->format, r, g, b);
00338 } else {
00339 return SDL_MapRGB(hwSurface->surface->format, r, g, b);
00340 }
00341 }
00342
00343 Surface *
00344 Graphics::loadImage(const char *fname)
00345 {
00346 if(!fname) return (Surface *)NULL;
00347
00348 Surface *n = new Surface;
00349 n->surface = IMG_Load(fname);
00350 if (!n) cout << SDL_GetError() << endl;
00351 n->w = n->surface->w;
00352 n->h = n->surface->h;
00353 return n;
00354 }
00355
00356 Surface *
00357 Graphics::loadImage(string fname)
00358 {
00359 return Graphics::loadImage(fname.c_str());
00360 }
00361
00362 Surface *
00363 Graphics::freeImage(Surface *surf)
00364 {
00365 if(surf) {
00366 SDL_FreeSurface (surf->surface);
00367 delete surf;
00368 }
00369 return NULL;
00370 }
00371
00372 Surface *Graphics::displayFormat(Surface *surf, bool alpha)
00373 {
00374 if (alpha) {
00375 Surface *n = new Surface;
00376 n->surface = SDL_DisplayFormatAlpha(surf->surface);
00377 n->w = surf->w;
00378 n->h = surf->h;
00379 return n;
00380 }
00381
00382 Surface *n = new Surface;
00383 n->surface = SDL_DisplayFormat(surf->surface);
00384 n->w = surf->w;
00385 n->h = surf->h;
00386 return n;
00387 }
00388
00389 bool Graphics::lockMouse(bool lock)
00390 {
00391 return (SDL_WM_GrabInput( (lock) ? SDL_GRAB_ON : SDL_GRAB_OFF ) == SDL_GRAB_ON);
00392 }
00393
00394 void Graphics::flip()
00395 {
00396 if (!hwSurface || !hwSurface->surface)
00397 return;
00398
00399 if (hwSurface->surface->flags & SDL_OPENGL) {
00400 GLint err = glGetError();
00401 if (err != GL_NO_ERROR) {
00402 cerr << "OpenGL error " << err << endl;
00403 err = glGetError();
00404 }
00405
00406 SDL_GL_SwapBuffers();
00407 glClear (GL_COLOR_BUFFER_BIT);
00408 } else {
00409 SDL_Flip(hwSurface->surface);
00410 }
00411 }
00412
00413 void Graphics::TexturizeSurface (Surface *s)
00414 {
00415 int size = Util_FindBestSurfaceSize (s->w, s->h);
00416
00417 Surface temp;
00418
00419 SDL_SetAlpha (s->surface, 0, 0);
00420
00421 temp.surface = SDL_AllocSurface (SDL_SWSURFACE, size, size, 32,
00422 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
00423
00424 SDL_BlitSurface (s->surface, NULL, temp.surface, NULL);
00425 SDL_FreeSurface (s->surface);
00426 s->surface = (SDL_Surface *) NULL;
00427
00428 glGenTextures (1, &(s->tex));
00429 glBindTexture(GL_TEXTURE_2D, s->tex);
00430 glPixelStorei(GL_UNPACK_ROW_LENGTH, temp.surface->pitch / temp.surface->format->BytesPerPixel);
00431 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00432 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00433 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, temp.surface->w, temp.surface->h, 0, GL_RGBA,
00434 GL_UNSIGNED_BYTE, temp.surface->pixels);
00435 glFlush();
00436
00437 SDL_FreeSurface (temp.surface);
00438
00439 s->tx = s->ty = 0;
00440 s->ts = size;
00441 }
00442
00443 void Graphics::UntexturizeSurface (Surface *s)
00444 {
00445 if (!s || !(s->tex >= 0))
00446 return;
00447
00448 glDeleteTextures(1, &s->tex);
00449 }
00450
00451 void Graphics::RotateZ (float degrees)
00452 {
00453 glLoadIdentity();
00454 glTranslatef (getWidth()/2, getHeight()/2, 0);
00455 glRotatef (degrees, 0.0, 0.0, 1.0);
00456 glTranslatef (getWidth()/-2, getHeight()/-2, 0);
00457 }
00458