Graphics.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489
  1. /**
  2. * Copyright (c) 2006-2017 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 "Graphics.h"
  22. #include "Buffer.h"
  23. #include "math/MathModule.h"
  24. #include "Polyline.h"
  25. #include "font/Font.h"
  26. #include "window/Window.h"
  27. #include "Font.h"
  28. #include "Video.h"
  29. // C++
  30. #include <algorithm>
  31. #include <stdlib.h>
  32. namespace love
  33. {
  34. namespace graphics
  35. {
  36. static bool gammaCorrect = false;
  37. static bool debugMode = false;
  38. static bool debugModeQueried = false;
  39. void setGammaCorrect(bool gammacorrect)
  40. {
  41. gammaCorrect = gammacorrect;
  42. }
  43. bool isGammaCorrect()
  44. {
  45. return gammaCorrect;
  46. }
  47. void gammaCorrectColor(Colorf &c)
  48. {
  49. if (isGammaCorrect())
  50. {
  51. c.r = math::gammaToLinear(c.r);
  52. c.g = math::gammaToLinear(c.g);
  53. c.b = math::gammaToLinear(c.b);
  54. }
  55. }
  56. Colorf gammaCorrectColor(const Colorf &c)
  57. {
  58. Colorf r = c;
  59. gammaCorrectColor(r);
  60. return r;
  61. }
  62. void unGammaCorrectColor(Colorf &c)
  63. {
  64. if (isGammaCorrect())
  65. {
  66. c.r = math::linearToGamma(c.r);
  67. c.g = math::linearToGamma(c.g);
  68. c.b = math::linearToGamma(c.b);
  69. }
  70. }
  71. Colorf unGammaCorrectColor(const Colorf &c)
  72. {
  73. Colorf r = c;
  74. unGammaCorrectColor(r);
  75. return r;
  76. }
  77. bool isDebugEnabled()
  78. {
  79. if (!debugModeQueried)
  80. {
  81. const char *debugenv = getenv("LOVE_GRAPHICS_DEBUG");
  82. debugMode = debugenv != nullptr && debugenv[0] != '0';
  83. debugModeQueried = true;
  84. }
  85. return debugMode;
  86. }
  87. love::Type Graphics::type("graphics", &Module::type);
  88. Shader::ShaderSource Graphics::defaultShaderCode[Shader::STANDARD_MAX_ENUM][Shader::LANGUAGE_MAX_ENUM][2];
  89. Graphics::Graphics()
  90. : width(0)
  91. , height(0)
  92. , pixelWidth(0)
  93. , pixelHeight(0)
  94. , created(false)
  95. , active(true)
  96. , writingToStencil(false)
  97. , streamBufferState()
  98. , projectionMatrix()
  99. , canvasSwitchCount(0)
  100. , capabilities()
  101. {
  102. transformStack.reserve(16);
  103. transformStack.push_back(Matrix4());
  104. pixelScaleStack.reserve(16);
  105. pixelScaleStack.push_back(1);
  106. if (!Shader::initialize())
  107. throw love::Exception("Shader support failed to initialize!");
  108. }
  109. Graphics::~Graphics()
  110. {
  111. states.clear();
  112. defaultFont.set(nullptr);
  113. for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++)
  114. {
  115. if (Shader::standardShaders[i])
  116. {
  117. Shader::standardShaders[i]->release();
  118. Shader::standardShaders[i] = nullptr;
  119. }
  120. }
  121. delete streamBufferState.vb[0];
  122. delete streamBufferState.vb[1];
  123. delete streamBufferState.indexBuffer;
  124. Shader::deinitialize();
  125. }
  126. Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh)
  127. {
  128. return new Quad(v, sw, sh);
  129. }
  130. Font *Graphics::newFont(love::font::Rasterizer *data, const Texture::Filter &filter)
  131. {
  132. return new Font(data, filter);
  133. }
  134. Video *Graphics::newVideo(love::video::VideoStream *stream, float pixeldensity)
  135. {
  136. return new Video(this, stream, pixeldensity);
  137. }
  138. bool Graphics::validateShader(bool gles, const Shader::ShaderSource &source, std::string &err)
  139. {
  140. return Shader::validate(this, gles, source, true, err);
  141. }
  142. int Graphics::getWidth() const
  143. {
  144. return width;
  145. }
  146. int Graphics::getHeight() const
  147. {
  148. return height;
  149. }
  150. int Graphics::getPixelWidth() const
  151. {
  152. return pixelWidth;
  153. }
  154. int Graphics::getPixelHeight() const
  155. {
  156. return pixelHeight;
  157. }
  158. double Graphics::getCurrentPixelDensity() const
  159. {
  160. if (states.back().renderTargets.colors.size() > 0)
  161. {
  162. Canvas *c = states.back().renderTargets.colors[0].canvas;
  163. return (double) c->getPixelHeight() / (double) c->getHeight();
  164. }
  165. return getScreenPixelDensity();
  166. }
  167. double Graphics::getScreenPixelDensity() const
  168. {
  169. return (double) getPixelHeight() / (double) getHeight();
  170. }
  171. bool Graphics::isCreated() const
  172. {
  173. return created;
  174. }
  175. bool Graphics::isActive() const
  176. {
  177. // The graphics module is only completely 'active' if there's a window, a
  178. // context, and the active variable is set.
  179. auto window = getInstance<love::window::Window>(M_WINDOW);
  180. return active && isCreated() && window != nullptr && window->isOpen();
  181. }
  182. void Graphics::reset()
  183. {
  184. DisplayState s;
  185. stopDrawToStencilBuffer();
  186. restoreState(s);
  187. origin();
  188. }
  189. /**
  190. * State functions.
  191. **/
  192. void Graphics::restoreState(const DisplayState &s)
  193. {
  194. setColor(s.color);
  195. setBackgroundColor(s.backgroundColor);
  196. setBlendMode(s.blendMode, s.blendAlphaMode);
  197. setLineWidth(s.lineWidth);
  198. setLineStyle(s.lineStyle);
  199. setLineJoin(s.lineJoin);
  200. setPointSize(s.pointSize);
  201. if (s.scissor)
  202. setScissor(s.scissorRect);
  203. else
  204. setScissor();
  205. setStencilTest(s.stencilCompare, s.stencilTestValue);
  206. setFont(s.font.get());
  207. setShader(s.shader.get());
  208. setCanvas(s.renderTargets);
  209. setColorMask(s.colorMask);
  210. setWireframe(s.wireframe);
  211. setDefaultFilter(s.defaultFilter);
  212. setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness);
  213. }
  214. void Graphics::restoreStateChecked(const DisplayState &s)
  215. {
  216. const DisplayState &cur = states.back();
  217. if (s.color != cur.color)
  218. setColor(s.color);
  219. setBackgroundColor(s.backgroundColor);
  220. if (s.blendMode != cur.blendMode || s.blendAlphaMode != cur.blendAlphaMode)
  221. setBlendMode(s.blendMode, s.blendAlphaMode);
  222. // These are just simple assignments.
  223. setLineWidth(s.lineWidth);
  224. setLineStyle(s.lineStyle);
  225. setLineJoin(s.lineJoin);
  226. if (s.pointSize != cur.pointSize)
  227. setPointSize(s.pointSize);
  228. if (s.scissor != cur.scissor || (s.scissor && !(s.scissorRect == cur.scissorRect)))
  229. {
  230. if (s.scissor)
  231. setScissor(s.scissorRect);
  232. else
  233. setScissor();
  234. }
  235. if (s.stencilCompare != cur.stencilCompare || s.stencilTestValue != cur.stencilTestValue)
  236. setStencilTest(s.stencilCompare, s.stencilTestValue);
  237. setFont(s.font.get());
  238. setShader(s.shader.get());
  239. const auto &sRTs = s.renderTargets;
  240. const auto &curRTs = cur.renderTargets;
  241. bool canvaseschanged = sRTs.colors.size() != curRTs.colors.size();
  242. if (!canvaseschanged)
  243. {
  244. for (size_t i = 0; i < sRTs.colors.size() && i < curRTs.colors.size(); i++)
  245. {
  246. const auto &rt1 = sRTs.colors[i];
  247. const auto &rt2 = curRTs.colors[i];
  248. if (rt1.canvas.get() != rt2.canvas.get() || rt1.slice != rt2.slice || rt1.mipmap != rt2.mipmap)
  249. {
  250. canvaseschanged = true;
  251. break;
  252. }
  253. }
  254. if (!canvaseschanged && (sRTs.depthStencil.canvas.get() != curRTs.depthStencil.canvas.get()
  255. || sRTs.depthStencil.slice != curRTs.depthStencil.slice
  256. || sRTs.depthStencil.mipmap != curRTs.depthStencil.mipmap))
  257. {
  258. canvaseschanged = true;
  259. }
  260. if (sRTs.temporaryRTFlags != curRTs.temporaryRTFlags)
  261. canvaseschanged = true;
  262. }
  263. if (canvaseschanged)
  264. setCanvas(s.renderTargets);
  265. if (s.colorMask != cur.colorMask)
  266. setColorMask(s.colorMask);
  267. if (s.wireframe != cur.wireframe)
  268. setWireframe(s.wireframe);
  269. setDefaultFilter(s.defaultFilter);
  270. setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness);
  271. }
  272. Colorf Graphics::getColor() const
  273. {
  274. return states.back().color;
  275. }
  276. void Graphics::setBackgroundColor(Colorf c)
  277. {
  278. states.back().backgroundColor = c;
  279. }
  280. Colorf Graphics::getBackgroundColor() const
  281. {
  282. return states.back().backgroundColor;
  283. }
  284. void Graphics::checkSetDefaultFont()
  285. {
  286. // We don't create or set the default Font if an existing font is in use.
  287. if (states.back().font.get() != nullptr)
  288. return;
  289. // Create a new default font if we don't have one yet.
  290. if (!defaultFont.get())
  291. {
  292. auto fontmodule = Module::getInstance<font::Font>(M_FONT);
  293. if (!fontmodule)
  294. throw love::Exception("Font module has not been loaded.");
  295. auto hinting = font::TrueTypeRasterizer::HINTING_NORMAL;
  296. StrongRef<font::Rasterizer> r(fontmodule->newTrueTypeRasterizer(12, hinting), Acquire::NORETAIN);
  297. defaultFont.set(newFont(r.get()), Acquire::NORETAIN);
  298. }
  299. states.back().font.set(defaultFont.get());
  300. }
  301. void Graphics::setFont(love::graphics::Font *font)
  302. {
  303. // We don't need to set a default font here if null is passed in, since we
  304. // only care about the default font in getFont and print.
  305. DisplayState &state = states.back();
  306. state.font.set(font);
  307. }
  308. love::graphics::Font *Graphics::getFont()
  309. {
  310. checkSetDefaultFont();
  311. return states.back().font.get();
  312. }
  313. void Graphics::setShader(love::graphics::Shader *shader)
  314. {
  315. if (shader == nullptr)
  316. return setShader();
  317. shader->attach();
  318. states.back().shader.set(shader);
  319. }
  320. void Graphics::setShader()
  321. {
  322. Shader::attachDefault(Shader::STANDARD_DEFAULT);
  323. states.back().shader.set(nullptr);
  324. }
  325. love::graphics::Shader *Graphics::getShader() const
  326. {
  327. return states.back().shader.get();
  328. }
  329. void Graphics::setCanvas(RenderTarget rt, uint32 temporaryRTFlags)
  330. {
  331. if (rt.canvas == nullptr)
  332. return setCanvas();
  333. RenderTargets rts;
  334. rts.colors.push_back(rt);
  335. rts.temporaryRTFlags = temporaryRTFlags;
  336. setCanvas(rts);
  337. }
  338. void Graphics::setCanvas(const RenderTargetsStrongRef &rts)
  339. {
  340. RenderTargets targets;
  341. targets.colors.reserve(rts.colors.size());
  342. for (const auto &rt : rts.colors)
  343. targets.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap);
  344. targets.depthStencil = RenderTarget(rts.depthStencil.canvas, rts.depthStencil.slice, rts.depthStencil.mipmap);
  345. targets.temporaryRTFlags = rts.temporaryRTFlags;
  346. return setCanvas(targets);
  347. }
  348. Graphics::RenderTargets Graphics::getCanvas() const
  349. {
  350. const auto &curRTs = states.back().renderTargets;
  351. RenderTargets rts;
  352. rts.colors.reserve(curRTs.colors.size());
  353. for (const auto &rt : curRTs.colors)
  354. rts.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap);
  355. rts.depthStencil = RenderTarget(curRTs.depthStencil.canvas, curRTs.depthStencil.slice, curRTs.depthStencil.mipmap);
  356. rts.temporaryRTFlags = curRTs.temporaryRTFlags;
  357. return rts;
  358. }
  359. bool Graphics::isCanvasActive() const
  360. {
  361. const auto &rts = states.back().renderTargets;
  362. return !rts.colors.empty() || rts.depthStencil.canvas != nullptr;
  363. }
  364. bool Graphics::isCanvasActive(love::graphics::Canvas *canvas) const
  365. {
  366. const auto &rts = states.back().renderTargets;
  367. for (const auto &rt : rts.colors)
  368. {
  369. if (rt.canvas.get() == canvas)
  370. return true;
  371. }
  372. if (rts.depthStencil.canvas.get() == canvas)
  373. return true;
  374. return false;
  375. }
  376. bool Graphics::isCanvasActive(Canvas *canvas, int slice) const
  377. {
  378. const auto &rts = states.back().renderTargets;
  379. for (const auto &rt : rts.colors)
  380. {
  381. if (rt.canvas.get() == canvas && rt.slice == slice)
  382. return true;
  383. }
  384. if (rts.depthStencil.canvas.get() == canvas && rts.depthStencil.slice == slice)
  385. return true;
  386. return false;
  387. }
  388. Canvas *Graphics::getTemporaryCanvas(PixelFormat format, int w, int h, int samples)
  389. {
  390. love::graphics::Canvas *canvas = nullptr;
  391. for (Canvas *c : temporaryCanvases)
  392. {
  393. if (c->getPixelFormat() == format && c->getPixelWidth() == w
  394. && c->getPixelHeight() == h && c->getRequestedMSAA() == samples)
  395. {
  396. canvas = c;
  397. break;
  398. }
  399. }
  400. if (canvas == nullptr)
  401. {
  402. Canvas::Settings settings;
  403. settings.format = format;
  404. settings.width = w;
  405. settings.height = h;
  406. settings.msaa = samples;
  407. canvas = newCanvas(settings);
  408. temporaryCanvases.push_back(canvas);
  409. }
  410. return canvas;
  411. }
  412. void Graphics::intersectScissor(const Rect &rect)
  413. {
  414. Rect currect = states.back().scissorRect;
  415. if (!states.back().scissor)
  416. {
  417. currect.x = 0;
  418. currect.y = 0;
  419. currect.w = std::numeric_limits<int>::max();
  420. currect.h = std::numeric_limits<int>::max();
  421. }
  422. int x1 = std::max(currect.x, rect.x);
  423. int y1 = std::max(currect.y, rect.y);
  424. int x2 = std::min(currect.x + currect.w, rect.x + rect.w);
  425. int y2 = std::min(currect.y + currect.h, rect.y + rect.h);
  426. Rect newrect = {x1, y1, std::max(0, x2 - x1), std::max(0, y2 - y1)};
  427. setScissor(newrect);
  428. }
  429. bool Graphics::getScissor(Rect &rect) const
  430. {
  431. const DisplayState &state = states.back();
  432. rect = state.scissorRect;
  433. return state.scissor;
  434. }
  435. void Graphics::getStencilTest(CompareMode &compare, int &value)
  436. {
  437. const DisplayState &state = states.back();
  438. compare = state.stencilCompare;
  439. value = state.stencilTestValue;
  440. }
  441. Graphics::ColorMask Graphics::getColorMask() const
  442. {
  443. return states.back().colorMask;
  444. }
  445. Graphics::BlendMode Graphics::getBlendMode(BlendAlpha &alphamode) const
  446. {
  447. alphamode = states.back().blendAlphaMode;
  448. return states.back().blendMode;
  449. }
  450. void Graphics::setDefaultFilter(const Texture::Filter &f)
  451. {
  452. Texture::defaultFilter = f;
  453. states.back().defaultFilter = f;
  454. }
  455. const Texture::Filter &Graphics::getDefaultFilter() const
  456. {
  457. return Texture::defaultFilter;
  458. }
  459. void Graphics::setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness)
  460. {
  461. Texture::defaultMipmapFilter = filter;
  462. Texture::defaultMipmapSharpness = sharpness;
  463. states.back().defaultMipmapFilter = filter;
  464. states.back().defaultMipmapSharpness = sharpness;
  465. }
  466. void Graphics::getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const
  467. {
  468. *filter = Texture::defaultMipmapFilter;
  469. *sharpness = Texture::defaultMipmapSharpness;
  470. }
  471. void Graphics::setLineWidth(float width)
  472. {
  473. states.back().lineWidth = width;
  474. }
  475. void Graphics::setLineStyle(Graphics::LineStyle style)
  476. {
  477. states.back().lineStyle = style;
  478. }
  479. void Graphics::setLineJoin(Graphics::LineJoin join)
  480. {
  481. states.back().lineJoin = join;
  482. }
  483. float Graphics::getLineWidth() const
  484. {
  485. return states.back().lineWidth;
  486. }
  487. Graphics::LineStyle Graphics::getLineStyle() const
  488. {
  489. return states.back().lineStyle;
  490. }
  491. Graphics::LineJoin Graphics::getLineJoin() const
  492. {
  493. return states.back().lineJoin;
  494. }
  495. float Graphics::getPointSize() const
  496. {
  497. return states.back().pointSize;
  498. }
  499. bool Graphics::isWireframe() const
  500. {
  501. return states.back().wireframe;
  502. }
  503. void Graphics::captureScreenshot(const ScreenshotInfo &info)
  504. {
  505. pendingScreenshotCallbacks.push_back(info);
  506. }
  507. Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &req)
  508. {
  509. using namespace vertex;
  510. StreamBufferState &state = streamBufferState;
  511. bool shouldflush = false;
  512. bool shouldresize = false;
  513. if (req.primitiveMode != state.primitiveMode
  514. || req.formats[0] != state.formats[0] || req.formats[1] != state.formats[1]
  515. || ((req.indexMode != TriangleIndexMode::NONE) != (state.indexCount > 0))
  516. || req.texture != state.texture
  517. || req.standardShaderType != state.standardShaderType)
  518. {
  519. shouldflush = true;
  520. }
  521. int totalvertices = state.vertexCount + req.vertexCount;
  522. // We only support uint16 index buffers for now.
  523. if (totalvertices > LOVE_UINT16_MAX && req.indexMode != TriangleIndexMode::NONE)
  524. shouldflush = true;
  525. int reqIndexCount = getIndexCount(req.indexMode, req.vertexCount);
  526. size_t reqIndexSize = reqIndexCount * sizeof(uint16);
  527. size_t newdatasizes[2] = {0, 0};
  528. size_t buffersizes[3] = {0, 0, 0};
  529. for (int i = 0; i < 2; i++)
  530. {
  531. if (req.formats[i] == CommonFormat::NONE)
  532. continue;
  533. size_t stride = getFormatStride(req.formats[i]);
  534. size_t datasize = stride * totalvertices;
  535. if (state.vbMap[i].data != nullptr && datasize > state.vbMap[i].size)
  536. shouldflush = true;
  537. if (datasize > state.vb[i]->getSize())
  538. {
  539. buffersizes[i] = std::max(datasize, state.vb[i]->getSize() * 2);
  540. shouldresize = true;
  541. }
  542. newdatasizes[i] = stride * req.vertexCount;
  543. }
  544. if (req.indexMode != TriangleIndexMode::NONE)
  545. {
  546. size_t datasize = (state.indexCount + reqIndexCount) * sizeof(uint16);
  547. if (state.indexBufferMap.data != nullptr && datasize > state.indexBufferMap.size)
  548. shouldflush = true;
  549. if (datasize > state.indexBuffer->getSize())
  550. {
  551. buffersizes[2] = std::max(datasize, state.indexBuffer->getSize() * 2);
  552. shouldresize = true;
  553. }
  554. }
  555. if (shouldflush || shouldresize)
  556. {
  557. flushStreamDraws();
  558. state.primitiveMode = req.primitiveMode;
  559. state.formats[0] = req.formats[0];
  560. state.formats[1] = req.formats[1];
  561. state.texture = req.texture;
  562. state.standardShaderType = req.standardShaderType;
  563. }
  564. if (state.vertexCount == 0 && Shader::isDefaultActive())
  565. Shader::attachDefault(state.standardShaderType);
  566. if (state.vertexCount == 0 && Shader::current != nullptr && req.texture != nullptr)
  567. Shader::current->checkMainTexture(req.texture);
  568. if (shouldresize)
  569. {
  570. for (int i = 0; i < 2; i++)
  571. {
  572. if (state.vb[i]->getSize() < buffersizes[i])
  573. {
  574. delete state.vb[i];
  575. state.vb[i] = newStreamBuffer(BUFFER_VERTEX, buffersizes[i]);
  576. }
  577. }
  578. if (state.indexBuffer->getSize() < buffersizes[2])
  579. {
  580. delete state.indexBuffer;
  581. state.indexBuffer = newStreamBuffer(BUFFER_INDEX, buffersizes[2]);
  582. }
  583. }
  584. if (req.indexMode != TriangleIndexMode::NONE)
  585. {
  586. if (state.indexBufferMap.data == nullptr)
  587. state.indexBufferMap = state.indexBuffer->map(reqIndexSize);
  588. uint16 *indices = (uint16 *) state.indexBufferMap.data;
  589. fillIndices(req.indexMode, state.vertexCount, req.vertexCount, indices);
  590. state.indexBufferMap.data += reqIndexSize;
  591. }
  592. StreamVertexData d;
  593. for (int i = 0; i < 2; i++)
  594. {
  595. if (newdatasizes[i] > 0)
  596. {
  597. if (state.vbMap[i].data == nullptr)
  598. state.vbMap[i] = state.vb[i]->map(newdatasizes[i]);
  599. d.stream[i] = state.vbMap[i].data;
  600. state.vbMap[i].data += newdatasizes[i];
  601. }
  602. }
  603. state.vertexCount += req.vertexCount;
  604. state.indexCount += reqIndexCount;
  605. return d;
  606. }
  607. void Graphics::flushStreamDrawsGlobal()
  608. {
  609. Graphics *instance = getInstance<Graphics>(M_GRAPHICS);
  610. if (instance != nullptr)
  611. instance->flushStreamDraws();
  612. }
  613. /**
  614. * Drawing
  615. **/
  616. void Graphics::draw(Drawable *drawable, const Matrix4 &m)
  617. {
  618. drawable->draw(this, m);
  619. }
  620. void Graphics::draw(Texture *texture, Quad *quad, const Matrix4 &m)
  621. {
  622. texture->draw(this, quad, m);
  623. }
  624. void Graphics::drawLayer(Texture *texture, int layer, const Matrix4 &m)
  625. {
  626. texture->drawLayer(this, layer, m);
  627. }
  628. void Graphics::drawLayer(Texture *texture, int layer, Quad *quad, const Matrix4 &m)
  629. {
  630. texture->drawLayer(this, layer, quad, m);
  631. }
  632. void Graphics::drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount)
  633. {
  634. mesh->drawInstanced(this, m, instancecount);
  635. }
  636. void Graphics::print(const std::vector<Font::ColoredString> &str, const Matrix4 &m)
  637. {
  638. checkSetDefaultFont();
  639. if (states.back().font.get() != nullptr)
  640. print(str, states.back().font.get(), m);
  641. }
  642. void Graphics::print(const std::vector<Font::ColoredString> &str, Font *font, const Matrix4 &m)
  643. {
  644. font->print(this, str, m, states.back().color);
  645. }
  646. void Graphics::printf(const std::vector<Font::ColoredString> &str, float wrap, Font::AlignMode align, const Matrix4 &m)
  647. {
  648. checkSetDefaultFont();
  649. if (states.back().font.get() != nullptr)
  650. printf(str, states.back().font.get(), wrap, align, m);
  651. }
  652. void Graphics::printf(const std::vector<Font::ColoredString> &str, Font *font, float wrap, Font::AlignMode align, const Matrix4 &m)
  653. {
  654. font->printf(this, str, wrap, align, m, states.back().color);
  655. }
  656. /**
  657. * Primitives (points, shapes, lines).
  658. **/
  659. void Graphics::points(const float *coords, const Colorf *colors, size_t numpoints)
  660. {
  661. const Matrix4 &t = getTransform();
  662. bool is2D = t.isAffine2DTransform();
  663. StreamDrawRequest req;
  664. req.primitiveMode = vertex::PrimitiveMode::POINTS;
  665. req.formats[0] = vertex::getSinglePositionFormat(is2D);
  666. req.formats[1] = vertex::CommonFormat::RGBAub;
  667. req.vertexCount = (int) numpoints;
  668. StreamVertexData data = requestStreamDraw(req);
  669. if (is2D)
  670. t.transformXY((Vector2 *) data.stream[0], (const Vector2 *) coords, req.vertexCount);
  671. else
  672. t.transformXY0((Vector3 *) data.stream[0], (const Vector2 *) coords, req.vertexCount);
  673. Color *colordata = (Color *) data.stream[1];
  674. if (colors)
  675. {
  676. Colorf nc = getColor();
  677. gammaCorrectColor(nc);
  678. if (isGammaCorrect())
  679. {
  680. for (int i = 0; i < req.vertexCount; i++)
  681. {
  682. Colorf ci = colors[i];
  683. gammaCorrectColor(ci);
  684. ci *= nc;
  685. unGammaCorrectColor(ci);
  686. colordata[i] = toColor(ci);
  687. }
  688. }
  689. else
  690. {
  691. for (int i = 0; i < req.vertexCount; i++)
  692. colordata[i] = toColor(nc * colors[i]);
  693. }
  694. }
  695. else
  696. {
  697. Color c = toColor(getColor());
  698. for (int i = 0; i < req.vertexCount; i++)
  699. colordata[i] = c;
  700. }
  701. }
  702. int Graphics::calculateEllipsePoints(float rx, float ry) const
  703. {
  704. int points = (int) sqrtf(((rx + ry) / 2.0f) * 20.0f * (float) pixelScaleStack.back());
  705. return std::max(points, 8);
  706. }
  707. void Graphics::polyline(const float *coords, size_t count)
  708. {
  709. float halfwidth = getLineWidth() * 0.5f;
  710. LineJoin linejoin = getLineJoin();
  711. LineStyle linestyle = getLineStyle();
  712. float pixelsize = 1.0f / std::max((float) pixelScaleStack.back(), 0.000001f);
  713. if (linejoin == LINE_JOIN_NONE)
  714. {
  715. NoneJoinPolyline line;
  716. line.render(coords, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH);
  717. line.draw(this);
  718. }
  719. else if (linejoin == LINE_JOIN_BEVEL)
  720. {
  721. BevelJoinPolyline line;
  722. line.render(coords, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH);
  723. line.draw(this);
  724. }
  725. else if (linejoin == LINE_JOIN_MITER)
  726. {
  727. MiterJoinPolyline line;
  728. line.render(coords, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH);
  729. line.draw(this);
  730. }
  731. }
  732. void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h)
  733. {
  734. float coords[] = {x,y, x,y+h, x+w,y+h, x+w,y, x,y};
  735. polygon(mode, coords, 5 * 2);
  736. }
  737. void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry, int points)
  738. {
  739. if (rx == 0 || ry == 0)
  740. {
  741. rectangle(mode, x, y, w, h);
  742. return;
  743. }
  744. // Radius values that are more than half the rectangle's size aren't handled
  745. // correctly (for now)...
  746. if (w >= 0.02f)
  747. rx = std::min(rx, w / 2.0f - 0.01f);
  748. if (h >= 0.02f)
  749. ry = std::min(ry, h / 2.0f - 0.01f);
  750. points = std::max(points / 4, 1);
  751. const float half_pi = static_cast<float>(LOVE_M_PI / 2);
  752. float angle_shift = half_pi / ((float) points + 1.0f);
  753. int num_coords = (points + 2) * 8;
  754. float *coords = getScratchBuffer<float>(num_coords + 2);
  755. float phi = .0f;
  756. for (int i = 0; i <= points + 2; ++i, phi += angle_shift)
  757. {
  758. coords[2 * i + 0] = x + rx * (1 - cosf(phi));
  759. coords[2 * i + 1] = y + ry * (1 - sinf(phi));
  760. }
  761. phi = half_pi;
  762. for (int i = points + 2; i <= 2 * (points + 2); ++i, phi += angle_shift)
  763. {
  764. coords[2 * i + 0] = x + w - rx * (1 + cosf(phi));
  765. coords[2 * i + 1] = y + ry * (1 - sinf(phi));
  766. }
  767. phi = 2 * half_pi;
  768. for (int i = 2 * (points + 2); i <= 3 * (points + 2); ++i, phi += angle_shift)
  769. {
  770. coords[2 * i + 0] = x + w - rx * (1 + cosf(phi));
  771. coords[2 * i + 1] = y + h - ry * (1 + sinf(phi));
  772. }
  773. phi = 3 * half_pi;
  774. for (int i = 3 * (points + 2); i <= 4 * (points + 2); ++i, phi += angle_shift)
  775. {
  776. coords[2 * i + 0] = x + rx * (1 - cosf(phi));
  777. coords[2 * i + 1] = y + h - ry * (1 + sinf(phi));
  778. }
  779. coords[num_coords + 0] = coords[0];
  780. coords[num_coords + 1] = coords[1];
  781. polygon(mode, coords, num_coords + 2);
  782. }
  783. void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry)
  784. {
  785. rectangle(mode, x, y, w, h, rx, ry, calculateEllipsePoints(rx, ry));
  786. }
  787. void Graphics::circle(DrawMode mode, float x, float y, float radius, int points)
  788. {
  789. ellipse(mode, x, y, radius, radius, points);
  790. }
  791. void Graphics::circle(DrawMode mode, float x, float y, float radius)
  792. {
  793. ellipse(mode, x, y, radius, radius);
  794. }
  795. void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b, int points)
  796. {
  797. float two_pi = (float) (LOVE_M_PI * 2);
  798. if (points <= 0) points = 1;
  799. float angle_shift = (two_pi / points);
  800. float phi = .0f;
  801. float *coords = getScratchBuffer<float>(2 * (points + 1));
  802. for (int i = 0; i < points; ++i, phi += angle_shift)
  803. {
  804. coords[2*i+0] = x + a * cosf(phi);
  805. coords[2*i+1] = y + b * sinf(phi);
  806. }
  807. coords[2*points+0] = coords[0];
  808. coords[2*points+1] = coords[1];
  809. polygon(mode, coords, (points + 1) * 2);
  810. }
  811. void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b)
  812. {
  813. ellipse(mode, x, y, a, b, calculateEllipsePoints(a, b));
  814. }
  815. void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float radius, float angle1, float angle2, int points)
  816. {
  817. // Nothing to display with no points or equal angles. (Or is there with line mode?)
  818. if (points <= 0 || angle1 == angle2)
  819. return;
  820. // Oh, you want to draw a circle?
  821. if (fabs(angle1 - angle2) >= 2.0f * (float) LOVE_M_PI)
  822. {
  823. circle(drawmode, x, y, radius, points);
  824. return;
  825. }
  826. float angle_shift = (angle2 - angle1) / points;
  827. // Bail on precision issues.
  828. if (angle_shift == 0.0)
  829. return;
  830. // Prevent the connecting line from being drawn if a closed line arc has a
  831. // small angle. Avoids some visual issues when connected lines are at sharp
  832. // angles, due to the miter line join drawing code.
  833. if (drawmode == DRAW_LINE && arcmode == ARC_CLOSED && fabsf(angle1 - angle2) < LOVE_TORAD(4))
  834. arcmode = ARC_OPEN;
  835. // Quick fix for the last part of a filled open arc not being drawn (because
  836. // polygon(DRAW_FILL, ...) doesn't work without a closed loop of vertices.)
  837. if (drawmode == DRAW_FILL && arcmode == ARC_OPEN)
  838. arcmode = ARC_CLOSED;
  839. float phi = angle1;
  840. float *coords = nullptr;
  841. int num_coords = 0;
  842. const auto createPoints = [&](float *coordinates)
  843. {
  844. for (int i = 0; i <= points; ++i, phi += angle_shift)
  845. {
  846. coordinates[2 * i + 0] = x + radius * cosf(phi);
  847. coordinates[2 * i + 1] = y + radius * sinf(phi);
  848. }
  849. };
  850. if (arcmode == ARC_PIE)
  851. {
  852. num_coords = (points + 3) * 2;
  853. coords = getScratchBuffer<float>(num_coords);
  854. coords[0] = coords[num_coords - 2] = x;
  855. coords[1] = coords[num_coords - 1] = y;
  856. createPoints(coords + 2);
  857. }
  858. else if (arcmode == ARC_OPEN)
  859. {
  860. num_coords = (points + 1) * 2;
  861. coords = getScratchBuffer<float>(num_coords);
  862. createPoints(coords);
  863. }
  864. else // ARC_CLOSED
  865. {
  866. num_coords = (points + 2) * 2;
  867. coords = getScratchBuffer<float>(num_coords);
  868. createPoints(coords);
  869. // Connect the ends of the arc.
  870. coords[num_coords - 2] = coords[0];
  871. coords[num_coords - 1] = coords[1];
  872. }
  873. polygon(drawmode, coords, num_coords);
  874. }
  875. void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float radius, float angle1, float angle2)
  876. {
  877. float points = (float) calculateEllipsePoints(radius, radius);
  878. // The amount of points is based on the fraction of the circle created by the arc.
  879. float angle = fabsf(angle1 - angle2);
  880. if (angle < 2.0f * (float) LOVE_M_PI)
  881. points *= angle / (2.0f * (float) LOVE_M_PI);
  882. arc(drawmode, arcmode, x, y, radius, angle1, angle2, (int) (points + 0.5f));
  883. }
  884. /// @param mode the draw mode
  885. /// @param coords the coordinate array
  886. /// @param count the number of coordinates/size of the array
  887. void Graphics::polygon(DrawMode mode, const float *coords, size_t count)
  888. {
  889. // coords is an array of a closed loop of vertices, i.e.
  890. // coords[count-2] = coords[0], coords[count-1] = coords[1]
  891. if (mode == DRAW_LINE)
  892. {
  893. polyline(coords, count);
  894. }
  895. else
  896. {
  897. const Matrix4 &t = getTransform();
  898. bool is2D = t.isAffine2DTransform();
  899. StreamDrawRequest req;
  900. req.formats[0] = vertex::getSinglePositionFormat(is2D);
  901. req.formats[1] = vertex::CommonFormat::RGBAub;
  902. req.indexMode = vertex::TriangleIndexMode::FAN;
  903. req.vertexCount = (int)count/2 - 1;
  904. StreamVertexData data = requestStreamDraw(req);
  905. if (is2D)
  906. t.transformXY((Vector2 *) data.stream[0], (const Vector2 *) coords, req.vertexCount);
  907. else
  908. t.transformXY0((Vector3 *) data.stream[0], (const Vector2 *) coords, req.vertexCount);
  909. Color c = toColor(getColor());
  910. Color *colordata = (Color *) data.stream[1];
  911. for (int i = 0; i < req.vertexCount; i++)
  912. colordata[i] = c;
  913. }
  914. }
  915. const Graphics::Capabilities &Graphics::getCapabilities() const
  916. {
  917. return capabilities;
  918. }
  919. Graphics::Stats Graphics::getStats() const
  920. {
  921. Stats stats;
  922. getAPIStats(stats.drawCalls, stats.shaderSwitches);
  923. if (streamBufferState.vertexCount > 0)
  924. stats.drawCalls++;
  925. stats.canvasSwitches = canvasSwitchCount;
  926. stats.canvases = Canvas::canvasCount;
  927. stats.images = Image::imageCount;
  928. stats.fonts = Font::fontCount;
  929. stats.textureMemory = Texture::totalGraphicsMemory;
  930. return stats;
  931. }
  932. void Graphics::push(StackType type)
  933. {
  934. if (stackTypeStack.size() == MAX_USER_STACK_DEPTH)
  935. throw Exception("Maximum stack depth reached (more pushes than pops?)");
  936. pushTransform();
  937. pixelScaleStack.push_back(pixelScaleStack.back());
  938. if (type == STACK_ALL)
  939. states.push_back(states.back());
  940. stackTypeStack.push_back(type);
  941. }
  942. void Graphics::pop()
  943. {
  944. if (stackTypeStack.size() < 1)
  945. throw Exception("Minimum stack depth reached (more pops than pushes?)");
  946. popTransform();
  947. pixelScaleStack.pop_back();
  948. if (stackTypeStack.back() == STACK_ALL)
  949. {
  950. DisplayState &newstate = states[states.size() - 2];
  951. restoreStateChecked(newstate);
  952. // The last two states in the stack should be equal now.
  953. states.pop_back();
  954. }
  955. stackTypeStack.pop_back();
  956. }
  957. /**
  958. * Transform and stack functions.
  959. **/
  960. const Matrix4 &Graphics::getTransform() const
  961. {
  962. return transformStack.back();
  963. }
  964. const Matrix4 &Graphics::getProjection() const
  965. {
  966. return projectionMatrix;
  967. }
  968. void Graphics::pushTransform()
  969. {
  970. transformStack.push_back(transformStack.back());
  971. }
  972. void Graphics::pushIdentityTransform()
  973. {
  974. transformStack.push_back(Matrix4());
  975. }
  976. void Graphics::popTransform()
  977. {
  978. transformStack.pop_back();
  979. }
  980. void Graphics::rotate(float r)
  981. {
  982. transformStack.back().rotate(r);
  983. }
  984. void Graphics::scale(float x, float y)
  985. {
  986. transformStack.back().scale(x, y);
  987. pixelScaleStack.back() *= (fabs(x) + fabs(y)) / 2.0;
  988. }
  989. void Graphics::translate(float x, float y)
  990. {
  991. transformStack.back().translate(x, y);
  992. }
  993. void Graphics::shear(float kx, float ky)
  994. {
  995. transformStack.back().shear(kx, ky);
  996. }
  997. void Graphics::origin()
  998. {
  999. transformStack.back().setIdentity();
  1000. pixelScaleStack.back() = 1;
  1001. }
  1002. void Graphics::applyTransform(love::math::Transform *transform)
  1003. {
  1004. Matrix4 &m = transformStack.back();
  1005. m *= transform->getMatrix();
  1006. float sx, sy;
  1007. m.getApproximateScale(sx, sy);
  1008. pixelScaleStack.back() = (sx + sy) / 2.0;
  1009. }
  1010. void Graphics::replaceTransform(love::math::Transform *transform)
  1011. {
  1012. const Matrix4 &m = transform->getMatrix();
  1013. transformStack.back() = m;
  1014. float sx, sy;
  1015. m.getApproximateScale(sx, sy);
  1016. pixelScaleStack.back() = (sx + sy) / 2.0;
  1017. }
  1018. Vector2 Graphics::transformPoint(Vector2 point)
  1019. {
  1020. Vector2 p;
  1021. transformStack.back().transformXY(&p, &point, 1);
  1022. return p;
  1023. }
  1024. Vector2 Graphics::inverseTransformPoint(Vector2 point)
  1025. {
  1026. Vector2 p;
  1027. // TODO: We should probably cache the inverse transform so we don't have to
  1028. // re-calculate it every time this is called.
  1029. transformStack.back().inverse().transformXY(&p, &point, 1);
  1030. return p;
  1031. }
  1032. const Shader::ShaderSource &Graphics::getCurrentDefaultShaderCode() const
  1033. {
  1034. return defaultShaderCode[Shader::STANDARD_DEFAULT][getShaderLanguageTarget()][isGammaCorrect() ? 1 : 0];
  1035. }
  1036. /**
  1037. * Constants.
  1038. **/
  1039. bool Graphics::getConstant(const char *in, DrawMode &out)
  1040. {
  1041. return drawModes.find(in, out);
  1042. }
  1043. bool Graphics::getConstant(DrawMode in, const char *&out)
  1044. {
  1045. return drawModes.find(in, out);
  1046. }
  1047. bool Graphics::getConstant(const char *in, ArcMode &out)
  1048. {
  1049. return arcModes.find(in, out);
  1050. }
  1051. bool Graphics::getConstant(ArcMode in, const char *&out)
  1052. {
  1053. return arcModes.find(in, out);
  1054. }
  1055. bool Graphics::getConstant(const char *in, BlendMode &out)
  1056. {
  1057. return blendModes.find(in, out);
  1058. }
  1059. bool Graphics::getConstant(BlendMode in, const char *&out)
  1060. {
  1061. return blendModes.find(in, out);
  1062. }
  1063. bool Graphics::getConstant(const char *in, BlendAlpha &out)
  1064. {
  1065. return blendAlphaModes.find(in, out);
  1066. }
  1067. bool Graphics::getConstant(BlendAlpha in, const char *&out)
  1068. {
  1069. return blendAlphaModes.find(in, out);
  1070. }
  1071. bool Graphics::getConstant(const char *in, LineStyle &out)
  1072. {
  1073. return lineStyles.find(in, out);
  1074. }
  1075. bool Graphics::getConstant(LineStyle in, const char *&out)
  1076. {
  1077. return lineStyles.find(in, out);
  1078. }
  1079. bool Graphics::getConstant(const char *in, LineJoin &out)
  1080. {
  1081. return lineJoins.find(in, out);
  1082. }
  1083. bool Graphics::getConstant(LineJoin in, const char *&out)
  1084. {
  1085. return lineJoins.find(in, out);
  1086. }
  1087. bool Graphics::getConstant(const char *in, Feature &out)
  1088. {
  1089. return features.find(in, out);
  1090. }
  1091. bool Graphics::getConstant(Feature in, const char *&out)
  1092. {
  1093. return features.find(in, out);
  1094. }
  1095. bool Graphics::getConstant(const char *in, SystemLimit &out)
  1096. {
  1097. return systemLimits.find(in, out);
  1098. }
  1099. bool Graphics::getConstant(SystemLimit in, const char *&out)
  1100. {
  1101. return systemLimits.find(in, out);
  1102. }
  1103. bool Graphics::getConstant(const char *in, StackType &out)
  1104. {
  1105. return stackTypes.find(in, out);
  1106. }
  1107. bool Graphics::getConstant(StackType in, const char *&out)
  1108. {
  1109. return stackTypes.find(in, out);
  1110. }
  1111. StringMap<Graphics::DrawMode, Graphics::DRAW_MAX_ENUM>::Entry Graphics::drawModeEntries[] =
  1112. {
  1113. { "line", DRAW_LINE },
  1114. { "fill", DRAW_FILL },
  1115. };
  1116. StringMap<Graphics::DrawMode, Graphics::DRAW_MAX_ENUM> Graphics::drawModes(Graphics::drawModeEntries, sizeof(Graphics::drawModeEntries));
  1117. StringMap<Graphics::ArcMode, Graphics::ARC_MAX_ENUM>::Entry Graphics::arcModeEntries[] =
  1118. {
  1119. { "open", ARC_OPEN },
  1120. { "closed", ARC_CLOSED },
  1121. { "pie", ARC_PIE },
  1122. };
  1123. StringMap<Graphics::ArcMode, Graphics::ARC_MAX_ENUM> Graphics::arcModes(Graphics::arcModeEntries, sizeof(Graphics::arcModeEntries));
  1124. StringMap<Graphics::BlendMode, Graphics::BLEND_MAX_ENUM>::Entry Graphics::blendModeEntries[] =
  1125. {
  1126. { "alpha", BLEND_ALPHA },
  1127. { "add", BLEND_ADD },
  1128. { "subtract", BLEND_SUBTRACT },
  1129. { "multiply", BLEND_MULTIPLY },
  1130. { "lighten", BLEND_LIGHTEN },
  1131. { "darken", BLEND_DARKEN },
  1132. { "screen", BLEND_SCREEN },
  1133. { "replace", BLEND_REPLACE },
  1134. { "none", BLEND_NONE },
  1135. };
  1136. StringMap<Graphics::BlendMode, Graphics::BLEND_MAX_ENUM> Graphics::blendModes(Graphics::blendModeEntries, sizeof(Graphics::blendModeEntries));
  1137. StringMap<Graphics::BlendAlpha, Graphics::BLENDALPHA_MAX_ENUM>::Entry Graphics::blendAlphaEntries[] =
  1138. {
  1139. { "alphamultiply", BLENDALPHA_MULTIPLY },
  1140. { "premultiplied", BLENDALPHA_PREMULTIPLIED },
  1141. };
  1142. StringMap<Graphics::BlendAlpha, Graphics::BLENDALPHA_MAX_ENUM> Graphics::blendAlphaModes(Graphics::blendAlphaEntries, sizeof(Graphics::blendAlphaEntries));
  1143. StringMap<Graphics::LineStyle, Graphics::LINE_MAX_ENUM>::Entry Graphics::lineStyleEntries[] =
  1144. {
  1145. { "smooth", LINE_SMOOTH },
  1146. { "rough", LINE_ROUGH }
  1147. };
  1148. StringMap<Graphics::LineStyle, Graphics::LINE_MAX_ENUM> Graphics::lineStyles(Graphics::lineStyleEntries, sizeof(Graphics::lineStyleEntries));
  1149. StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM>::Entry Graphics::lineJoinEntries[] =
  1150. {
  1151. { "none", LINE_JOIN_NONE },
  1152. { "miter", LINE_JOIN_MITER },
  1153. { "bevel", LINE_JOIN_BEVEL }
  1154. };
  1155. StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM> Graphics::lineJoins(Graphics::lineJoinEntries, sizeof(Graphics::lineJoinEntries));
  1156. StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM>::Entry Graphics::featureEntries[] =
  1157. {
  1158. { "multicanvasformats", FEATURE_MULTI_CANVAS_FORMATS },
  1159. { "clampzero", FEATURE_CLAMP_ZERO },
  1160. { "lighten", FEATURE_LIGHTEN },
  1161. { "fullnpot", FEATURE_FULL_NPOT },
  1162. { "pixelshaderhighp", FEATURE_PIXEL_SHADER_HIGHP },
  1163. { "glsl3", FEATURE_GLSL3 },
  1164. { "instancing", FEATURE_INSTANCING },
  1165. };
  1166. StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM> Graphics::features(Graphics::featureEntries, sizeof(Graphics::featureEntries));
  1167. StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM>::Entry Graphics::systemLimitEntries[] =
  1168. {
  1169. { "pointsize", LIMIT_POINT_SIZE },
  1170. { "texturesize", LIMIT_TEXTURE_SIZE },
  1171. { "texturelayers", LIMIT_TEXTURE_LAYERS },
  1172. { "volumetexturesize", LIMIT_VOLUME_TEXTURE_SIZE },
  1173. { "cubetexturesize", LIMIT_CUBE_TEXTURE_SIZE },
  1174. { "multicanvas", LIMIT_MULTI_CANVAS },
  1175. { "canvasmsaa", LIMIT_CANVAS_MSAA },
  1176. { "anisotropy", LIMIT_ANISOTROPY },
  1177. };
  1178. StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM> Graphics::systemLimits(Graphics::systemLimitEntries, sizeof(Graphics::systemLimitEntries));
  1179. StringMap<Graphics::StackType, Graphics::STACK_MAX_ENUM>::Entry Graphics::stackTypeEntries[] =
  1180. {
  1181. { "all", STACK_ALL },
  1182. { "transform", STACK_TRANSFORM },
  1183. };
  1184. StringMap<Graphics::StackType, Graphics::STACK_MAX_ENUM> Graphics::stackTypes(Graphics::stackTypeEntries, sizeof(Graphics::stackTypeEntries));
  1185. } // graphics
  1186. } // love