Mana
Loading...
Searching...
No Matches
openglgraphics.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#ifdef USE_OPENGL
23
24#include "openglgraphics.h"
25
26#include "log.h"
27#include "video.h"
28
29#include "resources/image.h"
30
31#ifdef __APPLE__
32#include <OpenGL/OpenGL.h>
33#endif
34
35#include <SDL.h>
36
37#include <cmath>
38
39#ifndef GL_TEXTURE_RECTANGLE_ARB
40#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
41#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
42#endif
43
44const unsigned int vertexBufSize = 500;
45
46GLuint OpenGLGraphics::mLastImage = 0;
47
48std::unique_ptr<OpenGLGraphics> OpenGLGraphics::create(SDL_Window *window,
49 const VideoSettings &settings)
50{
51 SDL_GLContext glContext = SDL_GL_CreateContext(window);
52 if (!glContext)
53 return {};
54
55 if (settings.vsync)
56 SDL_GL_SetSwapInterval(1);
57
58 return std::make_unique<OpenGLGraphics>(window, glContext);
59}
60
61OpenGLGraphics::OpenGLGraphics(SDL_Window *window, SDL_GLContext glContext)
62 : mWindow(window)
63 , mContext(glContext)
64{
65 Image::setLoadAsOpenGL(true);
66
67 mFloatTexArray = new GLfloat[vertexBufSize * 4];
68 mIntTexArray = new GLint[vertexBufSize * 4];
69 mIntVertArray = new GLint[vertexBufSize * 4];
70
71 SDL_GL_GetDrawableSize(mWindow, &mWidth, &mHeight);
72
73 // Setup OpenGL
74 glViewport(0, 0, mWidth, mHeight);
75 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
76
77 char const *glExtensions = (char const *)glGetString(GL_EXTENSIONS);
78 GLint texSize;
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)
82 {
83 Image::mTextureType = GL_TEXTURE_RECTANGLE_ARB;
84 Image::mPowerOfTwoTextures = false;
85 glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &texSize);
86 }
87 else
88 {
89 Image::mTextureType = GL_TEXTURE_2D;
90 Image::mPowerOfTwoTextures = !npotTex;
91 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
92 }
93 Image::mTextureSize = texSize;
94 Log::info("OpenGL texture size: %d pixels%s", Image::mTextureSize,
95 rectTex ? " (rectangle textures)" : "");
96
97 glMatrixMode(GL_TEXTURE);
98 glLoadIdentity();
99
100 glMatrixMode(GL_PROJECTION);
101 glLoadIdentity();
102 glOrtho(0.0, (double)mWidth, (double)mHeight, 0.0, -1.0, 1.0);
103
104 glMatrixMode(GL_MODELVIEW);
105 glLoadIdentity();
106
107 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
108
109 glEnableClientState(GL_VERTEX_ARRAY);
110 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
111}
112
113OpenGLGraphics::~OpenGLGraphics()
114{
115 SDL_GL_DeleteContext(mContext);
116
117 delete[] mFloatTexArray;
118 delete[] mIntTexArray;
119 delete[] mIntVertArray;
120}
121
122void OpenGLGraphics::setVSync(bool sync)
123{
124 SDL_GL_SetSwapInterval(sync ? 1 : 0);
125}
126
127void OpenGLGraphics::setReduceInputLag(bool reduceInputLag)
128{
129 mReduceInputLag = reduceInputLag;
130}
131
132void OpenGLGraphics::updateSize(int windowWidth, int windowHeight, float scale)
133{
134 mUserScale = scale;
135
136 int drawableWidth;
137 int drawableHeight;
138 SDL_GL_GetDrawableSize(mWindow, &drawableWidth, &drawableHeight);
139
140 glViewport(0, 0, drawableWidth, drawableHeight);
141
142 float displayScaleX = windowWidth > 0 ? static_cast<float>(drawableWidth) / windowWidth : 1.0f;
143 float displayScaleY = windowHeight > 0 ? static_cast<float>(drawableHeight) / windowHeight : 1.0f;
144
145 mScaleX = mUserScale * displayScaleX;
146 mScaleY = mUserScale * displayScaleY;
147
148 mWidth = std::ceil(drawableWidth / mScaleX);
149 mHeight = std::ceil(drawableHeight / mScaleY);
150 mScale = mScaleX;
151
152 glMatrixMode(GL_PROJECTION);
153 glLoadIdentity();
154 glOrtho(0.0, (double)mWidth, (double)mHeight, 0.0, -1.0, 1.0);
155}
156
157static inline void drawRescaledQuad(const Image *image,
158 int srcX, int srcY,
159 float dstX, float dstY,
160 int width, int height,
161 float desiredWidth, float desiredHeight)
162{
163 if (Image::getTextureType() == GL_TEXTURE_2D)
164 {
165 // Find OpenGL normalized texture coordinates.
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());
174
175 const GLfloat tex[] =
176 {
177 texX1, texY1,
178 texX2, texY1,
179 texX2, texY2,
180 texX1, texY2
181 };
182
183 const GLfloat vert[] =
184 {
185 dstX, dstY,
186 dstX + desiredWidth, dstY,
187 dstX + desiredWidth, dstY + desiredHeight,
188 dstX, dstY + desiredHeight
189 };
190
191 glVertexPointer(2, GL_FLOAT, 0, &vert);
192 glTexCoordPointer(2, GL_FLOAT, 0, &tex);
193
194 glDrawArrays(GL_QUADS, 0, 4);
195 }
196 else
197 {
198 const GLint tex[] =
199 {
200 srcX, srcY,
201 srcX + width, srcY,
202 srcX + width, srcY + height,
203 srcX, srcY + height
204 };
205 const GLfloat vert[] =
206 {
207 dstX, dstY,
208 dstX + desiredWidth, dstY,
209 dstX + desiredWidth, dstY + desiredHeight,
210 dstX, dstY + desiredHeight
211 };
212
213 glVertexPointer(2, GL_FLOAT, 0, &vert);
214 glTexCoordPointer(2, GL_INT, 0, &tex);
215
216 glDrawArrays(GL_QUADS, 0, 4);
217 }
218}
219
220
221bool OpenGLGraphics::drawRescaledImage(const Image *image, int srcX, int srcY,
222 int dstX, int dstY,
223 int width, int height,
224 int desiredWidth, int desiredHeight,
225 bool useColor)
226{
227 return drawRescaledImageF(image, srcX, srcY, dstX, dstY,
228 width, height, desiredWidth, desiredHeight,
229 useColor);
230}
231
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,
236 bool useColor)
237{
238 if (!image)
239 return false;
240
241 srcX += image->mBounds.x;
242 srcY += image->mBounds.y;
243
244 if (!useColor)
245 glColor4f(1.0f, 1.0f, 1.0f, image->mAlpha);
246
247 bindTexture(Image::mTextureType, image->mGLImage);
248
249 setTexturingAndBlending(true);
250
251 // Draw a textured quad.
252 drawRescaledQuad(image, srcX, srcY, dstX, dstY, width, height,
253 desiredWidth, desiredHeight);
254
255 if (!useColor)
256 {
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));
261 }
262
263 return true;
264}
265
266void OpenGLGraphics::drawImagePattern(const Image *image, int x, int y, int w, int h)
267{
268 if (!image)
269 return;
270
271 const int srcX = image->mBounds.x;
272 const int srcY = image->mBounds.y;
273
274 const int iw = image->getWidth();
275 const int ih = image->getHeight();
276
277 if (iw == 0 || ih == 0)
278 return;
279
280 const auto tw = static_cast<float>(image->getTextureWidth());
281 const auto th = static_cast<float>(image->getTextureHeight());
282
283 glColor4f(1.0f, 1.0f, 1.0f, image->mAlpha);
284
285 bindTexture(Image::mTextureType, image->mGLImage);
286
287 setTexturingAndBlending(true);
288
289 unsigned int vp = 0;
290 const unsigned int vLimit = vertexBufSize * 4;
291 // Draw a set of textured rectangles
292 if (Image::getTextureType() == GL_TEXTURE_2D)
293 {
294 float texX1 = static_cast<float>(srcX) / tw;
295 float texY1 = static_cast<float>(srcY) / th;
296
297 for (int py = 0; py < h; py += ih)
298 {
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)
302 {
303 int width = (px + iw >= w) ? w - px : iw;
304 int dstX = x + px;
305
306 float texX2 = static_cast<float>(srcX + width) / tw;
307 float texY2 = static_cast<float>(srcY + height) / th;
308
309 mFloatTexArray[vp + 0] = texX1;
310 mFloatTexArray[vp + 1] = texY1;
311
312 mFloatTexArray[vp + 2] = texX2;
313 mFloatTexArray[vp + 3] = texY1;
314
315 mFloatTexArray[vp + 4] = texX2;
316 mFloatTexArray[vp + 5] = texY2;
317
318 mFloatTexArray[vp + 6] = texX1;
319 mFloatTexArray[vp + 7] = texY2;
320
321 mIntVertArray[vp + 0] = dstX;
322 mIntVertArray[vp + 1] = dstY;
323
324 mIntVertArray[vp + 2] = dstX + width;
325 mIntVertArray[vp + 3] = dstY;
326
327 mIntVertArray[vp + 4] = dstX + width;
328 mIntVertArray[vp + 5] = dstY + height;
329
330 mIntVertArray[vp + 6] = dstX;
331 mIntVertArray[vp + 7] = dstY + height;
332
333 vp += 8;
334 if (vp >= vLimit)
335 {
336 drawQuadArrayfi(vp);
337 vp = 0;
338 }
339 }
340 }
341 if (vp > 0)
342 drawQuadArrayfi(vp);
343 }
344 else
345 {
346 for (int py = 0; py < h; py += ih)
347 {
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)
351 {
352 int width = (px + iw >= w) ? w - px : iw;
353 int dstX = x + px;
354
355 mIntTexArray[vp + 0] = srcX;
356 mIntTexArray[vp + 1] = srcY;
357
358 mIntTexArray[vp + 2] = srcX + width;
359 mIntTexArray[vp + 3] = srcY;
360
361 mIntTexArray[vp + 4] = srcX + width;
362 mIntTexArray[vp + 5] = srcY + height;
363
364 mIntTexArray[vp + 6] = srcX;
365 mIntTexArray[vp + 7] = srcY + height;
366
367 mIntVertArray[vp + 0] = dstX;
368 mIntVertArray[vp + 1] = dstY;
369
370 mIntVertArray[vp + 2] = dstX + width;
371 mIntVertArray[vp + 3] = dstY;
372
373 mIntVertArray[vp + 4] = dstX + width;
374 mIntVertArray[vp + 5] = dstY + height;
375
376 mIntVertArray[vp + 6] = dstX;
377 mIntVertArray[vp + 7] = dstY + height;
378
379 vp += 8;
380 if (vp >= vLimit)
381 {
382 drawQuadArrayii(vp);
383 vp = 0;
384 }
385 }
386 }
387 if (vp > 0)
388 drawQuadArrayii(vp);
389 }
390
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));
395}
396
397void OpenGLGraphics::drawRescaledImagePattern(const Image *image,
398 int srcX, int srcY,
399 int srcW, int srcH,
400 int dstX, int dstY,
401 int dstW, int dstH,
402 int scaledWidth,
403 int scaledHeight)
404{
405 if (!image)
406 return;
407
408 if (scaledWidth == 0 || scaledHeight == 0)
409 return;
410
411 srcX += image->mBounds.x;
412 srcY += image->mBounds.y;
413
414 if (srcW == 0 || srcH == 0)
415 return;
416
417 glColor4f(1.0f, 1.0f, 1.0f, image->mAlpha);
418
419 bindTexture(Image::mTextureType, image->mGLImage);
420
421 setTexturingAndBlending(true);
422
423 unsigned int vp = 0;
424 const unsigned int vLimit = vertexBufSize * 4;
425
426 // Draw a set of textured rectangles
427 if (Image::getTextureType() == GL_TEXTURE_2D)
428 {
429 const auto tw = static_cast<float>(image->getTextureWidth());
430 const auto th = static_cast<float>(image->getTextureHeight());
431
432 const float texX1 = static_cast<float>(srcX) / tw;
433 const float texY1 = static_cast<float>(srcY) / th;
434
435 const float tFractionW = srcW / tw;
436 const float tFractionH = srcH / th;
437
438 for (int py = 0; py < dstH; py += scaledHeight)
439 {
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)
443 {
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;
448
449 const float texX2 = texX1 + tFractionW * visibleFractionW;
450 const float texY2 = texY1 + tFractionH * visibleFractionH;
451
452 mFloatTexArray[vp + 0] = texX1;
453 mFloatTexArray[vp + 1] = texY1;
454
455 mFloatTexArray[vp + 2] = texX2;
456 mFloatTexArray[vp + 3] = texY1;
457
458 mFloatTexArray[vp + 4] = texX2;
459 mFloatTexArray[vp + 5] = texY2;
460
461 mFloatTexArray[vp + 6] = texX1;
462 mFloatTexArray[vp + 7] = texY2;
463
464 mIntVertArray[vp + 0] = destX;
465 mIntVertArray[vp + 1] = destY;
466
467 mIntVertArray[vp + 2] = destX + width;
468 mIntVertArray[vp + 3] = destY;
469
470 mIntVertArray[vp + 4] = destX + width;
471 mIntVertArray[vp + 5] = destY + height;
472
473 mIntVertArray[vp + 6] = destX;
474 mIntVertArray[vp + 7] = destY + height;
475
476 vp += 8;
477 if (vp >= vLimit)
478 {
479 drawQuadArrayfi(vp);
480 vp = 0;
481 }
482 }
483 }
484 if (vp > 0)
485 drawQuadArrayfi(vp);
486 }
487 else
488 {
489 const float scaleFactorW = (float) scaledWidth / srcW;
490 const float scaleFactorH = (float) scaledHeight / srcH;
491
492 for (int py = 0; py < dstH; py += scaledHeight)
493 {
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)
497 {
498 int width = (px + scaledWidth >= dstW) ? dstW - px : scaledWidth;
499 int destX = dstX + px;
500
501 mIntTexArray[vp + 0] = srcX;
502 mIntTexArray[vp + 1] = srcY;
503
504 mIntTexArray[vp + 2] = srcX + width / scaleFactorW;
505 mIntTexArray[vp + 3] = srcY;
506
507 mIntTexArray[vp + 4] = srcX + width / scaleFactorW;
508 mIntTexArray[vp + 5] = srcY + height / scaleFactorH;
509
510 mIntTexArray[vp + 6] = srcX;
511 mIntTexArray[vp + 7] = srcY + height / scaleFactorH;
512
513 mIntVertArray[vp + 0] = destX;
514 mIntVertArray[vp + 1] = destY;
515
516 mIntVertArray[vp + 2] = destX + width;
517 mIntVertArray[vp + 3] = destY;
518
519 mIntVertArray[vp + 4] = destX + width;
520 mIntVertArray[vp + 5] = destY + height;
521
522 mIntVertArray[vp + 6] = destX;
523 mIntVertArray[vp + 7] = destY + height;
524
525 vp += 8;
526 if (vp >= vLimit)
527 {
528 drawQuadArrayii(vp);
529 vp = 0;
530 }
531 }
532 }
533 if (vp > 0)
534 drawQuadArrayii(vp);
535 }
536
537 glColor4ub(mColor.r, mColor.g, mColor.b, mColor.a);
538}
539
540void OpenGLGraphics::updateScreen()
541{
542 SDL_GL_SwapWindow(mWindow);
543
544 /*
545 * glFinish flushes all OpenGL commands and makes sure they have been
546 * executed before continuing. If we do not do this we allow the next
547 * frame to be prepared while the current one isn't even displaying yet,
548 * which can cause input lag that is especially noticable at mouse
549 * movement.
550 *
551 * The setting is optional since calling glFinish can reduce performance
552 * and increase CPU usage.
553 */
554 if (mReduceInputLag)
555 glFinish();
556}
557
558void OpenGLGraphics::windowToLogical(int windowX, int windowY,
559 float &logicalX, float &logicalY) const
560{
561 logicalX = windowX / mUserScale;
562 logicalY = windowY / mUserScale;
563}
564
565SDL_Surface *OpenGLGraphics::getScreenshot()
566{
567 int w, h;
568 SDL_GL_GetDrawableSize(mWindow, &w, &h);
569 GLint pack = 1;
570
571 SDL_Surface *screenshot = SDL_CreateRGBSurface(
572 SDL_SWSURFACE,
573 w, h, 24,
574 0xff0000, 0x00ff00, 0x0000ff, 0x000000);
575
576 if (SDL_MUSTLOCK(screenshot))
577 SDL_LockSurface(screenshot);
578
579 // Grap the pixel buffer and write it to the SDL surface
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);
583
584 // Flip the screenshot, as OpenGL has 0,0 in bottom left
585 unsigned int lineSize = 3 * w;
586 auto* buf = (GLubyte*)malloc(lineSize);
587
588 for (int i = 0; i < (h / 2); i++)
589 {
590 GLubyte *top = (GLubyte*)screenshot->pixels + lineSize * i;
591 GLubyte *bot = (GLubyte*)screenshot->pixels + lineSize * (h - 1 - i);
592
593 memcpy(buf, top, lineSize);
594 memcpy(top, bot, lineSize);
595 memcpy(bot, buf, lineSize);
596 }
597
598 free(buf);
599
600 glPixelStorei(GL_PACK_ALIGNMENT, pack);
601
602 if (SDL_MUSTLOCK(screenshot))
603 SDL_UnlockSurface(screenshot);
604
605 return screenshot;
606}
607
608bool OpenGLGraphics::pushClipArea(gcn::Rectangle area)
609{
610 int transX = 0;
611 int transY = 0;
612
613 if (!mClipStack.empty())
614 {
615 transX = -mClipStack.top().xOffset;
616 transY = -mClipStack.top().yOffset;
617 }
618
619 bool result = Graphics::pushClipArea(area);
620
621 transX += mClipStack.top().xOffset;
622 transY += mClipStack.top().yOffset;
623
624 glPushMatrix();
625 glTranslatef(transX, transY, 0);
626
627 return result;
628}
629
630void OpenGLGraphics::popClipArea()
631{
632 Graphics::popClipArea();
633
634 glPopMatrix();
635}
636
637void OpenGLGraphics::setColor(const gcn::Color &color)
638{
639 Graphics::setColor(color);
640 glColor4ub(color.r, color.g, color.b, color.a);
641
642 mColorAlpha = (color.a != 255);
643}
644
645void OpenGLGraphics::updateClipRect()
646{
647 if (mClipRects.empty())
648 {
649 glDisable(GL_SCISSOR_TEST);
650 return;
651 }
652
653 const gcn::Rectangle &clipRect = mClipRects.top();
654
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);
659
660 glEnable(GL_SCISSOR_TEST);
661 glScissor(x, y, width, height);
662}
663
664void OpenGLGraphics::drawPoint(int x, int y)
665{
666 setTexturingAndBlending(false);
667
668 glBegin(GL_POINTS);
669 glVertex2i(x, y);
670 glEnd();
671}
672
673void OpenGLGraphics::drawLine(int x1, int y1, int x2, int y2)
674{
675 setTexturingAndBlending(false);
676
677 glBegin(GL_LINES);
678 glVertex2f(x1 + 0.5f, y1 + 0.5f);
679 glVertex2f(x2 + 0.5f, y2 + 0.5f);
680 glEnd();
681
682 glBegin(GL_POINTS);
683 glVertex2f(x2 + 0.5f, y2 + 0.5f);
684 glEnd();
685}
686
687void OpenGLGraphics::drawRectangle(const gcn::Rectangle &rect)
688{
689 drawRectangle(rect, false);
690}
691
692void OpenGLGraphics::fillRectangle(const gcn::Rectangle &rect)
693{
694 drawRectangle(rect, true);
695}
696
697void OpenGLGraphics::setTexturingAndBlending(bool enable)
698{
699 if (enable)
700 {
701 if (!mTexture)
702 {
703 glEnable(Image::mTextureType);
704 mTexture = true;
705 }
706
707 if (!mAlpha)
708 {
709 glEnable(GL_BLEND);
710 mAlpha = true;
711 }
712 }
713 else
714 {
715 mLastImage = 0;
716 if (mAlpha && !mColorAlpha)
717 {
718 glDisable(GL_BLEND);
719 mAlpha = false;
720 }
721 else if (!mAlpha && mColorAlpha)
722 {
723 glEnable(GL_BLEND);
724 mAlpha = true;
725 }
726
727 if (mTexture)
728 {
729 glDisable(Image::mTextureType);
730 mTexture = false;
731 }
732 }
733}
734
735void OpenGLGraphics::drawRectangle(const gcn::Rectangle &rect, bool filled)
736{
737 const float offset = filled ? 0 : 0.5f;
738
739 setTexturingAndBlending(false);
740
741 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
742
743 GLfloat vert[] =
744 {
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
749 };
750
751 glVertexPointer(2, GL_FLOAT, 0, &vert);
752 glDrawArrays(filled ? GL_QUADS : GL_LINE_LOOP, 0, 4);
753
754 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
755}
756
757void OpenGLGraphics::bindTexture(GLenum target, GLuint texture)
758{
759 if (mLastImage != texture)
760 {
761 mLastImage = texture;
762 glBindTexture(target, texture);
763 }
764}
765
766inline void OpenGLGraphics::drawQuadArrayfi(int size)
767{
768 glVertexPointer(2, GL_INT, 0, mIntVertArray);
769 glTexCoordPointer(2, GL_FLOAT, 0, mFloatTexArray);
770
771 glDrawArrays(GL_QUADS, 0, size / 2);
772}
773
774inline void OpenGLGraphics::drawQuadArrayii(int size)
775{
776 glVertexPointer(2, GL_INT, 0, mIntVertArray);
777 glTexCoordPointer(2, GL_INT, 0, mIntTexArray);
778
779 glDrawArrays(GL_QUADS, 0, size / 2);
780}
781
782#endif // USE_OPENGL
void setColor(const gcn::Color &color) override
Definition graphics.h:255
Defines a class for loading and storing images.
Definition image.h:45
int getHeight() const
Returns the height of the image.
Definition image.h:89
int getWidth() const
Returns the width of the image.
Definition image.h:83
SDL_Rect mBounds
Definition image.h:153
float mAlpha
Definition image.h:154
void info(const char *log_text,...) LOG_PRINTF_ATTR
bool vsync
Definition video.h:52