00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <SDL.h>
00023
00024 #include "log.h"
00025 #include "openglgraphics.h"
00026
00027 #include "resources/image.h"
00028
00029 #ifdef USE_OPENGL
00030
00031 #ifdef __APPLE__
00032 #include <OpenGL/OpenGL.h>
00033 #endif
00034
00035 #ifndef GL_TEXTURE_RECTANGLE_ARB
00036 #define GL_TEXTURE_RECTANGLE_ARB 0x84F5
00037 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
00038 #endif
00039
00040 OpenGLGraphics::OpenGLGraphics():
00041 mAlpha(false), mTexture(false), mColorAlpha(false),
00042 mSync(false)
00043 {
00044 }
00045
00046 OpenGLGraphics::~OpenGLGraphics()
00047 {
00048 }
00049
00050 void OpenGLGraphics::setSync(bool sync)
00051 {
00052 mSync = sync;
00053 }
00054
00055 bool OpenGLGraphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
00056 {
00057 logger->log("Setting video mode %dx%d %s",
00058 w, h, fs ? "fullscreen" : "windowed");
00059
00060 int displayFlags = SDL_ANYFORMAT | SDL_OPENGL;
00061
00062 mFullscreen = fs;
00063 mHWAccel = hwaccel;
00064
00065 if (fs)
00066 displayFlags |= SDL_FULLSCREEN;
00067
00068 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
00069
00070 if (!(mScreen = SDL_SetVideoMode(w, h, bpp, displayFlags)))
00071 return false;
00072
00073 #ifdef __APPLE__
00074 if (mSync)
00075 {
00076 const GLint VBL = 1;
00077 CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL);
00078 }
00079 #endif
00080
00081
00082 glViewport(0, 0, w, h);
00083 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
00084 int gotDoubleBuffer;
00085 SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &gotDoubleBuffer);
00086 logger->log("Using OpenGL %s double buffering.",
00087 (gotDoubleBuffer ? "with" : "without"));
00088
00089 char const *glExtensions = (char const *)glGetString(GL_EXTENSIONS);
00090 GLint texSize;
00091 bool rectTex = strstr(glExtensions, "GL_ARB_texture_rectangle");
00092 if (rectTex)
00093 {
00094 Image::mTextureType = GL_TEXTURE_RECTANGLE_ARB;
00095 glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &texSize);
00096 }
00097 else
00098 {
00099 Image::mTextureType = GL_TEXTURE_2D;
00100 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
00101 }
00102 Image::mTextureSize = texSize;
00103 logger->log("OpenGL texture size: %d pixels%s", Image::mTextureSize,
00104 rectTex ? " (rectangle textures)" : "");
00105
00106 return true;
00107 }
00108
00109 static inline void drawQuad(Image *image,
00110 int srcX, int srcY, int dstX, int dstY,
00111 int width, int height)
00112 {
00113 if (image->getTextureType() == GL_TEXTURE_2D)
00114 {
00115
00116 float texX1 = srcX / (float) image->getTextureWidth();
00117 float texY1 = srcY / (float) image->getTextureHeight();
00118 float texX2 = (srcX + width) / (float) image->getTextureWidth();
00119 float texY2 = (srcY + height) / (float) image->getTextureHeight();
00120
00121 glTexCoord2f(texX1, texY1);
00122 glVertex2i(dstX, dstY);
00123 glTexCoord2f(texX2, texY1);
00124 glVertex2i(dstX + width, dstY);
00125 glTexCoord2f(texX2, texY2);
00126 glVertex2i(dstX + width, dstY + height);
00127 glTexCoord2f(texX1, texY2);
00128 glVertex2i(dstX, dstY + height);
00129 }
00130 else
00131 {
00132 glTexCoord2i(srcX, srcY);
00133 glVertex2i(dstX, dstY);
00134 glTexCoord2i(srcX + width, srcY);
00135 glVertex2i(dstX + width, dstY);
00136 glTexCoord2i(srcX + width, srcY + height);
00137 glVertex2i(dstX + width, dstY + height);
00138 glTexCoord2i(srcX, srcY + height);
00139 glVertex2i(dstX, dstY + height);
00140 }
00141 }
00142
00143 bool OpenGLGraphics::drawImage(Image *image, int srcX, int srcY,
00144 int dstX, int dstY,
00145 int width, int height, bool useColor)
00146 {
00147 if (!image)
00148 return false;
00149
00150 srcX += image->mBounds.x;
00151 srcY += image->mBounds.y;
00152
00153 if (!useColor)
00154 glColor4f(1.0f, 1.0f, 1.0f, image->mAlpha);
00155
00156 glBindTexture(Image::mTextureType, image->mGLImage);
00157
00158 setTexturingAndBlending(true);
00159
00160
00161 glBegin(GL_QUADS);
00162 drawQuad(image, srcX, srcY, dstX, dstY, width, height);
00163 glEnd();
00164
00165 if (!useColor)
00166 glColor4ub(mColor.r, mColor.g, mColor.b, mColor.a);
00167
00168 return true;
00169 }
00170
00171
00172
00173 void OpenGLGraphics::drawImagePattern(Image *image, int x, int y, int w, int h)
00174 {
00175 if (!image)
00176 return;
00177
00178 const int srcX = image->mBounds.x;
00179 const int srcY = image->mBounds.y;
00180
00181 const int iw = image->getWidth();
00182 const int ih = image->getHeight();
00183 if (iw == 0 || ih == 0)
00184 return;
00185
00186 glColor4f(1.0f, 1.0f, 1.0f, image->mAlpha);
00187
00188 glBindTexture(Image::mTextureType, image->mGLImage);
00189
00190 setTexturingAndBlending(true);
00191
00192
00193 glBegin(GL_QUADS);
00194
00195 for (int py = 0; py < h; py += ih)
00196 {
00197 const int height = (py + ih >= h) ? h - py : ih;
00198 const int dstY = y + py;
00199 for (int px = 0; px < w; px += iw)
00200 {
00201 int width = (px + iw >= w) ? w - px : iw;
00202 int dstX = x + px;
00203
00204 drawQuad(image, srcX, srcY, dstX, dstY, width, height);
00205 }
00206 }
00207
00208 glEnd();
00209
00210 glColor4ub(mColor.r, mColor.g, mColor.b, mColor.a);
00211 }
00212
00213 void OpenGLGraphics::updateScreen()
00214 {
00215 glFlush();
00216 glFinish();
00217 SDL_GL_SwapBuffers();
00218 }
00219
00220 void OpenGLGraphics::_beginDraw()
00221 {
00222 glMatrixMode(GL_TEXTURE);
00223 glLoadIdentity();
00224
00225 glMatrixMode(GL_PROJECTION);
00226 glLoadIdentity();
00227
00228 glOrtho(0.0, (double)mScreen->w, (double)mScreen->h, 0.0, -1.0, 1.0);
00229
00230 glMatrixMode(GL_MODELVIEW);
00231 glLoadIdentity();
00232
00233 glEnable(GL_SCISSOR_TEST);
00234
00235 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00236
00237 pushClipArea(gcn::Rectangle(0, 0, mScreen->w, mScreen->h));
00238 }
00239
00240 void OpenGLGraphics::_endDraw()
00241 {
00242 }
00243
00244 SDL_Surface* OpenGLGraphics::getScreenshot()
00245 {
00246 int h = mScreen->h;
00247 int w = mScreen->w;
00248
00249 SDL_Surface *screenshot = SDL_CreateRGBSurface(
00250 SDL_SWSURFACE,
00251 w, h, 24,
00252 0xff0000, 0x00ff00, 0x0000ff, 0x000000);
00253
00254 if (SDL_MUSTLOCK(screenshot))
00255 SDL_LockSurface(screenshot);
00256
00257
00258 glPixelStorei(GL_PACK_ALIGNMENT, 1);
00259 glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, screenshot->pixels);
00260
00261
00262 unsigned int lineSize = 3 * w;
00263 GLubyte* buf = (GLubyte*)malloc(lineSize);
00264
00265 for (int i = 0; i < (h / 2); i++)
00266 {
00267 GLubyte *top = (GLubyte*)screenshot->pixels + lineSize * i;
00268 GLubyte *bot = (GLubyte*)screenshot->pixels + lineSize * (h - 1 - i);
00269
00270 memcpy(buf, top, lineSize);
00271 memcpy(top, bot, lineSize);
00272 memcpy(bot, buf, lineSize);
00273 }
00274
00275 free(buf);
00276
00277 if (SDL_MUSTLOCK(screenshot))
00278 SDL_UnlockSurface(screenshot);
00279
00280 return screenshot;
00281 }
00282
00283 bool OpenGLGraphics::pushClipArea(gcn::Rectangle area)
00284 {
00285 int transX = 0;
00286 int transY = 0;
00287
00288 if (!mClipStack.empty())
00289 {
00290 transX = -mClipStack.top().xOffset;
00291 transY = -mClipStack.top().yOffset;
00292 }
00293
00294 bool result = gcn::Graphics::pushClipArea(area);
00295
00296 transX += mClipStack.top().xOffset;
00297 transY += mClipStack.top().yOffset;
00298
00299 glPushMatrix();
00300 glTranslatef(transX, transY, 0);
00301 glScissor(mClipStack.top().x,
00302 mScreen->h - mClipStack.top().y - mClipStack.top().height,
00303 mClipStack.top().width,
00304 mClipStack.top().height);
00305
00306 return result;
00307 }
00308
00309 void OpenGLGraphics::popClipArea()
00310 {
00311 gcn::Graphics::popClipArea();
00312
00313 if (mClipStack.empty())
00314 return;
00315
00316 glPopMatrix();
00317 glScissor(mClipStack.top().x,
00318 mScreen->h - mClipStack.top().y - mClipStack.top().height,
00319 mClipStack.top().width,
00320 mClipStack.top().height);
00321 }
00322
00323 void OpenGLGraphics::setColor(const gcn::Color& color)
00324 {
00325 mColor = color;
00326 glColor4ub(color.r, color.g, color.b, color.a);
00327
00328 mColorAlpha = (color.a != 255);
00329 }
00330
00331 void OpenGLGraphics::drawPoint(int x, int y)
00332 {
00333 setTexturingAndBlending(false);
00334
00335 glBegin(GL_POINTS);
00336 glVertex2i(x, y);
00337 glEnd();
00338 }
00339
00340 void OpenGLGraphics::drawLine(int x1, int y1, int x2, int y2)
00341 {
00342 setTexturingAndBlending(false);
00343
00344 glBegin(GL_LINES);
00345 glVertex2f(x1 + 0.5f, y1 + 0.5f);
00346 glVertex2f(x2 + 0.5f, y2 + 0.5f);
00347 glEnd();
00348
00349 glBegin(GL_POINTS);
00350 glVertex2f(x2 + 0.5f, y2 + 0.5f);
00351 glEnd();
00352 }
00353
00354 void OpenGLGraphics::drawRectangle(const gcn::Rectangle& rect)
00355 {
00356 drawRectangle(rect, false);
00357 }
00358
00359 void OpenGLGraphics::fillRectangle(const gcn::Rectangle& rect)
00360 {
00361 drawRectangle(rect, true);
00362 }
00363
00364 void OpenGLGraphics::setTargetPlane(int width, int height)
00365 {
00366 }
00367
00368 void OpenGLGraphics::setTexturingAndBlending(bool enable)
00369 {
00370 if (enable)
00371 {
00372 if (!mTexture)
00373 {
00374 glEnable(Image::mTextureType);
00375 mTexture = true;
00376 }
00377
00378 if (!mAlpha)
00379 {
00380 glEnable(GL_BLEND);
00381 mAlpha = true;
00382 }
00383 }
00384 else
00385 {
00386 if (mAlpha && !mColorAlpha)
00387 {
00388 glDisable(GL_BLEND);
00389 mAlpha = false;
00390 }
00391 else if (!mAlpha && mColorAlpha)
00392 {
00393 glEnable(GL_BLEND);
00394 mAlpha = true;
00395 }
00396
00397 if (mTexture)
00398 {
00399 glDisable(Image::mTextureType);
00400 mTexture = false;
00401 }
00402 }
00403 }
00404
00405 void OpenGLGraphics::drawRectangle(const gcn::Rectangle& rect, bool filled)
00406 {
00407 const float offset = filled ? 0 : 0.5f;
00408
00409 setTexturingAndBlending(false);
00410
00411 glBegin(filled ? GL_QUADS : GL_LINE_LOOP);
00412 glVertex2f(rect.x + offset, rect.y + offset);
00413 glVertex2f(rect.x + rect.width - offset, rect.y + offset);
00414 glVertex2f(rect.x + rect.width - offset, rect.y + rect.height - offset);
00415 glVertex2f(rect.x + offset, rect.y + rect.height - offset);
00416 glEnd();
00417 }
00418
00419 #endif // USE_OPENGL