32#include <OpenGL/OpenGL.h>
39#ifndef GL_TEXTURE_RECTANGLE_ARB
40#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
41#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
44const unsigned int vertexBufSize = 500;
46GLuint OpenGLGraphics::mLastImage = 0;
48std::unique_ptr<OpenGLGraphics> OpenGLGraphics::create(SDL_Window *window,
51 SDL_GLContext glContext = SDL_GL_CreateContext(window);
56 SDL_GL_SetSwapInterval(1);
58 return std::make_unique<OpenGLGraphics>(window, glContext);
61OpenGLGraphics::OpenGLGraphics(SDL_Window *window, SDL_GLContext glContext)
65 Image::setLoadAsOpenGL(
true);
67 mFloatTexArray =
new GLfloat[vertexBufSize * 4];
68 mIntTexArray =
new GLint[vertexBufSize * 4];
69 mIntVertArray =
new GLint[vertexBufSize * 4];
71 SDL_GL_GetDrawableSize(mWindow, &mWidth, &mHeight);
74 glViewport(0, 0, mWidth, mHeight);
75 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
77 char const *glExtensions = (
char const *)glGetString(GL_EXTENSIONS);
79 bool rectTex = strstr(glExtensions,
"GL_ARB_texture_rectangle");
80 bool npotTex = strstr(glExtensions,
"GL_ARB_texture_non_power_of_two");
81 if (rectTex && !npotTex)
83 Image::mTextureType = GL_TEXTURE_RECTANGLE_ARB;
84 Image::mPowerOfTwoTextures =
false;
85 glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &texSize);
89 Image::mTextureType = GL_TEXTURE_2D;
90 Image::mPowerOfTwoTextures = !npotTex;
91 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
93 Image::mTextureSize = texSize;
94 Log::info(
"OpenGL texture size: %d pixels%s", Image::mTextureSize,
95 rectTex ?
" (rectangle textures)" :
"");
97 glMatrixMode(GL_TEXTURE);
100 glMatrixMode(GL_PROJECTION);
102 glOrtho(0.0, (
double)mWidth, (
double)mHeight, 0.0, -1.0, 1.0);
104 glMatrixMode(GL_MODELVIEW);
107 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
109 glEnableClientState(GL_VERTEX_ARRAY);
110 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
113OpenGLGraphics::~OpenGLGraphics()
115 SDL_GL_DeleteContext(mContext);
117 delete[] mFloatTexArray;
118 delete[] mIntTexArray;
119 delete[] mIntVertArray;
122void OpenGLGraphics::setVSync(
bool sync)
124 SDL_GL_SetSwapInterval(sync ? 1 : 0);
127void OpenGLGraphics::setReduceInputLag(
bool reduceInputLag)
129 mReduceInputLag = reduceInputLag;
132void OpenGLGraphics::updateSize(
int windowWidth,
int windowHeight,
float scale)
138 SDL_GL_GetDrawableSize(mWindow, &drawableWidth, &drawableHeight);
140 glViewport(0, 0, drawableWidth, drawableHeight);
142 float displayScaleX = windowWidth > 0 ?
static_cast<float>(drawableWidth) / windowWidth : 1.0f;
143 float displayScaleY = windowHeight > 0 ?
static_cast<float>(drawableHeight) / windowHeight : 1.0f;
145 mScaleX = mUserScale * displayScaleX;
146 mScaleY = mUserScale * displayScaleY;
148 mWidth = std::ceil(drawableWidth / mScaleX);
149 mHeight = std::ceil(drawableHeight / mScaleY);
152 glMatrixMode(GL_PROJECTION);
154 glOrtho(0.0, (
double)mWidth, (
double)mHeight, 0.0, -1.0, 1.0);
157static inline void drawRescaledQuad(
const Image *image,
159 float dstX,
float dstY,
160 int width,
int height,
161 float desiredWidth,
float desiredHeight)
163 if (Image::getTextureType() == GL_TEXTURE_2D)
166 const float texX1 =
static_cast<float>(srcX) /
167 static_cast<float>(image->getTextureWidth());
168 const float texY1 =
static_cast<float>(srcY) /
169 static_cast<float>(image->getTextureHeight());
170 const float texX2 =
static_cast<float>(srcX + width) /
171 static_cast<float>(image->getTextureWidth());
172 const float texY2 =
static_cast<float>(srcY + height) /
173 static_cast<float>(image->getTextureHeight());
175 const GLfloat tex[] =
183 const GLfloat vert[] =
186 dstX + desiredWidth, dstY,
187 dstX + desiredWidth, dstY + desiredHeight,
188 dstX, dstY + desiredHeight
191 glVertexPointer(2, GL_FLOAT, 0, &vert);
192 glTexCoordPointer(2, GL_FLOAT, 0, &tex);
194 glDrawArrays(GL_QUADS, 0, 4);
202 srcX + width, srcY + height,
205 const GLfloat vert[] =
208 dstX + desiredWidth, dstY,
209 dstX + desiredWidth, dstY + desiredHeight,
210 dstX, dstY + desiredHeight
213 glVertexPointer(2, GL_FLOAT, 0, &vert);
214 glTexCoordPointer(2, GL_INT, 0, &tex);
216 glDrawArrays(GL_QUADS, 0, 4);
221bool OpenGLGraphics::drawRescaledImage(
const Image *image,
int srcX,
int srcY,
223 int width,
int height,
224 int desiredWidth,
int desiredHeight,
227 return drawRescaledImageF(image, srcX, srcY, dstX, dstY,
228 width, height, desiredWidth, desiredHeight,
232bool OpenGLGraphics::drawRescaledImageF(
const Image *image,
int srcX,
int srcY,
233 float dstX,
float dstY,
234 int width,
int height,
235 float desiredWidth,
float desiredHeight,
245 glColor4f(1.0f, 1.0f, 1.0f, image->
mAlpha);
247 bindTexture(Image::mTextureType, image->mGLImage);
249 setTexturingAndBlending(
true);
252 drawRescaledQuad(image, srcX, srcY, dstX, dstY, width, height,
253 desiredWidth, desiredHeight);
257 glColor4ub(
static_cast<GLubyte
>(mColor.r),
258 static_cast<GLubyte
>(mColor.g),
259 static_cast<GLubyte
>(mColor.b),
260 static_cast<GLubyte
>(mColor.a));
266void OpenGLGraphics::drawImagePattern(
const Image *image,
int x,
int y,
int w,
int h)
271 const int srcX = image->
mBounds.x;
272 const int srcY = image->
mBounds.y;
277 if (iw == 0 || ih == 0)
280 const auto tw =
static_cast<float>(image->getTextureWidth());
281 const auto th =
static_cast<float>(image->getTextureHeight());
283 glColor4f(1.0f, 1.0f, 1.0f, image->
mAlpha);
285 bindTexture(Image::mTextureType, image->mGLImage);
287 setTexturingAndBlending(
true);
290 const unsigned int vLimit = vertexBufSize * 4;
292 if (Image::getTextureType() == GL_TEXTURE_2D)
294 float texX1 =
static_cast<float>(srcX) / tw;
295 float texY1 =
static_cast<float>(srcY) / th;
297 for (
int py = 0; py < h; py += ih)
299 const int height = (py + ih >= h) ? h - py : ih;
300 const int dstY = y + py;
301 for (
int px = 0; px < w; px += iw)
303 int width = (px + iw >= w) ? w - px : iw;
306 float texX2 =
static_cast<float>(srcX + width) / tw;
307 float texY2 =
static_cast<float>(srcY + height) / th;
309 mFloatTexArray[vp + 0] = texX1;
310 mFloatTexArray[vp + 1] = texY1;
312 mFloatTexArray[vp + 2] = texX2;
313 mFloatTexArray[vp + 3] = texY1;
315 mFloatTexArray[vp + 4] = texX2;
316 mFloatTexArray[vp + 5] = texY2;
318 mFloatTexArray[vp + 6] = texX1;
319 mFloatTexArray[vp + 7] = texY2;
321 mIntVertArray[vp + 0] = dstX;
322 mIntVertArray[vp + 1] = dstY;
324 mIntVertArray[vp + 2] = dstX + width;
325 mIntVertArray[vp + 3] = dstY;
327 mIntVertArray[vp + 4] = dstX + width;
328 mIntVertArray[vp + 5] = dstY + height;
330 mIntVertArray[vp + 6] = dstX;
331 mIntVertArray[vp + 7] = dstY + height;
346 for (
int py = 0; py < h; py += ih)
348 const int height = (py + ih >= h) ? h - py : ih;
349 const int dstY = y + py;
350 for (
int px = 0; px < w; px += iw)
352 int width = (px + iw >= w) ? w - px : iw;
355 mIntTexArray[vp + 0] = srcX;
356 mIntTexArray[vp + 1] = srcY;
358 mIntTexArray[vp + 2] = srcX + width;
359 mIntTexArray[vp + 3] = srcY;
361 mIntTexArray[vp + 4] = srcX + width;
362 mIntTexArray[vp + 5] = srcY + height;
364 mIntTexArray[vp + 6] = srcX;
365 mIntTexArray[vp + 7] = srcY + height;
367 mIntVertArray[vp + 0] = dstX;
368 mIntVertArray[vp + 1] = dstY;
370 mIntVertArray[vp + 2] = dstX + width;
371 mIntVertArray[vp + 3] = dstY;
373 mIntVertArray[vp + 4] = dstX + width;
374 mIntVertArray[vp + 5] = dstY + height;
376 mIntVertArray[vp + 6] = dstX;
377 mIntVertArray[vp + 7] = dstY + height;
391 glColor4ub(
static_cast<GLubyte
>(mColor.r),
392 static_cast<GLubyte
>(mColor.g),
393 static_cast<GLubyte
>(mColor.b),
394 static_cast<GLubyte
>(mColor.a));
397void OpenGLGraphics::drawRescaledImagePattern(
const Image *image,
408 if (scaledWidth == 0 || scaledHeight == 0)
414 if (srcW == 0 || srcH == 0)
417 glColor4f(1.0f, 1.0f, 1.0f, image->
mAlpha);
419 bindTexture(Image::mTextureType, image->mGLImage);
421 setTexturingAndBlending(
true);
424 const unsigned int vLimit = vertexBufSize * 4;
427 if (Image::getTextureType() == GL_TEXTURE_2D)
429 const auto tw =
static_cast<float>(image->getTextureWidth());
430 const auto th =
static_cast<float>(image->getTextureHeight());
432 const float texX1 =
static_cast<float>(srcX) / tw;
433 const float texY1 =
static_cast<float>(srcY) / th;
435 const float tFractionW = srcW / tw;
436 const float tFractionH = srcH / th;
438 for (
int py = 0; py < dstH; py += scaledHeight)
440 const int height = (py + scaledHeight >= dstH) ? dstH - py : scaledHeight;
441 const int destY = dstY + py;
442 for (
int px = 0; px < dstW; px += scaledWidth)
444 int width = (px + scaledWidth >= dstW) ? dstW - px : scaledWidth;
445 int destX = dstX + px;
446 const float visibleFractionW = (float) width / scaledWidth;
447 const float visibleFractionH = (float) height / scaledHeight;
449 const float texX2 = texX1 + tFractionW * visibleFractionW;
450 const float texY2 = texY1 + tFractionH * visibleFractionH;
452 mFloatTexArray[vp + 0] = texX1;
453 mFloatTexArray[vp + 1] = texY1;
455 mFloatTexArray[vp + 2] = texX2;
456 mFloatTexArray[vp + 3] = texY1;
458 mFloatTexArray[vp + 4] = texX2;
459 mFloatTexArray[vp + 5] = texY2;
461 mFloatTexArray[vp + 6] = texX1;
462 mFloatTexArray[vp + 7] = texY2;
464 mIntVertArray[vp + 0] = destX;
465 mIntVertArray[vp + 1] = destY;
467 mIntVertArray[vp + 2] = destX + width;
468 mIntVertArray[vp + 3] = destY;
470 mIntVertArray[vp + 4] = destX + width;
471 mIntVertArray[vp + 5] = destY + height;
473 mIntVertArray[vp + 6] = destX;
474 mIntVertArray[vp + 7] = destY + height;
489 const float scaleFactorW = (float) scaledWidth / srcW;
490 const float scaleFactorH = (float) scaledHeight / srcH;
492 for (
int py = 0; py < dstH; py += scaledHeight)
494 const int height = (py + scaledHeight >= dstH) ? dstH - py : scaledHeight;
495 const int destY = dstY + py;
496 for (
int px = 0; px < dstW; px += scaledWidth)
498 int width = (px + scaledWidth >= dstW) ? dstW - px : scaledWidth;
499 int destX = dstX + px;
501 mIntTexArray[vp + 0] = srcX;
502 mIntTexArray[vp + 1] = srcY;
504 mIntTexArray[vp + 2] = srcX + width / scaleFactorW;
505 mIntTexArray[vp + 3] = srcY;
507 mIntTexArray[vp + 4] = srcX + width / scaleFactorW;
508 mIntTexArray[vp + 5] = srcY + height / scaleFactorH;
510 mIntTexArray[vp + 6] = srcX;
511 mIntTexArray[vp + 7] = srcY + height / scaleFactorH;
513 mIntVertArray[vp + 0] = destX;
514 mIntVertArray[vp + 1] = destY;
516 mIntVertArray[vp + 2] = destX + width;
517 mIntVertArray[vp + 3] = destY;
519 mIntVertArray[vp + 4] = destX + width;
520 mIntVertArray[vp + 5] = destY + height;
522 mIntVertArray[vp + 6] = destX;
523 mIntVertArray[vp + 7] = destY + height;
537 glColor4ub(mColor.r, mColor.g, mColor.b, mColor.a);
540void OpenGLGraphics::updateScreen()
542 SDL_GL_SwapWindow(mWindow);
558void OpenGLGraphics::windowToLogical(
int windowX,
int windowY,
559 float &logicalX,
float &logicalY)
const
561 logicalX = windowX / mUserScale;
562 logicalY = windowY / mUserScale;
565SDL_Surface *OpenGLGraphics::getScreenshot()
568 SDL_GL_GetDrawableSize(mWindow, &w, &h);
571 SDL_Surface *screenshot = SDL_CreateRGBSurface(
574 0xff0000, 0x00ff00, 0x0000ff, 0x000000);
576 if (SDL_MUSTLOCK(screenshot))
577 SDL_LockSurface(screenshot);
580 glGetIntegerv(GL_PACK_ALIGNMENT, &pack);
581 glPixelStorei(GL_PACK_ALIGNMENT, 1);
582 glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, screenshot->pixels);
585 unsigned int lineSize = 3 * w;
586 auto* buf = (GLubyte*)malloc(lineSize);
588 for (
int i = 0; i < (h / 2); i++)
590 GLubyte *top = (GLubyte*)screenshot->pixels + lineSize * i;
591 GLubyte *bot = (GLubyte*)screenshot->pixels + lineSize * (h - 1 - i);
593 memcpy(buf, top, lineSize);
594 memcpy(top, bot, lineSize);
595 memcpy(bot, buf, lineSize);
600 glPixelStorei(GL_PACK_ALIGNMENT, pack);
602 if (SDL_MUSTLOCK(screenshot))
603 SDL_UnlockSurface(screenshot);
608bool OpenGLGraphics::pushClipArea(gcn::Rectangle area)
613 if (!mClipStack.empty())
615 transX = -mClipStack.top().xOffset;
616 transY = -mClipStack.top().yOffset;
619 bool result = Graphics::pushClipArea(area);
621 transX += mClipStack.top().xOffset;
622 transY += mClipStack.top().yOffset;
625 glTranslatef(transX, transY, 0);
630void OpenGLGraphics::popClipArea()
632 Graphics::popClipArea();
637void OpenGLGraphics::setColor(
const gcn::Color &color)
640 glColor4ub(color.r, color.g, color.b, color.a);
642 mColorAlpha = (color.a != 255);
645void OpenGLGraphics::updateClipRect()
647 if (mClipRects.empty())
649 glDisable(GL_SCISSOR_TEST);
653 const gcn::Rectangle &clipRect = mClipRects.top();
655 const int x = (int) (clipRect.x * mScaleX);
656 const int y = (int) ((mHeight - clipRect.y - clipRect.height) * mScaleY);
657 const int width = (int) (clipRect.width * mScaleX);
658 const int height = (int) (clipRect.height * mScaleY);
660 glEnable(GL_SCISSOR_TEST);
661 glScissor(x, y, width, height);
664void OpenGLGraphics::drawPoint(
int x,
int y)
666 setTexturingAndBlending(
false);
673void OpenGLGraphics::drawLine(
int x1,
int y1,
int x2,
int y2)
675 setTexturingAndBlending(
false);
678 glVertex2f(x1 + 0.5f, y1 + 0.5f);
679 glVertex2f(x2 + 0.5f, y2 + 0.5f);
683 glVertex2f(x2 + 0.5f, y2 + 0.5f);
687void OpenGLGraphics::drawRectangle(
const gcn::Rectangle &rect)
689 drawRectangle(rect,
false);
692void OpenGLGraphics::fillRectangle(
const gcn::Rectangle &rect)
694 drawRectangle(rect,
true);
697void OpenGLGraphics::setTexturingAndBlending(
bool enable)
703 glEnable(Image::mTextureType);
716 if (mAlpha && !mColorAlpha)
721 else if (!mAlpha && mColorAlpha)
729 glDisable(Image::mTextureType);
735void OpenGLGraphics::drawRectangle(
const gcn::Rectangle &rect,
bool filled)
737 const float offset = filled ? 0 : 0.5f;
739 setTexturingAndBlending(
false);
741 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
745 rect.x + offset, rect.y + offset,
746 rect.x + rect.width - offset, rect.y + offset,
747 rect.x + rect.width - offset, rect.y + rect.height - offset,
748 rect.x + offset, rect.y + rect.height - offset
751 glVertexPointer(2, GL_FLOAT, 0, &vert);
752 glDrawArrays(filled ? GL_QUADS : GL_LINE_LOOP, 0, 4);
754 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
757void OpenGLGraphics::bindTexture(GLenum target, GLuint texture)
759 if (mLastImage != texture)
761 mLastImage = texture;
762 glBindTexture(target, texture);
766inline void OpenGLGraphics::drawQuadArrayfi(
int size)
768 glVertexPointer(2, GL_INT, 0, mIntVertArray);
769 glTexCoordPointer(2, GL_FLOAT, 0, mFloatTexArray);
771 glDrawArrays(GL_QUADS, 0, size / 2);
774inline void OpenGLGraphics::drawQuadArrayii(
int size)
776 glVertexPointer(2, GL_INT, 0, mIntVertArray);
777 glTexCoordPointer(2, GL_INT, 0, mIntTexArray);
779 glDrawArrays(GL_QUADS, 0, size / 2);
void setColor(const gcn::Color &color) override
Defines a class for loading and storing images.
int getHeight() const
Returns the height of the image.
int getWidth() const
Returns the width of the image.
void info(const char *log_text,...) LOG_PRINTF_ATTR