00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <SDL.h>
00028
00029
00030 #include "util/base/exception.h"
00031 #include "util/log/logger.h"
00032 #include "video/devicecaps.h"
00033
00034 #include "fife_opengl.h"
00035 #include "glimage.h"
00036 #include "renderbackendopengl.h"
00037 #include "SDL_image.h"
00038
00039
00040 namespace FIFE {
00041 static Logger _log(LM_VIDEO);
00042
00043 RenderBackendOpenGL::RenderBackendOpenGL(const SDL_Color& colorkey) : RenderBackend(colorkey) {
00044
00045 SDL_Surface* testsurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, 1, 1, 32,
00046 RMASK, GMASK, BMASK ,AMASK);
00047
00048 m_rgba_format = *(testsurface->format);
00049 SDL_FreeSurface(testsurface);
00050 m_lightmodel = 0;
00051 m_light_enabled = false;
00052 m_stencil_enabled = false;
00053 m_alpha_enabled = false;
00054 m_sten_ref = 0;
00055 m_sten_buf = 0;
00056 m_sten_op = 0;
00057 m_sten_func = 0;
00058 m_blend_src = GL_SRC_ALPHA;
00059 m_blend_dst = GL_ONE_MINUS_SRC_ALPHA;
00060 }
00061
00062 const std::string& RenderBackendOpenGL::getName() const {
00063 static std::string backend_name = "OpenGL";
00064 return backend_name;
00065 }
00066
00067 RenderBackendOpenGL::~RenderBackendOpenGL() {
00068 }
00069
00070
00071 void RenderBackendOpenGL::init(const std::string& driver) {
00072
00073
00074
00075 Uint32 flags = SDL_INIT_VIDEO;
00076 if (SDL_InitSubSystem(flags) < 0)
00077 throw SDLException(SDL_GetError());
00078 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
00079 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
00080
00081 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
00082
00083 }
00084
00085 void RenderBackendOpenGL::clearBackBuffer() {
00086 GLDisable flag(GL_SCISSOR_TEST);
00087 glClear(GL_COLOR_BUFFER_BIT);
00088 }
00089
00090 Image* RenderBackendOpenGL::createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon){
00091 if(icon != "") {
00092 SDL_Surface *img = IMG_Load(icon.c_str());
00093 if(img != NULL) {
00094 SDL_WM_SetIcon(img, 0);
00095 }
00096 }
00097
00098 Image *image = setScreenMode(mode);
00099
00100 SDL_WM_SetCaption(title.c_str(), 0);
00101
00102 return image;
00103 }
00104
00105 Image* RenderBackendOpenGL::setScreenMode(const ScreenMode& mode) {
00106 uint16_t width = mode.getWidth();
00107 uint16_t height = mode.getHeight();
00108 uint16_t bitsPerPixel = mode.getBPP();
00109 bool fs = mode.isFullScreen();
00110 uint32_t flags = mode.getSDLFlags();
00111
00112 SDL_Surface* screen = NULL;
00113
00114 if (bitsPerPixel != 0) {
00115 uint16_t bpp = SDL_VideoModeOK(width, height, bitsPerPixel, flags);
00116 if (!bpp){
00117 throw SDLException("Selected video mode not supported!");
00118 }
00119 }
00120
00121 screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
00122 if( !screen ) {
00123 throw SDLException("Unable to set video mode selected!");
00124 }
00125
00126 FL_LOG(_log, LMsg("RenderBackendOpenGL")
00127 << "Videomode " << width << "x" << height
00128 << " at " << int(bitsPerPixel) << " bpp");
00129
00130
00131 m_screenMode = ScreenMode(width,
00132 height,
00133 bitsPerPixel,
00134 screen->flags);
00135
00136
00137 if (!screen) {
00138 throw SDLException(SDL_GetError());
00139 }
00140
00141 glViewport(0, 0, width, height);
00142 glMatrixMode(GL_PROJECTION);
00143 gluOrtho2D(0, width, height, 0);
00144 glMatrixMode(GL_MODELVIEW);
00145
00146 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
00147
00148 glEnable(GL_TEXTURE_2D);
00149 glEnable(GL_BLEND);
00150 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00151
00152 glEnable(GL_SCISSOR_TEST);
00153
00154 glPointSize(1.0);
00155 glLineWidth(1.0);
00156 delete m_screen;
00157 delete m_screen;
00158 m_screen = new GLImage(screen);
00159 return m_screen;
00160 }
00161
00162
00163 void RenderBackendOpenGL::startFrame() {
00164 }
00165
00166 void RenderBackendOpenGL::endFrame() {
00167 SDL_GL_SwapBuffers();
00168 }
00169
00170 Image* RenderBackendOpenGL::createImage(SDL_Surface* surface) {
00171
00172
00173
00174
00175
00176
00177 if( m_rgba_format.BitsPerPixel == surface->format->BitsPerPixel
00178 && m_rgba_format.Rmask == surface->format->Rmask
00179 && m_rgba_format.Gmask == surface->format->Gmask
00180 && m_rgba_format.Bmask == surface->format->Bmask
00181 && m_rgba_format.Amask == surface->format->Amask
00182 && m_rgba_format.Rshift == surface->format->Rshift
00183 && m_rgba_format.Gshift == surface->format->Gshift
00184 && m_rgba_format.Bshift == surface->format->Bshift
00185 && m_rgba_format.Ashift == surface->format->Ashift
00186 && m_rgba_format.Rloss == surface->format->Rloss
00187 && m_rgba_format.Gloss == surface->format->Gloss
00188 && m_rgba_format.Bloss == surface->format->Bloss
00189 && m_rgba_format.Aloss == surface->format->Aloss
00190 && surface->flags & SDL_SRCALPHA ) {
00191
00192 return new GLImage(surface);
00193 }
00194
00195 SDL_Surface* conv = SDL_ConvertSurface(surface, &m_rgba_format, SDL_SWSURFACE | SDL_SRCALPHA);
00196 GLImage* image = new GLImage(conv);
00197 SDL_FreeSurface( surface );
00198 return image;
00199 }
00200
00201 Image* RenderBackendOpenGL::createImage(const uint8_t* data, unsigned int width, unsigned int height) {
00202 return new GLImage(data, width, height);
00203 }
00204
00205 void RenderBackendOpenGL::setLightingModel(unsigned int lighting) {
00206 if (m_lightmodel != lighting) {
00207 if (m_lightmodel == 1) {
00208 disableLighting();
00209 glDisable(GL_COLOR_MATERIAL);
00210 } else if (lighting == 1) {
00211 enableLighting();
00212 glEnable(GL_LIGHT0);
00213 glColorMaterial(GL_FRONT, GL_DIFFUSE);
00214 glEnable(GL_COLOR_MATERIAL);
00215 }
00216 m_lightmodel = lighting;
00217 }
00218 }
00219
00220 unsigned int RenderBackendOpenGL::getLightingModel() const {
00221 return m_lightmodel;
00222 }
00223
00224 void RenderBackendOpenGL::enableLighting() {
00225 if (m_lightmodel == 1 && !m_light_enabled) {
00226 glEnable(GL_LIGHTING);
00227 m_light_enabled = true;
00228 }
00229 }
00230
00231 void RenderBackendOpenGL::disableLighting() {
00232 if (m_lightmodel == 1 && m_light_enabled) {
00233 glDisable(GL_LIGHTING);
00234 m_light_enabled = false;
00235 }
00236 }
00237
00238 void RenderBackendOpenGL::setLighting(float red, float green, float blue, float alpha) {
00239 if (m_lightmodel == 1) {
00240 GLfloat lightDiffuse[] = {red, green, blue, alpha};
00241 glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
00242 } else if(m_lightmodel == 2) {
00243 m_lred = red;
00244 m_lgreen = green;
00245 m_lblue = blue;
00246 m_lalpha = alpha;
00247 }
00248 }
00249
00250 void RenderBackendOpenGL::resetLighting() {
00251 if (m_lightmodel == 1) {
00252 setLighting(1.0, 1.0, 1.0, 1.0);
00253 } else if (m_lightmodel == 2 && m_lalpha > 0.01) {
00254 uint16_t width = getScreenWidth();
00255 uint16_t height = getScreenHeight();
00256 Point p = Point(0,0);
00257 setStencilTest(0, 0, 5);
00258 fillRectangle(p, width, height, m_lred*255, m_lgreen*255, m_lblue*255, m_lalpha*255);
00259 disableStencilTest();
00260 }
00261 }
00262
00263 void RenderBackendOpenGL::enableStencilTest() {
00264 if (!m_stencil_enabled) {
00265 glEnable(GL_STENCIL_TEST);
00266 m_stencil_enabled = true;
00267 }
00268 }
00269
00270 void RenderBackendOpenGL::disableStencilTest() {
00271 if (m_stencil_enabled) {
00272 glDisable(GL_STENCIL_TEST);
00273 m_stencil_enabled = false;
00274 }
00275 }
00276
00277 void RenderBackendOpenGL::setStencilTest(uint8_t stencil_ref, unsigned int stencil_op, unsigned int stencil_func) {
00278 enableStencilTest();
00279 if(m_sten_op != stencil_op) {
00280 GLenum op;
00281 m_sten_op = stencil_op;
00282 switch(stencil_op) {
00283 default :
00284 case 0 : op = GL_KEEP; break;
00285 case 1 : op = GL_ZERO; break;
00286 case 2 : op = GL_REPLACE; break;
00287 case 3 : op = GL_INCR; break;
00288 case 4 : op = GL_DECR; break;
00289 case 5 : op = GL_INVERT; break;
00290 }
00291 glStencilOp(GL_KEEP, GL_KEEP, op);
00292 }
00293
00294 if(m_sten_ref != stencil_ref || m_sten_func != stencil_func) {
00295 GLenum func;
00296 m_sten_ref = stencil_ref;
00297 m_sten_func = stencil_func;
00298 switch(stencil_func) {
00299 default :
00300 case 0 : func = GL_NEVER; break;
00301 case 1 : func = GL_LESS; break;
00302 case 2 : func = GL_LEQUAL; break;
00303 case 3 : func = GL_GREATER; break;
00304 case 4 : func = GL_GEQUAL; break;
00305 case 5 : func = GL_EQUAL; break;
00306 case 6 : func = GL_NOTEQUAL; break;
00307 case 7 : func = GL_ALWAYS; break;
00308 }
00309 glStencilFunc(func, stencil_ref, 0xff);
00310 }
00311 }
00312
00313 void RenderBackendOpenGL::resetStencilBuffer(uint8_t buffer) {
00314 if (buffer != m_sten_buf) {
00315 m_sten_buf = buffer;
00316 glClearStencil(buffer);
00317 }
00318 GLDisable flag(GL_SCISSOR_TEST);
00319 glClear(GL_STENCIL_BUFFER_BIT);
00320 }
00321
00322 uint8_t RenderBackendOpenGL::getStencilRef() const {
00323 return m_sten_ref;
00324 }
00325
00326 void RenderBackendOpenGL::enableAlphaTest() {
00327 if (!m_alpha_enabled) {
00328 glEnable(GL_ALPHA_TEST);
00329 m_alpha_enabled = true;
00330 }
00331 }
00332
00333 void RenderBackendOpenGL::disableAlphaTest() {
00334 if (m_alpha_enabled) {
00335 glDisable(GL_ALPHA_TEST);
00336 m_alpha_enabled = false;
00337 }
00338 }
00339
00340 void RenderBackendOpenGL::setAlphaTest(float ref_alpha) {
00341 enableAlphaTest();
00342 glAlphaFunc(GL_GREATER, ref_alpha);
00343 }
00344
00345 void RenderBackendOpenGL::changeBlending(int src, int dst) {
00346 GLenum src_fact;
00347 GLenum dst_fact;
00348
00349 switch(src) {
00350 case 0 : src_fact = GL_ZERO; break;
00351 case 1 : src_fact = GL_ONE; break;
00352 case 2 : src_fact = GL_DST_COLOR; break;
00353 case 3 : src_fact = GL_ONE_MINUS_DST_COLOR; break;
00354 case 4 : src_fact = GL_SRC_ALPHA; break;
00355 case 5 : src_fact = GL_ONE_MINUS_SRC_ALPHA; break;
00356 case 6 : src_fact = GL_DST_ALPHA; break;
00357 case 7 : src_fact = GL_ONE_MINUS_DST_ALPHA; break;
00358
00359 default : src_fact = GL_DST_COLOR; break;
00360 }
00361
00362 switch(dst) {
00363 case 0 : dst_fact = GL_ZERO; break;
00364 case 1 : dst_fact = GL_ONE; break;
00365 case 2 : dst_fact = GL_SRC_COLOR; break;
00366 case 3 : dst_fact = GL_ONE_MINUS_SRC_COLOR; break;
00367 case 4 : dst_fact = GL_SRC_ALPHA; break;
00368 case 5 : dst_fact = GL_ONE_MINUS_SRC_ALPHA; break;
00369 case 6 : dst_fact = GL_DST_ALPHA; break;
00370 case 7 : dst_fact = GL_ONE_MINUS_DST_ALPHA; break;
00371
00372 default : dst_fact = GL_SRC_ALPHA; break;
00373 }
00374
00375 if (m_blend_src != src_fact || m_blend_dst != dst_fact) {
00376 m_blend_src = src_fact;
00377 m_blend_dst = dst_fact;
00378 glBlendFunc(src_fact, dst_fact);
00379 }
00380 }
00381
00382 bool RenderBackendOpenGL::putPixel(int x, int y, int r, int g, int b, int a) {
00383 if ((x < 0) || (x >= (int)getWidth()) || (y < 0) || (y >= (int)getHeight())) {
00384 return false;
00385 }
00386
00387 glColor4ub(r, g, b, a);
00388
00389 glBegin(GL_POINTS);
00390 glVertex2i(x, y);
00391 glEnd();
00392 return true;
00393 }
00394
00395 void RenderBackendOpenGL::drawLine(const Point& p1, const Point& p2, int r, int g, int b, int a) {
00396 glColor4ub(r, g, b, a);
00397
00398 glBegin(GL_LINES);
00399 glVertex2f(p1.x+0.5f, p1.y+0.5f);
00400 glVertex2f(p2.x+0.5f, p2.y+0.5f);
00401 glEnd();
00402
00403 glBegin(GL_POINTS);
00404 glVertex2f(p2.x+0.5f, p2.y+0.5f);
00405 glEnd();
00406 }
00407
00408 void RenderBackendOpenGL::drawTriangle(const Point& p1, const Point& p2, const Point& p3, int r, int g, int b, int a) {
00409 glColor4ub(r, g, b, a);
00410
00411 glBegin(GL_TRIANGLES);
00412 glVertex2f(p1.x, p1.y);
00413 glVertex2f(p2.x, p2.y);
00414 glVertex2f(p3.x, p3.y);
00415 glEnd();
00416 }
00417
00418 void RenderBackendOpenGL::drawRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00419 glColor4ub(r, g, b, a);
00420
00421 glBegin(GL_LINE_LOOP);
00422 glVertex2f(p.x, p.y);
00423 glVertex2f(p.x+w, p.y);
00424 glVertex2f(p.x+w, p.y+h);
00425 glVertex2f(p.x, p.y+h);
00426 glEnd();
00427 }
00428
00429 void RenderBackendOpenGL::fillRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00430 glColor4ub(r, g, b, a);
00431
00432 glBegin(GL_QUADS);
00433 glVertex2f(p.x, p.y);
00434 glVertex2f(p.x+w, p.y);
00435 glVertex2f(p.x+w, p.y+h);
00436 glVertex2f(p.x, p.y+h);
00437 glEnd();
00438 }
00439
00440 void RenderBackendOpenGL::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4, int r, int g, int b, int a) {
00441 glColor4ub(r, g, b, a);
00442
00443 glBegin(GL_QUADS);
00444 glVertex2f(p1.x, p1.y);
00445 glVertex2f(p2.x, p2.y);
00446 glVertex2f(p3.x, p3.y);
00447 glVertex2f(p4.x, p4.y);
00448 glEnd();
00449 }
00450
00451 void RenderBackendOpenGL::drawVertex(const Point& p, const uint8_t size, int r, int g, int b, int a){
00452 GLfloat width;
00453 glGetFloatv(GL_LINE_WIDTH, &width);
00454 glLineWidth(1.0);
00455
00456 glColor4ub(r, g, b, a);
00457
00458 glBegin(GL_LINE_LOOP);
00459 glVertex2f(p.x-size, p.y+size);
00460 glVertex2f(p.x+size, p.y+size);
00461 glVertex2f(p.x+size, p.y-size);
00462 glVertex2f(p.x-size, p.y-size);
00463 glEnd();
00464
00465 glLineWidth(width);
00466 }
00467
00468 void RenderBackendOpenGL::drawLightPrimitive(const Point& p, uint8_t intensity, float radius, int subdivisions, float xstretch, float ystretch, uint8_t red, uint8_t green, uint8_t blue) {
00469 glBegin(GL_TRIANGLE_FAN);
00470 glColor4ub(red, green, blue, intensity);
00471 glVertex2f(p.x, p.y);
00472 if (m_lightmodel == 2) {
00473 glColor4ub(0, 0, 0, intensity);
00474 } else {
00475 glColor4ub(0, 0, 0, 255);
00476 }
00477 for(float angle=0; angle<=Mathf::twoPi(); angle+=(Mathf::twoPi()/subdivisions)){
00478 glVertex2f( radius*Mathf::Cos(angle)*xstretch + p.x,
00479 radius*Mathf::Sin(angle)*ystretch + p.y);
00480 }
00481 glVertex2f(p.x+radius*xstretch, p.y);
00482 glEnd();
00483 }
00484 }