30 #include "util/base/exception.h"
31 #include "util/log/logger.h"
32 #include "video/devicecaps.h"
34 #include "fife_opengl.h"
36 #include "renderbackendopengl.h"
37 #include "SDL_image.h"
41 static Logger _log(LM_VIDEO);
43 RenderBackendOpenGL::RenderBackendOpenGL(
const SDL_Color& colorkey) : RenderBackend(colorkey) {
45 SDL_Surface* testsurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, 1, 1, 32,
46 RMASK, GMASK, BMASK ,AMASK);
48 m_rgba_format = *(testsurface->format);
49 SDL_FreeSurface(testsurface);
51 m_light_enabled =
false;
52 m_stencil_enabled =
false;
53 m_alpha_enabled =
false;
58 m_blend_src = GL_SRC_ALPHA;
59 m_blend_dst = GL_ONE_MINUS_SRC_ALPHA;
63 static std::string backend_name =
"OpenGL";
67 RenderBackendOpenGL::~RenderBackendOpenGL() {
75 Uint32 flags = SDL_INIT_VIDEO;
76 if (SDL_InitSubSystem(flags) < 0)
77 throw SDLException(SDL_GetError());
78 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
79 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
81 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
86 GLDisable flag(GL_SCISSOR_TEST);
87 glClear(GL_COLOR_BUFFER_BIT);
92 SDL_Surface *img = IMG_Load(icon.c_str());
94 SDL_WM_SetIcon(img, 0);
100 SDL_WM_SetCaption(title.c_str(), 0);
106 uint16_t width = mode.getWidth();
107 uint16_t height = mode.getHeight();
108 uint16_t bitsPerPixel = mode.getBPP();
109 bool fs = mode.isFullScreen();
110 uint32_t flags = mode.getSDLFlags();
112 SDL_Surface* screen = NULL;
114 if (bitsPerPixel != 0) {
115 uint16_t bpp = SDL_VideoModeOK(width, height, bitsPerPixel, flags);
117 throw SDLException(
"Selected video mode not supported!");
121 screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
123 throw SDLException(
"Unable to set video mode selected!");
126 FL_LOG(_log,
LMsg(
"RenderBackendOpenGL")
127 <<
"Videomode " << width <<
"x" << height
128 <<
" at " <<
int(bitsPerPixel) <<
" bpp");
131 m_screenMode = ScreenMode(width,
138 throw SDLException(SDL_GetError());
141 glViewport(0, 0, width, height);
142 glMatrixMode(GL_PROJECTION);
143 gluOrtho2D(0, width, height, 0);
144 glMatrixMode(GL_MODELVIEW);
146 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
148 glEnable(GL_TEXTURE_2D);
150 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
152 glEnable(GL_SCISSOR_TEST);
158 m_screen =
new GLImage(screen);
167 SDL_GL_SwapBuffers();
177 if( m_rgba_format.BitsPerPixel == surface->format->BitsPerPixel
178 && m_rgba_format.Rmask == surface->format->Rmask
179 && m_rgba_format.Gmask == surface->format->Gmask
180 && m_rgba_format.Bmask == surface->format->Bmask
181 && m_rgba_format.Amask == surface->format->Amask
182 && m_rgba_format.Rshift == surface->format->Rshift
183 && m_rgba_format.Gshift == surface->format->Gshift
184 && m_rgba_format.Bshift == surface->format->Bshift
185 && m_rgba_format.Ashift == surface->format->Ashift
186 && m_rgba_format.Rloss == surface->format->Rloss
187 && m_rgba_format.Gloss == surface->format->Gloss
188 && m_rgba_format.Bloss == surface->format->Bloss
189 && m_rgba_format.Aloss == surface->format->Aloss
190 && surface->flags & SDL_SRCALPHA ) {
195 SDL_Surface* conv = SDL_ConvertSurface(surface, &m_rgba_format, SDL_SWSURFACE | SDL_SRCALPHA);
197 SDL_FreeSurface( surface );
202 return new GLImage(data, width, height);
206 if (m_lightmodel != lighting) {
207 if (m_lightmodel == 1) {
209 glDisable(GL_COLOR_MATERIAL);
210 }
else if (lighting == 1) {
213 glColorMaterial(GL_FRONT, GL_DIFFUSE);
214 glEnable(GL_COLOR_MATERIAL);
216 m_lightmodel = lighting;
225 if (m_lightmodel == 1 && !m_light_enabled) {
226 glEnable(GL_LIGHTING);
227 m_light_enabled =
true;
232 if (m_lightmodel == 1 && m_light_enabled) {
233 glDisable(GL_LIGHTING);
234 m_light_enabled =
false;
239 if (m_lightmodel == 1) {
240 GLfloat lightDiffuse[] = {red, green, blue, alpha};
241 glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
242 }
else if(m_lightmodel == 2) {
251 if (m_lightmodel == 1) {
253 }
else if (m_lightmodel == 2 && m_lalpha > 0.01) {
254 uint16_t width = getScreenWidth();
255 uint16_t height = getScreenHeight();
257 setStencilTest(0, 0, 5);
258 fillRectangle(p, width, height, m_lred*255, m_lgreen*255, m_lblue*255, m_lalpha*255);
264 if (!m_stencil_enabled) {
265 glEnable(GL_STENCIL_TEST);
266 m_stencil_enabled =
true;
271 if (m_stencil_enabled) {
272 glDisable(GL_STENCIL_TEST);
273 m_stencil_enabled =
false;
277 void RenderBackendOpenGL::setStencilTest(uint8_t stencil_ref,
unsigned int stencil_op,
unsigned int stencil_func) {
279 if(m_sten_op != stencil_op) {
281 m_sten_op = stencil_op;
284 case 0 : op = GL_KEEP;
break;
285 case 1 : op = GL_ZERO;
break;
286 case 2 : op = GL_REPLACE;
break;
287 case 3 : op = GL_INCR;
break;
288 case 4 : op = GL_DECR;
break;
289 case 5 : op = GL_INVERT;
break;
291 glStencilOp(GL_KEEP, GL_KEEP, op);
294 if(m_sten_ref != stencil_ref || m_sten_func != stencil_func) {
296 m_sten_ref = stencil_ref;
297 m_sten_func = stencil_func;
298 switch(stencil_func) {
300 case 0 : func = GL_NEVER;
break;
301 case 1 : func = GL_LESS;
break;
302 case 2 : func = GL_LEQUAL;
break;
303 case 3 : func = GL_GREATER;
break;
304 case 4 : func = GL_GEQUAL;
break;
305 case 5 : func = GL_EQUAL;
break;
306 case 6 : func = GL_NOTEQUAL;
break;
307 case 7 : func = GL_ALWAYS;
break;
309 glStencilFunc(func, stencil_ref, 0xff);
313 void RenderBackendOpenGL::resetStencilBuffer(uint8_t buffer) {
314 if (buffer != m_sten_buf) {
316 glClearStencil(buffer);
318 GLDisable flag(GL_SCISSOR_TEST);
319 glClear(GL_STENCIL_BUFFER_BIT);
327 if (!m_alpha_enabled) {
328 glEnable(GL_ALPHA_TEST);
329 m_alpha_enabled =
true;
334 if (m_alpha_enabled) {
335 glDisable(GL_ALPHA_TEST);
336 m_alpha_enabled =
false;
342 glAlphaFunc(GL_GREATER, ref_alpha);
350 case 0 : src_fact = GL_ZERO;
break;
351 case 1 : src_fact = GL_ONE;
break;
352 case 2 : src_fact = GL_DST_COLOR;
break;
353 case 3 : src_fact = GL_ONE_MINUS_DST_COLOR;
break;
354 case 4 : src_fact = GL_SRC_ALPHA;
break;
355 case 5 : src_fact = GL_ONE_MINUS_SRC_ALPHA;
break;
356 case 6 : src_fact = GL_DST_ALPHA;
break;
357 case 7 : src_fact = GL_ONE_MINUS_DST_ALPHA;
break;
359 default : src_fact = GL_DST_COLOR;
break;
363 case 0 : dst_fact = GL_ZERO;
break;
364 case 1 : dst_fact = GL_ONE;
break;
365 case 2 : dst_fact = GL_SRC_COLOR;
break;
366 case 3 : dst_fact = GL_ONE_MINUS_SRC_COLOR;
break;
367 case 4 : dst_fact = GL_SRC_ALPHA;
break;
368 case 5 : dst_fact = GL_ONE_MINUS_SRC_ALPHA;
break;
369 case 6 : dst_fact = GL_DST_ALPHA;
break;
370 case 7 : dst_fact = GL_ONE_MINUS_DST_ALPHA;
break;
372 default : dst_fact = GL_SRC_ALPHA;
break;
375 if (m_blend_src != src_fact || m_blend_dst != dst_fact) {
376 m_blend_src = src_fact;
377 m_blend_dst = dst_fact;
378 glBlendFunc(src_fact, dst_fact);
382 bool RenderBackendOpenGL::putPixel(
int x,
int y,
int r,
int g,
int b,
int a) {
383 if ((x < 0) || (x >= (
int)getWidth()) || (y < 0) || (y >= (
int)getHeight())) {
387 glColor4ub(r, g, b, a);
395 void RenderBackendOpenGL::drawLine(
const Point& p1,
const Point& p2,
int r,
int g,
int b,
int a) {
396 glColor4ub(r, g, b, a);
399 glVertex2f(p1.x+0.5f, p1.y+0.5f);
400 glVertex2f(p2.x+0.5f, p2.y+0.5f);
404 glVertex2f(p2.x+0.5f, p2.y+0.5f);
408 void RenderBackendOpenGL::drawTriangle(
const Point& p1,
const Point& p2,
const Point& p3,
int r,
int g,
int b,
int a) {
409 glColor4ub(r, g, b, a);
411 glBegin(GL_TRIANGLES);
412 glVertex2f(p1.x, p1.y);
413 glVertex2f(p2.x, p2.y);
414 glVertex2f(p3.x, p3.y);
418 void RenderBackendOpenGL::drawRectangle(
const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
419 glColor4ub(r, g, b, a);
421 glBegin(GL_LINE_LOOP);
422 glVertex2f(p.x, p.y);
423 glVertex2f(p.x+w, p.y);
424 glVertex2f(p.x+w, p.y+h);
425 glVertex2f(p.x, p.y+h);
429 void RenderBackendOpenGL::fillRectangle(
const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
430 glColor4ub(r, g, b, a);
433 glVertex2f(p.x, p.y);
434 glVertex2f(p.x+w, p.y);
435 glVertex2f(p.x+w, p.y+h);
436 glVertex2f(p.x, p.y+h);
440 void RenderBackendOpenGL::drawQuad(
const Point& p1,
const Point& p2,
const Point& p3,
const Point& p4,
int r,
int g,
int b,
int a) {
441 glColor4ub(r, g, b, a);
444 glVertex2f(p1.x, p1.y);
445 glVertex2f(p2.x, p2.y);
446 glVertex2f(p3.x, p3.y);
447 glVertex2f(p4.x, p4.y);
451 void RenderBackendOpenGL::drawVertex(
const Point& p,
const uint8_t size,
int r,
int g,
int b,
int a){
453 glGetFloatv(GL_LINE_WIDTH, &width);
456 glColor4ub(r, g, b, a);
458 glBegin(GL_LINE_LOOP);
459 glVertex2f(p.x-size, p.y+size);
460 glVertex2f(p.x+size, p.y+size);
461 glVertex2f(p.x+size, p.y-size);
462 glVertex2f(p.x-size, p.y-size);
468 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) {
469 glBegin(GL_TRIANGLE_FAN);
470 glColor4ub(red, green, blue, intensity);
471 glVertex2f(p.x, p.y);
472 if (m_lightmodel == 2) {
473 glColor4ub(0, 0, 0, intensity);
475 glColor4ub(0, 0, 0, 255);
477 for(
float angle=0; angle<=Mathf::twoPi(); angle+=(Mathf::twoPi()/subdivisions)){
478 glVertex2f( radius*Mathf::Cos(angle)*xstretch + p.x,
479 radius*Mathf::Sin(angle)*ystretch + p.y);
481 glVertex2f(p.x+radius*xstretch, p.y);