Graphics.cpp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394
  1. /**
  2. * Copyright (c) 2006-2014 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "common/config.h"
  22. #include "common/math.h"
  23. #include "common/Vector.h"
  24. #include "Graphics.h"
  25. #include "window/sdl/Window.h"
  26. #include "Polyline.h"
  27. // C++
  28. #include <vector>
  29. #include <sstream>
  30. #include <algorithm>
  31. #include <iterator>
  32. // C
  33. #include <cmath>
  34. namespace love
  35. {
  36. namespace graphics
  37. {
  38. namespace opengl
  39. {
  40. Graphics::Graphics()
  41. : width(0)
  42. , height(0)
  43. , created(false)
  44. , writingToStencil(false)
  45. , displayedMinReqWarning(false)
  46. {
  47. states.reserve(10);
  48. states.push_back(DisplayState());
  49. currentWindow = love::window::sdl::Window::createSingleton();
  50. int w, h;
  51. love::window::WindowSettings wsettings;
  52. currentWindow->getWindow(w, h, wsettings);
  53. if (currentWindow->isCreated())
  54. setMode(w, h, wsettings.sRGB);
  55. }
  56. Graphics::~Graphics()
  57. {
  58. // We do this manually so the love objects get released before the window.
  59. states.clear();
  60. currentWindow->release();
  61. }
  62. const char *Graphics::getName() const
  63. {
  64. return "love.graphics.opengl";
  65. }
  66. void Graphics::restoreState(const DisplayState &s)
  67. {
  68. setColor(s.color);
  69. setBackgroundColor(s.backgroundColor);
  70. setBlendMode(s.blendMode);
  71. setLineWidth(s.lineWidth);
  72. setLineStyle(s.lineStyle);
  73. setLineJoin(s.lineJoin);
  74. setPointSize(s.pointSize);
  75. if (s.scissor)
  76. setScissor(s.scissorBox.x, s.scissorBox.y, s.scissorBox.w, s.scissorBox.h);
  77. else
  78. setScissor();
  79. setStencilTest(s.stencilTest, s.stencilInvert);
  80. setFont(s.font.get());
  81. setShader(s.shader.get());
  82. setCanvas(s.canvases);
  83. setColorMask(s.colorMask);
  84. setWireframe(s.wireframe);
  85. }
  86. void Graphics::restoreStateChecked(const DisplayState &s)
  87. {
  88. const DisplayState &cur = states.back();
  89. if (*(uint32 *) &s.color.r != *(uint32 *) &cur.color.r)
  90. setColor(s.color);
  91. if (*(uint32 *) &s.backgroundColor.r != *(uint32 *) &cur.backgroundColor.r)
  92. setBackgroundColor(s.backgroundColor);
  93. if (s.blendMode != cur.blendMode)
  94. setBlendMode(s.blendMode);
  95. // These are just simple assignments.
  96. setLineWidth(s.lineWidth);
  97. setLineStyle(s.lineStyle);
  98. setLineJoin(s.lineJoin);
  99. if (s.pointSize != cur.pointSize)
  100. setPointSize(s.pointSize);
  101. if (s.scissor != cur.scissor || (s.scissor && !(s.scissorBox == cur.scissorBox)))
  102. {
  103. if (s.scissor)
  104. setScissor(s.scissorBox.x, s.scissorBox.y, s.scissorBox.w, s.scissorBox.h);
  105. else
  106. setScissor();
  107. }
  108. if (s.stencilTest != cur.stencilTest || s.stencilInvert != cur.stencilInvert)
  109. setStencilTest(s.stencilTest, s.stencilInvert);
  110. setFont(s.font.get());
  111. setShader(s.shader.get());
  112. for (size_t i = 0; i < s.canvases.size() && i < cur.canvases.size(); i++)
  113. {
  114. if (s.canvases[i].get() != cur.canvases[i].get())
  115. {
  116. setCanvas(s.canvases);
  117. break;
  118. }
  119. }
  120. for (int i = 0; i < 4; i++)
  121. {
  122. if (s.colorMask[i] != cur.colorMask[i])
  123. {
  124. setColorMask(s.colorMask);
  125. break;
  126. }
  127. }
  128. if (s.wireframe != cur.wireframe)
  129. setWireframe(s.wireframe);
  130. }
  131. void Graphics::setViewportSize(int width, int height)
  132. {
  133. this->width = width;
  134. this->height = height;
  135. if (!isCreated())
  136. return;
  137. // We want to affect the main screen, not any Canvas that's currently active
  138. // (not that any *should* be active when this is called.)
  139. std::vector<Object::StrongRef<Canvas>> canvases = states.back().canvases;
  140. setCanvas();
  141. // Set the viewport to top-left corner.
  142. gl.setViewport(OpenGL::Viewport(0, 0, width, height));
  143. // If a canvas was bound before this function was called, it needs to be
  144. // made aware of the new system viewport size.
  145. Canvas::systemViewport = gl.getViewport();
  146. // Set up the projection matrix
  147. gl.matrices.projection.back() = Matrix::ortho(0.0, width, height, 0.0);
  148. // Restore the previously active Canvas.
  149. setCanvas(canvases);
  150. }
  151. bool Graphics::setMode(int width, int height, bool &sRGB)
  152. {
  153. this->width = width;
  154. this->height = height;
  155. gl.initContext();
  156. // Does the system meet LOVE's minimum requirements for graphics?
  157. if (!(GLAD_VERSION_2_0 && Shader::isSupported() && Canvas::isSupported())
  158. && !displayedMinReqWarning)
  159. {
  160. love::window::Window::MessageBoxType type = love::window::Window::MESSAGEBOX_ERROR;
  161. std::string title = "Minimum system requirements not met!";
  162. std::string message;
  163. message += "Detected OpenGL version: ";
  164. message += (const char *) glGetString(GL_VERSION);
  165. message += "\nRequired OpenGL version: 2.1."; // -ish
  166. message += "\nThe program may crash or have graphical issues.";
  167. ::printf("%s\n%s\n", title.c_str(), message.c_str());
  168. currentWindow->showMessageBox(type, title, message, true);
  169. // We should only show the message once, instead of after every setMode.
  170. displayedMinReqWarning = true;
  171. }
  172. // Okay, setup OpenGL.
  173. gl.setupContext();
  174. created = true;
  175. setViewportSize(width, height);
  176. // Make sure antialiasing works when set elsewhere
  177. glEnable(GL_MULTISAMPLE);
  178. // Enable blending
  179. glEnable(GL_BLEND);
  180. // Enable all color component writes.
  181. bool colormask[] = {true, true, true, true};
  182. setColorMask(colormask);
  183. // Auto-generated mipmaps should be the best quality possible
  184. glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
  185. // Enable textures
  186. glEnable(GL_TEXTURE_2D);
  187. gl.setTextureUnit(0);
  188. // Set pixel row alignment
  189. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  190. // Set whether drawing converts input from linear -> sRGB colorspace.
  191. if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
  192. {
  193. if (sRGB)
  194. glEnable(GL_FRAMEBUFFER_SRGB);
  195. else
  196. glDisable(GL_FRAMEBUFFER_SRGB);
  197. }
  198. else
  199. sRGB = false;
  200. Canvas::screenHasSRGB = sRGB;
  201. bool enabledebug = false;
  202. if (GLAD_VERSION_3_0)
  203. {
  204. // Enable OpenGL's debug output if a debug context has been created.
  205. GLint flags = 0;
  206. glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
  207. enabledebug = (flags & GL_CONTEXT_FLAG_DEBUG_BIT) != 0;
  208. }
  209. setDebug(enabledebug);
  210. // Reload all volatile objects.
  211. if (!Volatile::loadAll())
  212. std::cerr << "Could not reload all volatile objects." << std::endl;
  213. // Restore the graphics state.
  214. restoreState(states.back());
  215. pixel_size_stack.clear();
  216. pixel_size_stack.reserve(5);
  217. pixel_size_stack.push_back(1);
  218. return true;
  219. }
  220. void Graphics::unSetMode()
  221. {
  222. if (!isCreated())
  223. return;
  224. // Unload all volatile objects. These must be reloaded after the display
  225. // mode change.
  226. Volatile::unloadAll();
  227. gl.deInitContext();
  228. created = false;
  229. }
  230. static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, const GLvoid* /*usr*/)
  231. {
  232. // Human-readable strings for the debug info.
  233. const char *sourceStr = OpenGL::debugSourceString(source);
  234. const char *typeStr = OpenGL::debugTypeString(type);
  235. const char *severityStr = OpenGL::debugSeverityString(severity);
  236. const char *fmt = "OpenGL: %s [source=%s, type=%s, severity=%s, id=%d]\n";
  237. printf(fmt, msg, sourceStr, typeStr, severityStr, id);
  238. }
  239. void Graphics::setDebug(bool enable)
  240. {
  241. // Make sure debug output is supported. The AMD ext. is a bit different
  242. // so we don't make use of it, since AMD drivers now support KHR_debug.
  243. if (!(GLAD_VERSION_4_3 || GLAD_KHR_debug || GLAD_ARB_debug_output))
  244. return;
  245. // Ugly hack to reduce code duplication.
  246. if (GLAD_ARB_debug_output && !(GLAD_VERSION_4_3 || GLAD_KHR_debug))
  247. {
  248. fp_glDebugMessageCallback = (pfn_glDebugMessageCallback) fp_glDebugMessageCallbackARB;
  249. fp_glDebugMessageControl = (pfn_glDebugMessageControl) fp_glDebugMessageControlARB;
  250. }
  251. if (!enable)
  252. {
  253. // Disable the debug callback function.
  254. glDebugMessageCallback(nullptr, nullptr);
  255. // We can disable debug output entirely with KHR_debug.
  256. if (GLAD_VERSION_4_3 || GLAD_KHR_debug)
  257. glDisable(GL_DEBUG_OUTPUT);
  258. return;
  259. }
  260. // We don't want asynchronous debug output.
  261. glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
  262. glDebugMessageCallback(debugCB, nullptr);
  263. // Initially, enable everything.
  264. glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
  265. // Disable messages about deprecated OpenGL functionality.
  266. glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE);
  267. glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE);
  268. if (GLAD_VERSION_4_3 || GLAD_KHR_debug)
  269. glEnable(GL_DEBUG_OUTPUT);
  270. ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n");
  271. }
  272. void Graphics::reset()
  273. {
  274. DisplayState s;
  275. drawToStencilBuffer(false);
  276. restoreState(s);
  277. origin();
  278. }
  279. void Graphics::clear(ClearType type)
  280. {
  281. GLbitfield mask = 0;
  282. switch (type)
  283. {
  284. case CLEAR_ALL:
  285. default:
  286. mask = GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
  287. break;
  288. case CLEAR_STENCIL:
  289. mask = GL_STENCIL_BUFFER_BIT;
  290. break;
  291. }
  292. glClear(mask);
  293. }
  294. void Graphics::present()
  295. {
  296. currentWindow->swapBuffers();
  297. }
  298. int Graphics::getWidth() const
  299. {
  300. return width;
  301. }
  302. int Graphics::getHeight() const
  303. {
  304. return height;
  305. }
  306. bool Graphics::isCreated() const
  307. {
  308. return created;
  309. }
  310. void Graphics::setScissor(int x, int y, int width, int height)
  311. {
  312. OpenGL::Viewport box(x, y, width, height);
  313. states.back().scissor = true;
  314. glEnable(GL_SCISSOR_TEST);
  315. // OpenGL's reversed y-coordinate is compensated for in OpenGL::setScissor.
  316. gl.setScissor(box);
  317. states.back().scissorBox = box;
  318. }
  319. void Graphics::setScissor()
  320. {
  321. states.back().scissor = false;
  322. glDisable(GL_SCISSOR_TEST);
  323. }
  324. bool Graphics::getScissor(int &x, int &y, int &width, int &height) const
  325. {
  326. OpenGL::Viewport scissor = gl.getScissor();
  327. x = scissor.x;
  328. y = scissor.y;
  329. width = scissor.w;
  330. height = scissor.h;
  331. return states.back().scissor;
  332. }
  333. void Graphics::drawToStencilBuffer(bool enable)
  334. {
  335. if (writingToStencil == enable)
  336. return;
  337. writingToStencil = enable;
  338. if (!enable)
  339. {
  340. const DisplayState &state = states.back();
  341. // Revert the color write mask.
  342. setColorMask(state.colorMask);
  343. // Use the user-set stencil test state when writes are disabled.
  344. setStencilTest(state.stencilTest, state.stencilInvert);
  345. return;
  346. }
  347. // Make sure the active canvas has a stencil buffer.
  348. if (Canvas::current)
  349. Canvas::current->checkCreateStencil();
  350. // Disable color writes but don't save the state for it.
  351. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  352. // The stencil test must be enabled in order to write to the stencil buffer.
  353. glEnable(GL_STENCIL_TEST);
  354. glStencilFunc(GL_ALWAYS, 1, 1);
  355. glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  356. }
  357. void Graphics::setStencilTest(bool enable, bool invert)
  358. {
  359. DisplayState &state = states.back();
  360. state.stencilTest = enable;
  361. state.stencilInvert = invert;
  362. if (writingToStencil)
  363. return;
  364. if (!enable)
  365. {
  366. glDisable(GL_STENCIL_TEST);
  367. return;
  368. }
  369. // Make sure the active canvas has a stencil buffer.
  370. if (Canvas::current)
  371. Canvas::current->checkCreateStencil();
  372. glEnable(GL_STENCIL_TEST);
  373. glStencilFunc(GL_EQUAL, invert ? 0 : 1, 1);
  374. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  375. }
  376. void Graphics::getStencilTest(bool &enable, bool &invert)
  377. {
  378. const DisplayState &state = states.back();
  379. enable = state.stencilTest;
  380. invert = state.stencilInvert;
  381. }
  382. Image *Graphics::newImage(love::image::ImageData *data, const Image::Flags &flags)
  383. {
  384. // Create the image.
  385. Image *image = new Image(data, flags);
  386. if (!isCreated())
  387. return image;
  388. bool success = false;
  389. try
  390. {
  391. success = image->load();
  392. }
  393. catch(love::Exception &)
  394. {
  395. image->release();
  396. throw;
  397. }
  398. if (!success)
  399. {
  400. image->release();
  401. return nullptr;
  402. }
  403. return image;
  404. }
  405. Image *Graphics::newImage(love::image::CompressedData *cdata, const Image::Flags &flags)
  406. {
  407. // Create the image.
  408. Image *image = new Image(cdata, flags);
  409. if (!isCreated())
  410. return image;
  411. bool success = false;
  412. try
  413. {
  414. success = image->load();
  415. }
  416. catch(love::Exception &)
  417. {
  418. image->release();
  419. throw;
  420. }
  421. if (!success)
  422. {
  423. image->release();
  424. return nullptr;
  425. }
  426. return image;
  427. }
  428. Quad *Graphics::newQuad(Quad::Viewport v, float sw, float sh)
  429. {
  430. return new Quad(v, sw, sh);
  431. }
  432. Font *Graphics::newFont(love::font::Rasterizer *r, const Texture::Filter &filter)
  433. {
  434. return new Font(r, filter);
  435. }
  436. SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, int usage)
  437. {
  438. return new SpriteBatch(texture, size, usage);
  439. }
  440. ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
  441. {
  442. return new ParticleSystem(texture, size);
  443. }
  444. Canvas *Graphics::newCanvas(int width, int height, Canvas::Format format, int msaa)
  445. {
  446. if (!Canvas::isFormatSupported(format))
  447. {
  448. const char *fstr = "rgba8";
  449. Canvas::getConstant(format, fstr);
  450. throw love::Exception("The %s canvas format is not supported by your OpenGL implementation.", fstr);
  451. }
  452. if (width > gl.getMaxTextureSize())
  453. throw Exception("Cannot create canvas: width of %d pixels is too large for this system.", width);
  454. else if (height > gl.getMaxTextureSize())
  455. throw Exception("Cannot create canvas: height of %d pixels is too large for this system.", height);
  456. while (GL_NO_ERROR != glGetError())
  457. /* clear opengl error flag */;
  458. Canvas *canvas = new Canvas(width, height, format, msaa);
  459. GLenum err = canvas->getStatus();
  460. // everything ok, return canvas (early out)
  461. if (err == GL_FRAMEBUFFER_COMPLETE)
  462. return canvas;
  463. // create error message
  464. std::stringstream error_string;
  465. error_string << "Cannot create canvas: ";
  466. switch (err)
  467. {
  468. case GL_FRAMEBUFFER_UNSUPPORTED:
  469. error_string << "Not supported by your OpenGL implementation.";
  470. break;
  471. // remaining error codes are highly unlikely:
  472. case GL_FRAMEBUFFER_UNDEFINED:
  473. case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
  474. case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
  475. case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
  476. case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
  477. case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
  478. error_string << "Error in implementation. Possible fix: Make canvas width and height powers of two.";
  479. break;
  480. default:
  481. // my intel hda card wrongly returns 0 to glCheckFramebufferStatus() but sets
  482. // no error flag. I think it meant to return GL_FRAMEBUFFER_UNSUPPORTED, but who
  483. // knows.
  484. if (glGetError() == GL_NO_ERROR)
  485. error_string << "May not be supported by your OpenGL implementation.";
  486. // the remaining error is an indication of a serious fuckup since it should
  487. // only be returned if glCheckFramebufferStatus() was called with the wrong
  488. // arguments.
  489. else
  490. error_string << "Cannot create canvas: Aliens did it (OpenGL error code: " << glGetError() << ")";
  491. }
  492. canvas->release();
  493. throw Exception("%s", error_string.str().c_str());
  494. return nullptr; // never reached
  495. }
  496. Shader *Graphics::newShader(const Shader::ShaderSources &sources)
  497. {
  498. return new Shader(sources);
  499. }
  500. Mesh *Graphics::newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode mode)
  501. {
  502. return new Mesh(vertices, mode);
  503. }
  504. Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode mode)
  505. {
  506. return new Mesh(vertexcount, mode);
  507. }
  508. void Graphics::setColor(const Color &c)
  509. {
  510. gl.setColor(c);
  511. states.back().color = c;
  512. }
  513. Color Graphics::getColor() const
  514. {
  515. return states.back().color;
  516. }
  517. void Graphics::setBackgroundColor(const Color &c)
  518. {
  519. gl.setClearColor(c);
  520. states.back().backgroundColor = c;
  521. }
  522. Color Graphics::getBackgroundColor() const
  523. {
  524. return states.back().backgroundColor;
  525. }
  526. void Graphics::setFont(Font *font)
  527. {
  528. DisplayState &state = states.back();
  529. state.font.set(font);
  530. }
  531. Font *Graphics::getFont() const
  532. {
  533. return states.back().font.get();
  534. }
  535. void Graphics::setShader(Shader *shader)
  536. {
  537. if (shader == nullptr)
  538. return setShader();
  539. DisplayState &state = states.back();
  540. shader->attach();
  541. state.shader.set(shader);
  542. }
  543. void Graphics::setShader()
  544. {
  545. DisplayState &state = states.back();
  546. Shader::detach();
  547. state.shader.set(nullptr);
  548. }
  549. Shader *Graphics::getShader() const
  550. {
  551. return states.back().shader.get();
  552. }
  553. void Graphics::setCanvas(Canvas *canvas)
  554. {
  555. if (canvas == nullptr)
  556. return setCanvas();
  557. DisplayState &state = states.back();
  558. canvas->startGrab();
  559. std::vector<Object::StrongRef<Canvas>> canvasref;
  560. canvasref.push_back(canvas);
  561. std::swap(state.canvases, canvasref);
  562. }
  563. void Graphics::setCanvas(const std::vector<Canvas *> &canvases)
  564. {
  565. if (canvases.size() == 0)
  566. return setCanvas();
  567. else if (canvases.size() == 1)
  568. return setCanvas(canvases[0]);
  569. DisplayState &state = states.back();
  570. auto attachments = std::vector<Canvas *>(canvases.begin() + 1, canvases.end());
  571. canvases[0]->startGrab(attachments);
  572. std::vector<Object::StrongRef<Canvas>> canvasrefs;
  573. canvasrefs.reserve(canvases.size());
  574. for (Canvas *c : canvases)
  575. canvasrefs.push_back(c);
  576. std::swap(state.canvases, canvasrefs);
  577. }
  578. void Graphics::setCanvas(const std::vector<Object::StrongRef<Canvas>> &canvases)
  579. {
  580. std::vector<Canvas *> canvaslist;
  581. canvaslist.reserve(canvases.size());
  582. for (const Object::StrongRef<Canvas> &c : canvases)
  583. canvaslist.push_back(c.get());
  584. return setCanvas(canvaslist);
  585. }
  586. void Graphics::setCanvas()
  587. {
  588. DisplayState &state = states.back();
  589. if (Canvas::current != nullptr)
  590. Canvas::current->stopGrab();
  591. state.canvases.clear();
  592. }
  593. std::vector<Canvas *> Graphics::getCanvas() const
  594. {
  595. std::vector<Canvas *> canvases;
  596. canvases.reserve(states.back().canvases.size());
  597. for (const Object::StrongRef<Canvas> &c : states.back().canvases)
  598. canvases.push_back(c.get());
  599. return canvases;
  600. }
  601. void Graphics::setColorMask(const bool mask[4])
  602. {
  603. for (int i = 0; i < 4; i++)
  604. states.back().colorMask[i] = mask[i];
  605. glColorMask(mask[0], mask[1], mask[2], mask[3]);
  606. }
  607. const bool *Graphics::getColorMask() const
  608. {
  609. return states.back().colorMask;
  610. }
  611. void Graphics::setBlendMode(Graphics::BlendMode mode)
  612. {
  613. OpenGL::BlendState blend = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD};
  614. switch (mode)
  615. {
  616. case BLEND_ALPHA:
  617. blend.srcRGB = GL_SRC_ALPHA;
  618. blend.srcA = GL_ONE;
  619. blend.dstRGB = blend.dstA = GL_ONE_MINUS_SRC_ALPHA;
  620. break;
  621. case BLEND_MULTIPLY:
  622. blend.srcRGB = blend.srcA = GL_DST_COLOR;
  623. blend.dstRGB = blend.dstA = GL_ZERO;
  624. break;
  625. case BLEND_PREMULTIPLIED:
  626. blend.srcRGB = blend.srcA = GL_ONE;
  627. blend.dstRGB = blend.dstA = GL_ONE_MINUS_SRC_ALPHA;
  628. break;
  629. case BLEND_SUBTRACT:
  630. blend.func = GL_FUNC_REVERSE_SUBTRACT;
  631. case BLEND_ADD:
  632. blend.srcRGB = blend.srcA = GL_SRC_ALPHA;
  633. blend.dstRGB = blend.dstA = GL_ONE;
  634. break;
  635. case BLEND_SCREEN:
  636. blend.srcRGB = blend.srcA = GL_ONE;
  637. blend.dstRGB = blend.dstA = GL_ONE_MINUS_SRC_COLOR;
  638. break;
  639. case BLEND_REPLACE:
  640. default:
  641. blend.srcRGB = blend.srcA = GL_ONE;
  642. blend.dstRGB = blend.dstA = GL_ZERO;
  643. break;
  644. }
  645. gl.setBlendState(blend);
  646. states.back().blendMode = mode;
  647. }
  648. Graphics::BlendMode Graphics::getBlendMode() const
  649. {
  650. return states.back().blendMode;
  651. }
  652. void Graphics::setDefaultFilter(const Texture::Filter &f)
  653. {
  654. Texture::setDefaultFilter(f);
  655. }
  656. const Texture::Filter &Graphics::getDefaultFilter() const
  657. {
  658. return Texture::getDefaultFilter();
  659. }
  660. void Graphics::setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness)
  661. {
  662. Image::setDefaultMipmapFilter(filter);
  663. Image::setDefaultMipmapSharpness(sharpness);
  664. }
  665. void Graphics::getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const
  666. {
  667. *filter = Image::getDefaultMipmapFilter();
  668. *sharpness = Image::getDefaultMipmapSharpness();
  669. }
  670. void Graphics::setLineWidth(float width)
  671. {
  672. states.back().lineWidth = width;
  673. }
  674. void Graphics::setLineStyle(Graphics::LineStyle style)
  675. {
  676. states.back().lineStyle = style;
  677. }
  678. void Graphics::setLineJoin(Graphics::LineJoin join)
  679. {
  680. states.back().lineJoin = join;
  681. }
  682. float Graphics::getLineWidth() const
  683. {
  684. return states.back().lineWidth;
  685. }
  686. Graphics::LineStyle Graphics::getLineStyle() const
  687. {
  688. return states.back().lineStyle;
  689. }
  690. Graphics::LineJoin Graphics::getLineJoin() const
  691. {
  692. return states.back().lineJoin;
  693. }
  694. void Graphics::setPointSize(float size)
  695. {
  696. glPointSize(size);
  697. states.back().pointSize = size;
  698. }
  699. float Graphics::getPointSize() const
  700. {
  701. return states.back().pointSize;
  702. }
  703. void Graphics::setWireframe(bool enable)
  704. {
  705. glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL);
  706. states.back().wireframe = enable;
  707. }
  708. bool Graphics::isWireframe() const
  709. {
  710. return states.back().wireframe;
  711. }
  712. void Graphics::print(const std::string &str, float x, float y , float angle, float sx, float sy, float ox, float oy, float kx, float ky)
  713. {
  714. DisplayState &state = states.back();
  715. if (state.font.get() != nullptr)
  716. state.font->print(str, x, y, 0.0, angle, sx, sy, ox, oy, kx, ky);
  717. }
  718. void Graphics::printf(const std::string &str, float x, float y, float wrap, AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
  719. {
  720. DisplayState &state = states.back();
  721. if (state.font.get() == nullptr)
  722. return;
  723. if (wrap < 0.0f)
  724. throw love::Exception("Horizontal wrap limit cannot be negative.");
  725. using std::string;
  726. using std::vector;
  727. // wrappedlines indicates which lines were automatically wrapped. It's
  728. // guaranteed to have the same number of elements as lines_to_draw.
  729. vector<bool> wrappedlines;
  730. vector<string> lines_to_draw = state.font->getWrap(str, wrap, 0, &wrappedlines);
  731. static Matrix t;
  732. t.setTransformation(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
  733. OpenGL::TempTransform transform(gl);
  734. transform.get() *= t;
  735. x = y = 0.0f;
  736. // now for the actual printing
  737. vector<string>::const_iterator line_iter, line_end = lines_to_draw.end();
  738. float extra_spacing = 0.0f;
  739. int num_spaces = 0;
  740. int i = 0;
  741. for (line_iter = lines_to_draw.begin(); line_iter != line_end; ++line_iter)
  742. {
  743. float width = static_cast<float>(state.font->getWidth(*line_iter));
  744. switch (align)
  745. {
  746. case ALIGN_RIGHT:
  747. state.font->print(*line_iter, ceilf(x + (wrap - width)), ceilf(y), 0.0f);
  748. break;
  749. case ALIGN_CENTER:
  750. state.font->print(*line_iter, ceilf(x + (wrap - width) / 2), ceilf(y), 0.0f);
  751. break;
  752. case ALIGN_JUSTIFY:
  753. num_spaces = std::count(line_iter->begin(), line_iter->end(), ' ');
  754. if (wrappedlines[i] && num_spaces >= 1)
  755. extra_spacing = (wrap - width) / float(num_spaces);
  756. else
  757. extra_spacing = 0.0f;
  758. state.font->print(*line_iter, ceilf(x), ceilf(y), extra_spacing);
  759. break;
  760. case ALIGN_LEFT:
  761. default:
  762. state.font->print(*line_iter, ceilf(x), ceilf(y), 0.0f);
  763. break;
  764. }
  765. y += state.font->getHeight() * state.font->getLineHeight();
  766. i++;
  767. }
  768. }
  769. /**
  770. * Primitives
  771. **/
  772. void Graphics::point(float x, float y)
  773. {
  774. gl.prepareDraw();
  775. gl.bindTexture(0);
  776. glBegin(GL_POINTS);
  777. glVertex2f(x, y);
  778. glEnd();
  779. }
  780. void Graphics::polyline(const float *coords, size_t count)
  781. {
  782. DisplayState &state = states.back();
  783. if (state.lineJoin == LINE_JOIN_NONE)
  784. {
  785. NoneJoinPolyline line;
  786. line.render(coords, count, state.lineWidth * .5f, float(pixel_size_stack.back()), state.lineStyle == LINE_SMOOTH);
  787. line.draw();
  788. }
  789. else if (state.lineJoin == LINE_JOIN_BEVEL)
  790. {
  791. BevelJoinPolyline line;
  792. line.render(coords, count, state.lineWidth * .5f, float(pixel_size_stack.back()), state.lineStyle == LINE_SMOOTH);
  793. line.draw();
  794. }
  795. else // LINE_JOIN_MITER
  796. {
  797. MiterJoinPolyline line;
  798. line.render(coords, count, state.lineWidth * .5f, float(pixel_size_stack.back()), state.lineStyle == LINE_SMOOTH);
  799. line.draw();
  800. }
  801. }
  802. void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h)
  803. {
  804. float coords[] = {x,y, x,y+h, x+w,y+h, x+w,y, x,y};
  805. polygon(mode, coords, 5 * 2);
  806. }
  807. void Graphics::circle(DrawMode mode, float x, float y, float radius, int points)
  808. {
  809. float two_pi = static_cast<float>(LOVE_M_PI * 2);
  810. if (points <= 0) points = 1;
  811. float angle_shift = (two_pi / points);
  812. float phi = .0f;
  813. float *coords = new float[2 * (points + 1)];
  814. for (int i = 0; i < points; ++i, phi += angle_shift)
  815. {
  816. coords[2*i] = x + radius * cosf(phi);
  817. coords[2*i+1] = y + radius * sinf(phi);
  818. }
  819. coords[2*points] = coords[0];
  820. coords[2*points+1] = coords[1];
  821. polygon(mode, coords, (points + 1) * 2);
  822. delete[] coords;
  823. }
  824. void Graphics::arc(DrawMode mode, float x, float y, float radius, float angle1, float angle2, int points)
  825. {
  826. // Nothing to display with no points or equal angles. (Or is there with line mode?)
  827. if (points <= 0 || angle1 == angle2)
  828. return;
  829. // Oh, you want to draw a circle?
  830. if (fabs(angle1 - angle2) >= 2.0f * (float) LOVE_M_PI)
  831. {
  832. circle(mode, x, y, radius, points);
  833. return;
  834. }
  835. float angle_shift = (angle2 - angle1) / points;
  836. // Bail on precision issues.
  837. if (angle_shift == 0.0)
  838. return;
  839. float phi = angle1;
  840. int num_coords = (points + 3) * 2;
  841. float *coords = new float[num_coords];
  842. coords[0] = coords[num_coords - 2] = x;
  843. coords[1] = coords[num_coords - 1] = y;
  844. for (int i = 0; i <= points; ++i, phi += angle_shift)
  845. {
  846. coords[2 * (i+1)] = x + radius * cosf(phi);
  847. coords[2 * (i+1) + 1] = y + radius * sinf(phi);
  848. }
  849. // GL_POLYGON can only fill-draw convex polygons, so we need to do stuff manually here
  850. if (mode == DRAW_LINE)
  851. {
  852. polyline(coords, num_coords); // Artifacts at sharp angles if set to looping.
  853. }
  854. else
  855. {
  856. gl.prepareDraw();
  857. gl.bindTexture(0);
  858. glEnableClientState(GL_VERTEX_ARRAY);
  859. glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *) coords);
  860. glDrawArrays(GL_TRIANGLE_FAN, 0, points + 2);
  861. glDisableClientState(GL_VERTEX_ARRAY);
  862. }
  863. delete[] coords;
  864. }
  865. /// @param mode the draw mode
  866. /// @param coords the coordinate array
  867. /// @param count the number of coordinates/size of the array
  868. void Graphics::polygon(DrawMode mode, const float *coords, size_t count)
  869. {
  870. // coords is an array of a closed loop of vertices, i.e.
  871. // coords[count-2] = coords[0], coords[count-1] = coords[1]
  872. if (mode == DRAW_LINE)
  873. {
  874. polyline(coords, count);
  875. }
  876. else
  877. {
  878. gl.prepareDraw();
  879. gl.bindTexture(0);
  880. glEnableClientState(GL_VERTEX_ARRAY);
  881. glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *)coords);
  882. glDrawArrays(GL_POLYGON, 0, count/2-1); // opengl will close the polygon for us
  883. glDisableClientState(GL_VERTEX_ARRAY);
  884. }
  885. }
  886. love::image::ImageData *Graphics::newScreenshot(love::image::Image *image, bool copyAlpha)
  887. {
  888. // Temporarily unbind the currently active canvas (glReadPixels reads the
  889. // active framebuffer, not the main one.)
  890. std::vector<Object::StrongRef<Canvas>> canvases = states.back().canvases;
  891. setCanvas();
  892. int w = getWidth();
  893. int h = getHeight();
  894. int row = 4*w;
  895. int size = row*h;
  896. GLubyte *pixels = 0;
  897. GLubyte *screenshot = 0;
  898. try
  899. {
  900. pixels = new GLubyte[size];
  901. screenshot = new GLubyte[size];
  902. }
  903. catch (std::exception &)
  904. {
  905. delete[] pixels;
  906. delete[] screenshot;
  907. setCanvas(canvases);
  908. throw love::Exception("Out of memory.");
  909. }
  910. glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  911. if (!copyAlpha)
  912. {
  913. // Replace alpha values with full opacity.
  914. for (int i = 3; i < size; i += 4)
  915. pixels[i] = 255;
  916. }
  917. // OpenGL sucks and reads pixels from the lower-left. Let's fix that.
  918. GLubyte *src = pixels - row, *dst = screenshot + size;
  919. for (int i = 0; i < h; ++i)
  920. memcpy(dst-=row, src+=row, row);
  921. delete[] pixels;
  922. love::image::ImageData *img = 0;
  923. try
  924. {
  925. // Tell the new ImageData that it owns the screenshot data, so we don't
  926. // need to delete it here.
  927. img = image->newImageData(w, h, (void *) screenshot, true);
  928. }
  929. catch (love::Exception &)
  930. {
  931. delete[] screenshot;
  932. setCanvas(canvases);
  933. throw;
  934. }
  935. // Re-bind the active canvas, if necessary.
  936. setCanvas(canvases);
  937. return img;
  938. }
  939. Graphics::RendererInfo Graphics::getRendererInfo() const
  940. {
  941. RendererInfo info;
  942. info.name = "OpenGL";
  943. const char *str = (const char *) glGetString(GL_VERSION);
  944. if (str)
  945. info.version = str;
  946. else
  947. throw love::Exception("Cannot retrieve renderer version information.");
  948. str = (const char *) glGetString(GL_VENDOR);
  949. if (str)
  950. info.vendor = str;
  951. else
  952. throw love::Exception("Cannot retrieve renderer vendor information.");
  953. str = (const char *) glGetString(GL_RENDERER);
  954. if (str)
  955. info.device = str;
  956. else
  957. throw love::Exception("Cannot retrieve renderer device information.");
  958. return info;
  959. }
  960. double Graphics::getSystemLimit(SystemLimit limittype) const
  961. {
  962. double limit = 0.0;
  963. switch (limittype)
  964. {
  965. case Graphics::LIMIT_POINT_SIZE:
  966. {
  967. GLfloat limits[2];
  968. glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, limits);
  969. limit = limits[1];
  970. }
  971. break;
  972. case Graphics::LIMIT_TEXTURE_SIZE:
  973. limit = (double) gl.getMaxTextureSize();
  974. break;
  975. case Graphics::LIMIT_MULTI_CANVAS:
  976. limit = (double) gl.getMaxRenderTargets();
  977. break;
  978. case Graphics::LIMIT_CANVAS_MSAA:
  979. if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object
  980. || GLAD_EXT_framebuffer_multisample)
  981. {
  982. GLint intlimit = 0;
  983. glGetIntegerv(GL_MAX_SAMPLES, &intlimit);
  984. limit = (double) intlimit;
  985. }
  986. break;
  987. default:
  988. break;
  989. }
  990. return limit;
  991. }
  992. bool Graphics::isSupported(Support feature) const
  993. {
  994. switch (feature)
  995. {
  996. case SUPPORT_MULTI_CANVAS:
  997. return Canvas::isMultiCanvasSupported();
  998. case SUPPORT_SRGB:
  999. // sRGB support for the screen is guaranteed if it's supported as a
  1000. // Canvas format.
  1001. return Canvas::isFormatSupported(Canvas::FORMAT_SRGB);
  1002. default:
  1003. return false;
  1004. }
  1005. }
  1006. void Graphics::push(StackType type)
  1007. {
  1008. if (stackTypes.size() == MAX_USER_STACK_DEPTH)
  1009. throw Exception("Maximum stack depth reached (more pushes than pops?)");
  1010. gl.pushTransform();
  1011. pixel_size_stack.push_back(pixel_size_stack.back());
  1012. if (type == STACK_ALL)
  1013. states.push_back(states.back());
  1014. stackTypes.push_back(type);
  1015. }
  1016. void Graphics::pop()
  1017. {
  1018. if (stackTypes.size() < 1)
  1019. throw Exception("Minimum stack depth reached (more pops than pushes?)");
  1020. gl.popTransform();
  1021. pixel_size_stack.pop_back();
  1022. if (stackTypes.back() == STACK_ALL)
  1023. {
  1024. DisplayState &newstate = states[states.size() - 2];
  1025. // Hack: the Lua-facing love.graphics.print function will set the current
  1026. // font if needed, but only on its first call... we always want a font.
  1027. if (newstate.font.get() == nullptr)
  1028. newstate.font.set(states.back().font.get());
  1029. restoreStateChecked(newstate);
  1030. // The last two states in the stack should be equal now.
  1031. states.pop_back();
  1032. }
  1033. stackTypes.pop_back();
  1034. }
  1035. void Graphics::rotate(float r)
  1036. {
  1037. gl.getTransform().rotate(r);
  1038. }
  1039. void Graphics::scale(float x, float y)
  1040. {
  1041. gl.getTransform().scale(x, y);
  1042. pixel_size_stack.back() *= 2. / (fabs(x) + fabs(y));
  1043. }
  1044. void Graphics::translate(float x, float y)
  1045. {
  1046. gl.getTransform().translate(x, y);
  1047. }
  1048. void Graphics::shear(float kx, float ky)
  1049. {
  1050. gl.getTransform().setShear(kx, ky);
  1051. }
  1052. void Graphics::origin()
  1053. {
  1054. gl.getTransform().setIdentity();
  1055. pixel_size_stack.back() = 1;
  1056. }
  1057. Graphics::DisplayState::DisplayState()
  1058. : color(255, 255, 255, 255)
  1059. , backgroundColor(0, 0, 0, 255)
  1060. , blendMode(BLEND_ALPHA)
  1061. , lineWidth(1.0f)
  1062. , lineStyle(LINE_SMOOTH)
  1063. , lineJoin(LINE_JOIN_MITER)
  1064. , pointSize(1.0f)
  1065. , scissor(false)
  1066. , scissorBox()
  1067. , stencilTest(false)
  1068. , stencilInvert(false)
  1069. , font(nullptr)
  1070. , shader(nullptr)
  1071. , wireframe(false)
  1072. {
  1073. // We should just directly initialize the array in the initializer list, but
  1074. // that feature of C++11 is broken in Visual Studio 2013...
  1075. colorMask[0] = colorMask[1] = colorMask[2] = colorMask[3] = true;
  1076. }
  1077. Graphics::DisplayState::DisplayState(const DisplayState &other)
  1078. : color(other.color)
  1079. , backgroundColor(other.backgroundColor)
  1080. , blendMode(other.blendMode)
  1081. , lineWidth(other.lineWidth)
  1082. , lineStyle(other.lineStyle)
  1083. , lineJoin(other.lineJoin)
  1084. , pointSize(other.pointSize)
  1085. , scissor(other.scissor)
  1086. , scissorBox(other.scissorBox)
  1087. , stencilTest(other.stencilTest)
  1088. , stencilInvert(other.stencilInvert)
  1089. , font(other.font)
  1090. , shader(other.shader)
  1091. , canvases(other.canvases)
  1092. , wireframe(other.wireframe)
  1093. {
  1094. for (int i = 0; i < 4; i++)
  1095. colorMask[i] = other.colorMask[i];
  1096. }
  1097. Graphics::DisplayState::~DisplayState()
  1098. {
  1099. }
  1100. Graphics::DisplayState &Graphics::DisplayState::operator = (const DisplayState &other)
  1101. {
  1102. color = other.color;
  1103. backgroundColor = other.backgroundColor;
  1104. blendMode = other.blendMode;
  1105. lineWidth = other.lineWidth;
  1106. lineStyle = other.lineStyle;
  1107. lineJoin = other.lineJoin;
  1108. pointSize = other.pointSize;
  1109. scissor = other.scissor;
  1110. scissorBox = other.scissorBox;
  1111. stencilTest = other.stencilTest;
  1112. stencilInvert = other.stencilInvert;
  1113. font = other.font;
  1114. shader = other.shader;
  1115. canvases = other.canvases;
  1116. for (int i = 0; i < 4; i++)
  1117. colorMask[i] = other.colorMask[i];
  1118. wireframe = other.wireframe;
  1119. return *this;
  1120. }
  1121. } // opengl
  1122. } // graphics
  1123. } // love