Graphics.cpp 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355
  1. /**
  2. * Copyright (c) 2006-2022 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 "data/DataModule.h"
  25. #include "Polyline.h"
  26. #include "font/Font.h"
  27. #include "window/Window.h"
  28. #include "SpriteBatch.h"
  29. #include "ParticleSystem.h"
  30. #include "Font.h"
  31. #include "Video.h"
  32. #include "Text.h"
  33. #include "common/deprecation.h"
  34. #include "common/config.h"
  35. // C++
  36. #include <algorithm>
  37. #include <stdlib.h>
  38. namespace love
  39. {
  40. namespace graphics
  41. {
  42. static bool gammaCorrect = false;
  43. static bool debugMode = false;
  44. static bool debugModeQueried = false;
  45. void setGammaCorrect(bool gammacorrect)
  46. {
  47. gammaCorrect = gammacorrect;
  48. }
  49. bool isGammaCorrect()
  50. {
  51. return gammaCorrect;
  52. }
  53. void gammaCorrectColor(Colorf &c)
  54. {
  55. if (isGammaCorrect())
  56. {
  57. c.r = math::gammaToLinear(c.r);
  58. c.g = math::gammaToLinear(c.g);
  59. c.b = math::gammaToLinear(c.b);
  60. }
  61. }
  62. Colorf gammaCorrectColor(const Colorf &c)
  63. {
  64. Colorf r = c;
  65. gammaCorrectColor(r);
  66. return r;
  67. }
  68. void unGammaCorrectColor(Colorf &c)
  69. {
  70. if (isGammaCorrect())
  71. {
  72. c.r = math::linearToGamma(c.r);
  73. c.g = math::linearToGamma(c.g);
  74. c.b = math::linearToGamma(c.b);
  75. }
  76. }
  77. Colorf unGammaCorrectColor(const Colorf &c)
  78. {
  79. Colorf r = c;
  80. unGammaCorrectColor(r);
  81. return r;
  82. }
  83. bool isDebugEnabled()
  84. {
  85. if (!debugModeQueried)
  86. {
  87. const char *debugenv = getenv("LOVE_GRAPHICS_DEBUG");
  88. debugMode = debugenv != nullptr && debugenv[0] != '0';
  89. debugModeQueried = true;
  90. }
  91. return debugMode;
  92. }
  93. love::Type Graphics::type("graphics", &Module::type);
  94. namespace opengl { extern love::graphics::Graphics *createInstance(); }
  95. #ifdef LOVE_GRAPHICS_METAL
  96. namespace metal { extern love::graphics::Graphics *createInstance(); }
  97. #endif
  98. static const Renderer rendererOrder[] = {
  99. RENDERER_OPENGL,
  100. RENDERER_METAL,
  101. };
  102. static std::vector<Renderer> defaultRenderers =
  103. {
  104. RENDERER_METAL,
  105. RENDERER_OPENGL,
  106. };
  107. static std::vector<Renderer> _renderers = defaultRenderers;
  108. const std::vector<Renderer> &getDefaultRenderers()
  109. {
  110. return defaultRenderers;
  111. }
  112. const std::vector<Renderer> &getRenderers()
  113. {
  114. return _renderers;
  115. }
  116. void setRenderers(const std::vector<Renderer> &renderers)
  117. {
  118. _renderers = renderers;
  119. }
  120. Graphics *Graphics::createInstance()
  121. {
  122. Graphics *instance = Module::getInstance<Graphics>(M_GRAPHICS);
  123. if (instance != nullptr)
  124. instance->retain();
  125. else
  126. {
  127. for (auto r : rendererOrder)
  128. {
  129. if (std::find(_renderers.begin(), _renderers.end(), r) == _renderers.end())
  130. continue;
  131. if (r == RENDERER_OPENGL)
  132. instance = opengl::createInstance();
  133. #ifdef LOVE_GRAPHICS_METAL
  134. if (r == RENDERER_METAL)
  135. instance = metal::createInstance();
  136. #endif
  137. if (instance != nullptr)
  138. break;
  139. }
  140. }
  141. return instance;
  142. }
  143. Graphics::DisplayState::DisplayState()
  144. {
  145. defaultSamplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_LINEAR;
  146. }
  147. Graphics::Graphics()
  148. : width(0)
  149. , height(0)
  150. , pixelWidth(0)
  151. , pixelHeight(0)
  152. , created(false)
  153. , active(true)
  154. , batchedDrawState()
  155. , deviceProjectionMatrix()
  156. , renderTargetSwitchCount(0)
  157. , drawCalls(0)
  158. , drawCallsBatched(0)
  159. , quadIndexBuffer(nullptr)
  160. , capabilities()
  161. , cachedShaderStages()
  162. {
  163. transformStack.reserve(16);
  164. transformStack.push_back(Matrix4());
  165. pixelScaleStack.reserve(16);
  166. pixelScaleStack.push_back(1);
  167. states.reserve(10);
  168. states.push_back(DisplayState());
  169. if (!Shader::initialize())
  170. throw love::Exception("Shader support failed to initialize!");
  171. }
  172. Graphics::~Graphics()
  173. {
  174. delete quadIndexBuffer;
  175. // Clean up standard shaders before the active shader. If we do it after,
  176. // the active shader may try to activate a standard shader when deactivating
  177. // itself, which will cause problems since it calls Graphics methods in the
  178. // Graphics destructor.
  179. for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++)
  180. {
  181. if (Shader::standardShaders[i])
  182. {
  183. Shader::standardShaders[i]->release();
  184. Shader::standardShaders[i] = nullptr;
  185. }
  186. }
  187. states.clear();
  188. defaultFont.set(nullptr);
  189. if (batchedDrawState.vb[0])
  190. batchedDrawState.vb[0]->release();
  191. if (batchedDrawState.vb[1])
  192. batchedDrawState.vb[1]->release();
  193. if (batchedDrawState.indexBuffer)
  194. batchedDrawState.indexBuffer->release();
  195. for (int i = 0; i < (int) SHADERSTAGE_MAX_ENUM; i++)
  196. cachedShaderStages[i].clear();
  197. Shader::deinitialize();
  198. }
  199. void Graphics::createQuadIndexBuffer()
  200. {
  201. if (quadIndexBuffer != nullptr)
  202. return;
  203. size_t size = sizeof(uint16) * (LOVE_UINT16_MAX / 4) * 6;
  204. Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, BUFFERDATAUSAGE_STATIC);
  205. quadIndexBuffer = newBuffer(settings, DATAFORMAT_UINT16, nullptr, size, 0);
  206. Buffer::Mapper map(*quadIndexBuffer);
  207. fillIndices(TRIANGLEINDEX_QUADS, 0, LOVE_UINT16_MAX, (uint16 *) map.data);
  208. quadIndexBuffer->setImmutable(true);
  209. }
  210. Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh)
  211. {
  212. return new Quad(v, sw, sh);
  213. }
  214. Font *Graphics::newFont(love::font::Rasterizer *data)
  215. {
  216. return new Font(data, states.back().defaultSamplerState);
  217. }
  218. Font *Graphics::newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting)
  219. {
  220. auto fontmodule = Module::getInstance<font::Font>(M_FONT);
  221. if (!fontmodule)
  222. throw love::Exception("Font module has not been loaded.");
  223. StrongRef<font::Rasterizer> r(fontmodule->newTrueTypeRasterizer(size, hinting), Acquire::NORETAIN);
  224. return newFont(r.get());
  225. }
  226. Video *Graphics::newVideo(love::video::VideoStream *stream, float dpiscale)
  227. {
  228. return new Video(this, stream, dpiscale);
  229. }
  230. love::graphics::SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, BufferDataUsage usage)
  231. {
  232. return new SpriteBatch(this, texture, size, usage);
  233. }
  234. love::graphics::ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
  235. {
  236. return new ParticleSystem(texture, size);
  237. }
  238. ShaderStage *Graphics::newShaderStage(ShaderStageType stage, const std::string &source, const Shader::SourceInfo &info)
  239. {
  240. ShaderStage *s = nullptr;
  241. std::string cachekey;
  242. if (!source.empty())
  243. {
  244. data::HashFunction::Value hashvalue;
  245. data::hash(data::HashFunction::FUNCTION_SHA1, source.c_str(), source.size(), hashvalue);
  246. cachekey = std::string(hashvalue.data, hashvalue.size);
  247. auto it = cachedShaderStages[stage].find(cachekey);
  248. if (it != cachedShaderStages[stage].end())
  249. {
  250. s = it->second;
  251. s->retain();
  252. }
  253. }
  254. if (s == nullptr)
  255. {
  256. bool glsles = usesGLSLES();
  257. std::string glsl = Shader::createShaderStageCode(this, stage, source, info, glsles, true);
  258. s = newShaderStageInternal(stage, cachekey, glsl, glsles);
  259. if (!cachekey.empty())
  260. cachedShaderStages[stage][cachekey] = s;
  261. }
  262. return s;
  263. }
  264. Shader *Graphics::newShader(const std::vector<std::string> &stagessource)
  265. {
  266. StrongRef<ShaderStage> stages[SHADERSTAGE_MAX_ENUM] = {};
  267. bool validstages[SHADERSTAGE_MAX_ENUM] = {};
  268. validstages[SHADERSTAGE_VERTEX] = true;
  269. validstages[SHADERSTAGE_PIXEL] = true;
  270. for (const std::string &source : stagessource)
  271. {
  272. Shader::SourceInfo info = Shader::getSourceInfo(source);
  273. bool isanystage = false;
  274. for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
  275. {
  276. if (!validstages[i])
  277. continue;
  278. if (info.stages[i] != Shader::ENTRYPOINT_NONE)
  279. {
  280. isanystage = true;
  281. stages[i].set(newShaderStage((ShaderStageType) i, source, info), Acquire::NORETAIN);
  282. }
  283. }
  284. if (!isanystage)
  285. throw love::Exception("Could not parse shader code (missing 'position' or 'effect' function?)");
  286. }
  287. for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
  288. {
  289. auto stype = (ShaderStageType) i;
  290. if (validstages[i] && stages[i].get() == nullptr)
  291. {
  292. const std::string &source = Shader::getDefaultCode(Shader::STANDARD_DEFAULT, stype);
  293. Shader::SourceInfo info = Shader::getSourceInfo(source);
  294. stages[i].set(newShaderStage(stype, source, info), Acquire::NORETAIN);
  295. }
  296. }
  297. return newShaderInternal(stages);
  298. }
  299. Shader *Graphics::newComputeShader(const std::string &source)
  300. {
  301. Shader::SourceInfo info = Shader::getSourceInfo(source);
  302. if (info.stages[SHADERSTAGE_COMPUTE] == Shader::ENTRYPOINT_NONE)
  303. throw love::Exception("Could not parse compute shader code (missing 'computemain' function?)");
  304. StrongRef<ShaderStage> stages[SHADERSTAGE_MAX_ENUM];
  305. stages[SHADERSTAGE_COMPUTE].set(newShaderStage(SHADERSTAGE_COMPUTE, source, info));
  306. return newShaderInternal(stages);
  307. }
  308. Buffer *Graphics::newBuffer(const Buffer::Settings &settings, DataFormat format, const void *data, size_t size, size_t arraylength)
  309. {
  310. std::vector<Buffer::DataDeclaration> dataformat = {{"", format, 0}};
  311. return newBuffer(settings, dataformat, data, size, arraylength);
  312. }
  313. Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferDataUsage usage)
  314. {
  315. return new Mesh(this, vertexformat, vertexcount, drawmode, usage);
  316. }
  317. Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferDataUsage usage)
  318. {
  319. return new Mesh(this, vertexformat, data, datasize, drawmode, usage);
  320. }
  321. Mesh *Graphics::newMesh(const std::vector<Mesh::BufferAttribute> &attributes, PrimitiveType drawmode)
  322. {
  323. return new Mesh(attributes, drawmode);
  324. }
  325. love::graphics::Text *Graphics::newText(graphics::Font *font, const std::vector<Font::ColoredString> &text)
  326. {
  327. return new Text(font, text);
  328. }
  329. void Graphics::cleanupCachedShaderStage(ShaderStageType type, const std::string &hashkey)
  330. {
  331. cachedShaderStages[type].erase(hashkey);
  332. }
  333. bool Graphics::validateShader(bool gles, const std::vector<std::string> &stagessource, std::string &err)
  334. {
  335. StrongRef<ShaderStage> stages[SHADERSTAGE_MAX_ENUM] = {};
  336. bool validstages[SHADERSTAGE_MAX_ENUM] = {};
  337. validstages[SHADERSTAGE_VERTEX] = true;
  338. validstages[SHADERSTAGE_PIXEL] = true;
  339. validstages[SHADERSTAGE_COMPUTE] = true;
  340. // Don't use cached shader stages, since the gles flag may not match the
  341. // current renderer.
  342. for (const std::string &source : stagessource)
  343. {
  344. Shader::SourceInfo info = Shader::getSourceInfo(source);
  345. bool isanystage = false;
  346. for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
  347. {
  348. auto stype = (ShaderStageType) i;
  349. if (!validstages[i])
  350. continue;
  351. if (info.stages[i] != Shader::ENTRYPOINT_NONE)
  352. {
  353. isanystage = true;
  354. std::string glsl = Shader::createShaderStageCode(this, stype, source, info, gles, false);
  355. stages[i].set(new ShaderStageForValidation(this, stype, glsl, gles), Acquire::NORETAIN);
  356. }
  357. }
  358. if (!isanystage)
  359. {
  360. err = "Could not parse shader code (missing 'position' or 'effect' function?)";
  361. return false;
  362. }
  363. }
  364. return Shader::validate(stages, err);
  365. }
  366. int Graphics::getWidth() const
  367. {
  368. return width;
  369. }
  370. int Graphics::getHeight() const
  371. {
  372. return height;
  373. }
  374. int Graphics::getPixelWidth() const
  375. {
  376. return pixelWidth;
  377. }
  378. int Graphics::getPixelHeight() const
  379. {
  380. return pixelHeight;
  381. }
  382. double Graphics::getCurrentDPIScale() const
  383. {
  384. const auto &rt = states.back().renderTargets.getFirstTarget();
  385. if (rt.texture.get())
  386. return rt.texture->getDPIScale();
  387. return getScreenDPIScale();
  388. }
  389. double Graphics::getScreenDPIScale() const
  390. {
  391. return (double) getPixelHeight() / (double) getHeight();
  392. }
  393. bool Graphics::isCreated() const
  394. {
  395. return created;
  396. }
  397. bool Graphics::isActive() const
  398. {
  399. // The graphics module is only completely 'active' if there's a window, a
  400. // context, and the active variable is set.
  401. auto window = getInstance<love::window::Window>(M_WINDOW);
  402. return active && isCreated() && window != nullptr && window->isOpen();
  403. }
  404. void Graphics::reset()
  405. {
  406. DisplayState s;
  407. stopDrawToStencilBuffer();
  408. restoreState(s);
  409. origin();
  410. }
  411. /**
  412. * State functions.
  413. **/
  414. void Graphics::restoreState(const DisplayState &s)
  415. {
  416. setColor(s.color);
  417. setBackgroundColor(s.backgroundColor);
  418. setBlendState(s.blend);
  419. setLineWidth(s.lineWidth);
  420. setLineStyle(s.lineStyle);
  421. setLineJoin(s.lineJoin);
  422. setPointSize(s.pointSize);
  423. if (s.scissor)
  424. setScissor(s.scissorRect);
  425. else
  426. setScissor();
  427. if (s.stencil.action != STENCIL_KEEP)
  428. drawToStencilBuffer(s.stencil.action, s.stencil.value);
  429. else
  430. stopDrawToStencilBuffer();
  431. setStencilTest(s.stencil.compare, s.stencil.value);
  432. setDepthMode(s.depthTest, s.depthWrite);
  433. setMeshCullMode(s.meshCullMode);
  434. setFrontFaceWinding(s.winding);
  435. setFont(s.font.get());
  436. setShader(s.shader.get());
  437. setRenderTargets(s.renderTargets);
  438. setColorMask(s.colorMask);
  439. setWireframe(s.wireframe);
  440. setDefaultSamplerState(s.defaultSamplerState);
  441. if (s.useCustomProjection)
  442. updateDeviceProjection(s.customProjection);
  443. else
  444. resetProjection();
  445. }
  446. void Graphics::restoreStateChecked(const DisplayState &s)
  447. {
  448. const DisplayState &cur = states.back();
  449. if (s.color != cur.color)
  450. setColor(s.color);
  451. setBackgroundColor(s.backgroundColor);
  452. if (!(s.blend == cur.blend))
  453. setBlendState(s.blend);
  454. // These are just simple assignments.
  455. setLineWidth(s.lineWidth);
  456. setLineStyle(s.lineStyle);
  457. setLineJoin(s.lineJoin);
  458. if (s.pointSize != cur.pointSize)
  459. setPointSize(s.pointSize);
  460. if (s.scissor != cur.scissor || (s.scissor && !(s.scissorRect == cur.scissorRect)))
  461. {
  462. if (s.scissor)
  463. setScissor(s.scissorRect);
  464. else
  465. setScissor();
  466. }
  467. if (s.stencil.action != cur.stencil.action)
  468. {
  469. if (s.stencil.action != STENCIL_KEEP)
  470. drawToStencilBuffer(s.stencil.action, s.stencil.value);
  471. else
  472. stopDrawToStencilBuffer();
  473. }
  474. if (s.stencil.compare != cur.stencil.compare || s.stencil.value != cur.stencil.value)
  475. setStencilTest(s.stencil.compare, s.stencil.value);
  476. if (s.depthTest != cur.depthTest || s.depthWrite != cur.depthWrite)
  477. setDepthMode(s.depthTest, s.depthWrite);
  478. setMeshCullMode(s.meshCullMode);
  479. if (s.winding != cur.winding)
  480. setFrontFaceWinding(s.winding);
  481. setFont(s.font.get());
  482. setShader(s.shader.get());
  483. const auto &sRTs = s.renderTargets;
  484. const auto &curRTs = cur.renderTargets;
  485. bool rtschanged = sRTs.colors.size() != curRTs.colors.size();
  486. if (!rtschanged)
  487. {
  488. for (size_t i = 0; i < sRTs.colors.size() && i < curRTs.colors.size(); i++)
  489. {
  490. if (sRTs.colors[i] != curRTs.colors[i])
  491. {
  492. rtschanged = true;
  493. break;
  494. }
  495. }
  496. if (!rtschanged && sRTs.depthStencil != curRTs.depthStencil)
  497. rtschanged = true;
  498. if (sRTs.temporaryRTFlags != curRTs.temporaryRTFlags)
  499. rtschanged = true;
  500. }
  501. if (rtschanged)
  502. setRenderTargets(s.renderTargets);
  503. if (s.colorMask != cur.colorMask)
  504. setColorMask(s.colorMask);
  505. if (s.wireframe != cur.wireframe)
  506. setWireframe(s.wireframe);
  507. setDefaultSamplerState(s.defaultSamplerState);
  508. if (s.useCustomProjection)
  509. setCustomProjection(s.customProjection);
  510. else if (cur.useCustomProjection)
  511. resetProjection();
  512. }
  513. Colorf Graphics::getColor() const
  514. {
  515. return states.back().color;
  516. }
  517. void Graphics::setBackgroundColor(Colorf c)
  518. {
  519. states.back().backgroundColor = c;
  520. }
  521. Colorf Graphics::getBackgroundColor() const
  522. {
  523. return states.back().backgroundColor;
  524. }
  525. void Graphics::checkSetDefaultFont()
  526. {
  527. // We don't create or set the default Font if an existing font is in use.
  528. if (states.back().font.get() != nullptr)
  529. return;
  530. // Create a new default font if we don't have one yet.
  531. if (!defaultFont.get())
  532. defaultFont.set(newDefaultFont(13, font::TrueTypeRasterizer::HINTING_NORMAL), Acquire::NORETAIN);
  533. states.back().font.set(defaultFont.get());
  534. }
  535. void Graphics::setFont(love::graphics::Font *font)
  536. {
  537. // We don't need to set a default font here if null is passed in, since we
  538. // only care about the default font in getFont and print.
  539. DisplayState &state = states.back();
  540. state.font.set(font);
  541. }
  542. love::graphics::Font *Graphics::getFont()
  543. {
  544. checkSetDefaultFont();
  545. return states.back().font.get();
  546. }
  547. void Graphics::setShader(love::graphics::Shader *shader)
  548. {
  549. if (shader == nullptr)
  550. return setShader();
  551. shader->attach();
  552. states.back().shader.set(shader);
  553. }
  554. void Graphics::setShader()
  555. {
  556. Shader::attachDefault(Shader::STANDARD_DEFAULT);
  557. states.back().shader.set(nullptr);
  558. }
  559. love::graphics::Shader *Graphics::getShader() const
  560. {
  561. return states.back().shader.get();
  562. }
  563. void Graphics::setRenderTarget(RenderTarget rt, uint32 temporaryRTFlags)
  564. {
  565. if (rt.texture == nullptr)
  566. return setRenderTarget();
  567. RenderTargets rts;
  568. rts.colors.push_back(rt);
  569. rts.temporaryRTFlags = temporaryRTFlags;
  570. setRenderTargets(rts);
  571. }
  572. void Graphics::setRenderTargets(const RenderTargetsStrongRef &rts)
  573. {
  574. RenderTargets targets;
  575. targets.colors.reserve(rts.colors.size());
  576. for (const auto &rt : rts.colors)
  577. targets.colors.emplace_back(rt.texture.get(), rt.slice, rt.mipmap);
  578. targets.depthStencil = RenderTarget(rts.depthStencil.texture, rts.depthStencil.slice, rts.depthStencil.mipmap);
  579. targets.temporaryRTFlags = rts.temporaryRTFlags;
  580. return setRenderTargets(targets);
  581. }
  582. void Graphics::setRenderTargets(const RenderTargets &rts)
  583. {
  584. DisplayState &state = states.back();
  585. int rtcount = (int) rts.colors.size();
  586. RenderTarget firsttarget = rts.getFirstTarget();
  587. Texture *firsttex = firsttarget.texture;
  588. if (firsttex == nullptr)
  589. return setRenderTarget();
  590. const auto &prevRTs = state.renderTargets;
  591. if (rtcount == (int) prevRTs.colors.size())
  592. {
  593. bool modified = false;
  594. for (int i = 0; i < rtcount; i++)
  595. {
  596. if (rts.colors[i] != prevRTs.colors[i])
  597. {
  598. modified = true;
  599. break;
  600. }
  601. }
  602. if (!modified && rts.depthStencil != prevRTs.depthStencil)
  603. modified = true;
  604. if (rts.temporaryRTFlags != prevRTs.temporaryRTFlags)
  605. modified = true;
  606. if (!modified)
  607. return;
  608. }
  609. if (rtcount > capabilities.limits[LIMIT_RENDER_TARGETS])
  610. throw love::Exception("This system can't simultaneously render to %d textures.", rtcount);
  611. bool multiformatsupported = capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS];
  612. PixelFormat firstcolorformat = PIXELFORMAT_UNKNOWN;
  613. if (!rts.colors.empty())
  614. firstcolorformat = rts.colors[0].texture->getPixelFormat();
  615. if (!firsttex->isRenderTarget())
  616. throw love::Exception("Texture must be created as a render target to be used in setRenderTargets.");
  617. if (isPixelFormatDepthStencil(firstcolorformat))
  618. throw love::Exception("Depth/stencil format textures must be used with the 'depthstencil' field of the table passed into setRenderTargets.");
  619. if (firsttarget.mipmap < 0 || firsttarget.mipmap >= firsttex->getMipmapCount())
  620. throw love::Exception("Invalid mipmap level %d.", firsttarget.mipmap + 1);
  621. if (!firsttex->isValidSlice(firsttarget.slice))
  622. throw love::Exception("Invalid slice index: %d.", firsttarget.slice + 1);
  623. bool hasSRGBtexture = isPixelFormatSRGB(firstcolorformat);
  624. int pixelw = firsttex->getPixelWidth(firsttarget.mipmap);
  625. int pixelh = firsttex->getPixelHeight(firsttarget.mipmap);
  626. int reqmsaa = firsttex->getRequestedMSAA();
  627. for (int i = 1; i < rtcount; i++)
  628. {
  629. Texture *c = rts.colors[i].texture;
  630. PixelFormat format = c->getPixelFormat();
  631. int mip = rts.colors[i].mipmap;
  632. int slice = rts.colors[i].slice;
  633. if (!c->isRenderTarget())
  634. throw love::Exception("Texture must be created as a render target to be used in setRenderTargets.");
  635. if (mip < 0 || mip >= c->getMipmapCount())
  636. throw love::Exception("Invalid mipmap level %d.", mip + 1);
  637. if (!c->isValidSlice(slice))
  638. throw love::Exception("Invalid slice index: %d.", slice + 1);
  639. if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh)
  640. throw love::Exception("All textures must have the same pixel dimensions.");
  641. if (!multiformatsupported && format != firstcolorformat)
  642. throw love::Exception("This system doesn't support multi-render-target rendering with different texture formats.");
  643. if (c->getRequestedMSAA() != reqmsaa)
  644. throw love::Exception("All textures must have the same MSAA value.");
  645. if (isPixelFormatDepthStencil(format))
  646. throw love::Exception("Depth/stencil format textures must be used with the 'depthstencil' field of the table passed into setRenderTargets.");
  647. if (isPixelFormatSRGB(format))
  648. hasSRGBtexture = true;
  649. }
  650. if (rts.depthStencil.texture != nullptr)
  651. {
  652. Texture *c = rts.depthStencil.texture;
  653. int mip = rts.depthStencil.mipmap;
  654. int slice = rts.depthStencil.slice;
  655. if (!c->isRenderTarget())
  656. throw love::Exception("Texture must be created as a render target to be used in setRenderTargets.");
  657. if (!isPixelFormatDepthStencil(c->getPixelFormat()))
  658. throw love::Exception("Only depth/stencil format textures can be used with the 'depthstencil' field of the table passed into setRenderTargets.");
  659. if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh)
  660. throw love::Exception("All Textures must have the same pixel dimensions.");
  661. if (c->getRequestedMSAA() != firsttex->getRequestedMSAA())
  662. throw love::Exception("All Textures must have the same MSAA value.");
  663. if (mip < 0 || mip >= c->getMipmapCount())
  664. throw love::Exception("Invalid mipmap level %d.", mip + 1);
  665. if (!c->isValidSlice(slice))
  666. throw love::Exception("Invalid slice index: %d.", slice + 1);
  667. }
  668. int w = firsttex->getWidth(firsttarget.mipmap);
  669. int h = firsttex->getHeight(firsttarget.mipmap);
  670. flushBatchedDraws();
  671. if (rts.depthStencil.texture == nullptr && rts.temporaryRTFlags != 0)
  672. {
  673. bool wantsdepth = (rts.temporaryRTFlags & TEMPORARY_RT_DEPTH) != 0;
  674. bool wantsstencil = (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) != 0;
  675. PixelFormat dsformat = PIXELFORMAT_STENCIL8;
  676. if (wantsdepth && wantsstencil)
  677. dsformat = PIXELFORMAT_DEPTH24_UNORM_STENCIL8;
  678. else if (wantsdepth && isPixelFormatSupported(PIXELFORMAT_DEPTH24_UNORM, PIXELFORMATUSAGEFLAGS_RENDERTARGET, false))
  679. dsformat = PIXELFORMAT_DEPTH24_UNORM;
  680. else if (wantsdepth)
  681. dsformat = PIXELFORMAT_DEPTH16_UNORM;
  682. else if (wantsstencil)
  683. dsformat = PIXELFORMAT_STENCIL8;
  684. // We want setRenderTargetsInternal to have a pointer to the temporary RT,
  685. // but we don't want to directly store it in the main graphics state.
  686. RenderTargets realRTs = rts;
  687. realRTs.depthStencil.texture = getTemporaryTexture(dsformat, pixelw, pixelh, reqmsaa);
  688. realRTs.depthStencil.slice = 0;
  689. setRenderTargetsInternal(realRTs, w, h, pixelw, pixelh, hasSRGBtexture);
  690. }
  691. else
  692. setRenderTargetsInternal(rts, w, h, pixelw, pixelh, hasSRGBtexture);
  693. RenderTargetsStrongRef refs;
  694. refs.colors.reserve(rts.colors.size());
  695. for (auto c : rts.colors)
  696. refs.colors.emplace_back(c.texture, c.slice, c.mipmap);
  697. refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.texture, rts.depthStencil.slice);
  698. refs.temporaryRTFlags = rts.temporaryRTFlags;
  699. std::swap(state.renderTargets, refs);
  700. renderTargetSwitchCount++;
  701. resetProjection();
  702. }
  703. void Graphics::setRenderTarget()
  704. {
  705. DisplayState &state = states.back();
  706. if (state.renderTargets.colors.empty() && state.renderTargets.depthStencil.texture == nullptr)
  707. return;
  708. flushBatchedDraws();
  709. setRenderTargetsInternal(RenderTargets(), width, height, pixelWidth, pixelHeight, isGammaCorrect());
  710. state.renderTargets = RenderTargetsStrongRef();
  711. renderTargetSwitchCount++;
  712. resetProjection();
  713. }
  714. Graphics::RenderTargets Graphics::getRenderTargets() const
  715. {
  716. const auto &curRTs = states.back().renderTargets;
  717. RenderTargets rts;
  718. rts.colors.reserve(curRTs.colors.size());
  719. for (const auto &rt : curRTs.colors)
  720. rts.colors.emplace_back(rt.texture.get(), rt.slice, rt.mipmap);
  721. rts.depthStencil = RenderTarget(curRTs.depthStencil.texture, curRTs.depthStencil.slice, curRTs.depthStencil.mipmap);
  722. rts.temporaryRTFlags = curRTs.temporaryRTFlags;
  723. return rts;
  724. }
  725. bool Graphics::isRenderTargetActive() const
  726. {
  727. const auto &rts = states.back().renderTargets;
  728. return !rts.colors.empty() || rts.depthStencil.texture != nullptr;
  729. }
  730. bool Graphics::isRenderTargetActive(Texture *texture) const
  731. {
  732. const auto &rts = states.back().renderTargets;
  733. for (const auto &rt : rts.colors)
  734. {
  735. if (rt.texture.get() == texture)
  736. return true;
  737. }
  738. if (rts.depthStencil.texture.get() == texture)
  739. return true;
  740. return false;
  741. }
  742. bool Graphics::isRenderTargetActive(Texture *texture, int slice) const
  743. {
  744. const auto &rts = states.back().renderTargets;
  745. for (const auto &rt : rts.colors)
  746. {
  747. if (rt.texture.get() == texture && rt.slice == slice)
  748. return true;
  749. }
  750. if (rts.depthStencil.texture.get() == texture && rts.depthStencil.slice == slice)
  751. return true;
  752. return false;
  753. }
  754. Texture *Graphics::getTemporaryTexture(PixelFormat format, int w, int h, int samples)
  755. {
  756. Texture *texture = nullptr;
  757. for (TemporaryTexture &temp : temporaryTextures)
  758. {
  759. Texture *c = temp.texture;
  760. if (c->getPixelFormat() == format && c->getPixelWidth() == w
  761. && c->getPixelHeight() == h && c->getRequestedMSAA() == samples)
  762. {
  763. texture = c;
  764. temp.framesSinceUse = 0;
  765. break;
  766. }
  767. }
  768. if (texture == nullptr)
  769. {
  770. Texture::Settings settings;
  771. settings.renderTarget = true;
  772. settings.format = format;
  773. settings.width = w;
  774. settings.height = h;
  775. settings.msaa = samples;
  776. texture = newTexture(settings);
  777. temporaryTextures.emplace_back(texture);
  778. }
  779. return texture;
  780. }
  781. void Graphics::intersectScissor(const Rect &rect)
  782. {
  783. Rect currect = states.back().scissorRect;
  784. if (!states.back().scissor)
  785. {
  786. currect.x = 0;
  787. currect.y = 0;
  788. currect.w = std::numeric_limits<int>::max();
  789. currect.h = std::numeric_limits<int>::max();
  790. }
  791. int x1 = std::max(currect.x, rect.x);
  792. int y1 = std::max(currect.y, rect.y);
  793. int x2 = std::min(currect.x + currect.w, rect.x + rect.w);
  794. int y2 = std::min(currect.y + currect.h, rect.y + rect.h);
  795. Rect newrect = {x1, y1, std::max(0, x2 - x1), std::max(0, y2 - y1)};
  796. setScissor(newrect);
  797. }
  798. bool Graphics::getScissor(Rect &rect) const
  799. {
  800. const DisplayState &state = states.back();
  801. rect = state.scissorRect;
  802. return state.scissor;
  803. }
  804. void Graphics::setStencilTest()
  805. {
  806. setStencilTest(COMPARE_ALWAYS, 0);
  807. }
  808. void Graphics::getStencilTest(CompareMode &compare, int &value) const
  809. {
  810. const DisplayState &state = states.back();
  811. compare = state.stencil.compare;
  812. value = state.stencil.value;
  813. }
  814. void Graphics::setDepthMode()
  815. {
  816. setDepthMode(COMPARE_ALWAYS, false);
  817. }
  818. void Graphics::getDepthMode(CompareMode &compare, bool &write) const
  819. {
  820. const DisplayState &state = states.back();
  821. compare = state.depthTest;
  822. write = state.depthWrite;
  823. }
  824. void Graphics::setMeshCullMode(CullMode cull)
  825. {
  826. // Handled inside the draw() graphics API implementations.
  827. states.back().meshCullMode = cull;
  828. }
  829. CullMode Graphics::getMeshCullMode() const
  830. {
  831. return states.back().meshCullMode;
  832. }
  833. Winding Graphics::getFrontFaceWinding() const
  834. {
  835. return states.back().winding;
  836. }
  837. ColorChannelMask Graphics::getColorMask() const
  838. {
  839. return states.back().colorMask;
  840. }
  841. void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode)
  842. {
  843. if (alphamode == BLENDALPHA_MULTIPLY && !isAlphaMultiplyBlendSupported(mode))
  844. {
  845. const char *modestr = "unknown";
  846. love::graphics::getConstant(mode, modestr);
  847. throw love::Exception("The '%s' blend mode must be used with premultiplied alpha.", modestr);
  848. }
  849. setBlendState(computeBlendState(mode, alphamode));
  850. }
  851. BlendMode Graphics::getBlendMode(BlendAlpha &alphamode) const
  852. {
  853. return computeBlendMode(states.back().blend, alphamode);
  854. }
  855. const BlendState &Graphics::getBlendState() const
  856. {
  857. return states.back().blend;
  858. }
  859. void Graphics::setDefaultSamplerState(const SamplerState &s)
  860. {
  861. states.back().defaultSamplerState = s;
  862. }
  863. const SamplerState &Graphics::getDefaultSamplerState() const
  864. {
  865. return states.back().defaultSamplerState;
  866. }
  867. void Graphics::setLineWidth(float width)
  868. {
  869. states.back().lineWidth = width;
  870. }
  871. void Graphics::setLineStyle(Graphics::LineStyle style)
  872. {
  873. states.back().lineStyle = style;
  874. }
  875. void Graphics::setLineJoin(Graphics::LineJoin join)
  876. {
  877. states.back().lineJoin = join;
  878. }
  879. float Graphics::getLineWidth() const
  880. {
  881. return states.back().lineWidth;
  882. }
  883. Graphics::LineStyle Graphics::getLineStyle() const
  884. {
  885. return states.back().lineStyle;
  886. }
  887. Graphics::LineJoin Graphics::getLineJoin() const
  888. {
  889. return states.back().lineJoin;
  890. }
  891. float Graphics::getPointSize() const
  892. {
  893. return states.back().pointSize;
  894. }
  895. bool Graphics::isWireframe() const
  896. {
  897. return states.back().wireframe;
  898. }
  899. void Graphics::captureScreenshot(const ScreenshotInfo &info)
  900. {
  901. pendingScreenshotCallbacks.push_back(info);
  902. }
  903. void Graphics::copyBuffer(Buffer *source, Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
  904. {
  905. if (!capabilities.features[FEATURE_COPY_BUFFER])
  906. throw love::Exception("Buffer copying is not supported on this system.");
  907. Range sourcerange(sourceoffset, size);
  908. Range destrange(destoffset, size);
  909. if (dest->getDataUsage() == BUFFERDATAUSAGE_STREAM)
  910. throw love::Exception("Buffers created with 'stream' data usage cannot be used as a copy destination.");
  911. if (sourcerange.getMax() >= source->getSize())
  912. throw love::Exception("Buffer copy source offset and size doesn't fit within the source Buffer's size.");
  913. if (destrange.getMax() >= dest->getSize())
  914. throw love::Exception("Buffer copy destination offset and size doesn't fit within the destination buffer's size.");
  915. if (source == dest && sourcerange.intersects(destrange))
  916. throw love::Exception("Copying a portion of a buffer to the same buffer requires non-overlapping source and destination offsets.");
  917. if (dest->isImmutable())
  918. throw love::Exception("Cannot copy to an immutable buffer.");
  919. source->copyTo(dest, sourceoffset, destoffset, size);
  920. }
  921. void Graphics::copyTextureToBuffer(Texture *source, Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth)
  922. {
  923. if (!capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER])
  924. {
  925. if (!source->isRenderTarget())
  926. throw love::Exception("Copying a non-render target Texture to a Buffer is not supported on this system.");
  927. if (!capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER])
  928. throw love::Exception("Copying a render target Texture to a Buffer is not supported on this system.");
  929. }
  930. PixelFormat format = source->getPixelFormat();
  931. if (isPixelFormatDepthStencil(format))
  932. throw love::Exception("Copying a depth/stencil Texture to a Buffer is not supported.");
  933. if (!source->isReadable())
  934. throw love::Exception("copyTextureToBuffer can only be called on readable Textures.");
  935. if (dest->getDataUsage() == BUFFERDATAUSAGE_STREAM)
  936. throw love::Exception("Buffers created with 'stream' data usage cannot be used as a copy destination.");
  937. if (dest->isImmutable())
  938. throw love::Exception("Cannot copy to an immutable buffer.");
  939. if (isRenderTargetActive(source))
  940. throw love::Exception("copyTextureToBuffer cannot be called while the Texture is an active render target.");
  941. if (mipmap < 0 || mipmap >= source->getMipmapCount())
  942. throw love::Exception("Invalid texture mipmap index %d.", mipmap + 1);
  943. TextureType textype = source->getTextureType();
  944. if (slice < 0 || (textype == TEXTURE_CUBE && slice >= 6)
  945. || (textype == TEXTURE_VOLUME && slice >= source->getDepth(mipmap))
  946. || (textype == TEXTURE_2D_ARRAY && slice >= source->getLayerCount()))
  947. {
  948. throw love::Exception("Invalid texture slice index %d.", slice + 1);
  949. }
  950. int mipw = source->getPixelWidth(mipmap);
  951. int miph = source->getPixelHeight(mipmap);
  952. if (rect.x < 0 || rect.y < 0 || rect.w <= 0 || rect.h <= 0
  953. || (rect.x + rect.w) > mipw || (rect.y + rect.h) > miph)
  954. {
  955. throw love::Exception("Invalid rectangle dimensions (x=%d, y=%d, w=%d, h=%d) for %dx%d texture.", rect.x, rect.y, rect.w, rect.h, mipw, miph);
  956. }
  957. if (destwidth <= 0)
  958. destwidth = rect.w;
  959. size_t size = 0;
  960. if (isPixelFormatCompressed(format))
  961. {
  962. if (destwidth != rect.w) // OpenGL limitation...
  963. throw love::Exception("Copying a compressed texture to a buffer cannot use a custom destination width.");
  964. const PixelFormatInfo &info = getPixelFormatInfo(format);
  965. int bw = (int) info.blockWidth;
  966. int bh = (int) info.blockHeight;
  967. if (rect.x % bw != 0 || rect.y % bh != 0 ||
  968. ((rect.w % bw != 0 || rect.h % bh != 0) && rect.x + rect.w != source->getPixelWidth(mipmap)))
  969. {
  970. const char *name = nullptr;
  971. love::getConstant(format, name);
  972. throw love::Exception("Compressed texture format %s only supports copying a sub-rectangle with offset and dimensions that are a multiple of %d x %d.", name, bw, bh);
  973. }
  974. // Note: this will need to change if destwidth == rect.w restriction
  975. // is removed.
  976. size = getPixelFormatSliceSize(format, destwidth, rect.h);
  977. }
  978. else
  979. {
  980. // Not the cleanest, but should work since uncompressed formats always
  981. // have 1x1 blocks.
  982. int pixels = (rect.h - 1) * destwidth + rect.w;
  983. size = getPixelFormatUncompressedRowSize(format, pixels);
  984. }
  985. Range destrange(destoffset, size);
  986. if (destrange.getMax() >= dest->getSize())
  987. throw love::Exception("Buffer copy destination offset and width/height doesn't fit within the destination Buffer.");
  988. source->copyToBuffer(dest, slice, mipmap, rect, destoffset, destwidth, size);
  989. }
  990. void Graphics::copyBufferToTexture(Buffer *source, Texture *dest, size_t sourceoffset, int sourcewidth, int slice, int mipmap, const Rect &rect)
  991. {
  992. if (!capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE])
  993. throw love::Exception("Copying a Buffer to a Texture is not supported on this system.");
  994. PixelFormat format = dest->getPixelFormat();
  995. if (isPixelFormatDepthStencil(format))
  996. throw love::Exception("Copying a Buffer to a depth/stencil Texture is not supported.");
  997. if (!dest->isReadable())
  998. throw love::Exception("copyBufferToTexture can only be called on readable Textures.");
  999. if (isRenderTargetActive(dest))
  1000. throw love::Exception("copyBufferToTexture cannot be called while the Texture is an active render target.");
  1001. if (mipmap < 0 || mipmap >= dest->getMipmapCount())
  1002. throw love::Exception("Invalid texture mipmap index %d.", mipmap + 1);
  1003. TextureType textype = dest->getTextureType();
  1004. if (slice < 0 || (textype == TEXTURE_CUBE && slice >= 6)
  1005. || (textype == TEXTURE_VOLUME && slice >= dest->getDepth(mipmap))
  1006. || (textype == TEXTURE_2D_ARRAY && slice >= dest->getLayerCount()))
  1007. {
  1008. throw love::Exception("Invalid texture slice index %d.", slice + 1);
  1009. }
  1010. int mipw = dest->getPixelWidth(mipmap);
  1011. int miph = dest->getPixelHeight(mipmap);
  1012. if (rect.x < 0 || rect.y < 0 || rect.w <= 0 || rect.h <= 0
  1013. || (rect.x + rect.w) > mipw || (rect.y + rect.h) > miph)
  1014. {
  1015. throw love::Exception("Invalid rectangle dimensions (x=%d, y=%d, w=%d, h=%d) for %dx%d texture.", rect.x, rect.y, rect.w, rect.h, mipw, miph);
  1016. }
  1017. if (sourcewidth <= 0)
  1018. sourcewidth = rect.w;
  1019. size_t size = 0;
  1020. if (isPixelFormatCompressed(format))
  1021. {
  1022. if (sourcewidth != rect.w) // OpenGL limitation...
  1023. throw love::Exception("Copying a buffer to a compressed texture cannot use a custom source width.");
  1024. const PixelFormatInfo &info = getPixelFormatInfo(format);
  1025. int bw = (int) info.blockWidth;
  1026. int bh = (int) info.blockHeight;
  1027. if (rect.x % bw != 0 || rect.y % bh != 0 ||
  1028. ((rect.w % bw != 0 || rect.h % bh != 0) && rect.x + rect.w != dest->getPixelWidth(mipmap)))
  1029. {
  1030. const char *name = nullptr;
  1031. love::getConstant(format, name);
  1032. throw love::Exception("Compressed texture format %s only supports copying a sub-rectangle with offset and dimensions that are a multiple of %d x %d.", name, bw, bh);
  1033. }
  1034. // Note: this will need to change if sourcewidth == rect.w restriction
  1035. // is removed.
  1036. size = getPixelFormatSliceSize(format, sourcewidth, rect.h);
  1037. }
  1038. else
  1039. {
  1040. // Not the cleanest, but should work since uncompressed formats always
  1041. // have 1x1 blocks.
  1042. int pixels = (rect.h - 1) * sourcewidth + rect.w;
  1043. size = getPixelFormatUncompressedRowSize(format, pixels);
  1044. }
  1045. Range sourcerange(sourceoffset, size);
  1046. if (sourcerange.getMax() >= source->getSize())
  1047. throw love::Exception("Buffer copy source offset and width/height doesn't fit within the source Buffer.");
  1048. dest->copyFromBuffer(source, sourceoffset, sourcewidth, size, slice, mipmap, rect);
  1049. }
  1050. void Graphics::dispatchThreadgroups(Shader* shader, int x, int y, int z)
  1051. {
  1052. if (!shader->hasStage(SHADERSTAGE_COMPUTE))
  1053. throw love::Exception("Only compute shaders can have threads dispatched.");
  1054. if (x <= 0 || y <= 0 || z <= 0)
  1055. throw love::Exception("Threadgroup dispatch size must be positive.");
  1056. if (x > capabilities.limits[LIMIT_THREADGROUPS_X]
  1057. || y > capabilities.limits[LIMIT_THREADGROUPS_Y]
  1058. || z > capabilities.limits[LIMIT_THREADGROUPS_Z])
  1059. {
  1060. throw love::Exception("Too many threadgroups dispatched.");
  1061. }
  1062. flushBatchedDraws();
  1063. auto prevshader = Shader::current;
  1064. shader->attach();
  1065. bool success = dispatch(x, y, z);
  1066. if (prevshader != nullptr)
  1067. prevshader->attach();
  1068. if (!success)
  1069. throw love::Exception("Compute shader must have resources bound to all writable texture and buffer variables.");
  1070. }
  1071. Graphics::BatchedVertexData Graphics::requestBatchedDraw(const BatchedDrawCommand &cmd)
  1072. {
  1073. BatchedDrawState &state = batchedDrawState;
  1074. bool shouldflush = false;
  1075. bool shouldresize = false;
  1076. if (cmd.primitiveMode != state.primitiveMode
  1077. || cmd.formats[0] != state.formats[0] || cmd.formats[1] != state.formats[1]
  1078. || ((cmd.indexMode != TRIANGLEINDEX_NONE) != (state.indexCount > 0))
  1079. || cmd.texture != state.texture
  1080. || cmd.standardShaderType != state.standardShaderType)
  1081. {
  1082. shouldflush = true;
  1083. }
  1084. int totalvertices = state.vertexCount + cmd.vertexCount;
  1085. // We only support uint16 index buffers for now.
  1086. if (totalvertices > LOVE_UINT16_MAX && cmd.indexMode != TRIANGLEINDEX_NONE)
  1087. shouldflush = true;
  1088. int reqIndexCount = getIndexCount(cmd.indexMode, cmd.vertexCount);
  1089. size_t reqIndexSize = reqIndexCount * sizeof(uint16);
  1090. size_t newdatasizes[2] = {0, 0};
  1091. size_t buffersizes[3] = {0, 0, 0};
  1092. for (int i = 0; i < 2; i++)
  1093. {
  1094. if (cmd.formats[i] == CommonFormat::NONE)
  1095. continue;
  1096. size_t stride = getFormatStride(cmd.formats[i]);
  1097. size_t datasize = stride * totalvertices;
  1098. if (state.vbMap[i].data != nullptr && datasize > state.vbMap[i].size)
  1099. shouldflush = true;
  1100. if (datasize > state.vb[i]->getUsableSize())
  1101. {
  1102. buffersizes[i] = std::max(datasize, state.vb[i]->getSize() * 2);
  1103. shouldresize = true;
  1104. }
  1105. newdatasizes[i] = stride * cmd.vertexCount;
  1106. }
  1107. if (cmd.indexMode != TRIANGLEINDEX_NONE)
  1108. {
  1109. size_t datasize = (state.indexCount + reqIndexCount) * sizeof(uint16);
  1110. if (state.indexBufferMap.data != nullptr && datasize > state.indexBufferMap.size)
  1111. shouldflush = true;
  1112. if (datasize > state.indexBuffer->getUsableSize())
  1113. {
  1114. buffersizes[2] = std::max(datasize, state.indexBuffer->getSize() * 2);
  1115. shouldresize = true;
  1116. }
  1117. }
  1118. if (shouldflush || shouldresize)
  1119. {
  1120. flushBatchedDraws();
  1121. state.primitiveMode = cmd.primitiveMode;
  1122. state.formats[0] = cmd.formats[0];
  1123. state.formats[1] = cmd.formats[1];
  1124. state.texture = cmd.texture;
  1125. state.standardShaderType = cmd.standardShaderType;
  1126. }
  1127. if (state.vertexCount == 0)
  1128. {
  1129. if (Shader::isDefaultActive())
  1130. Shader::attachDefault(state.standardShaderType);
  1131. if (Shader::current != nullptr)
  1132. Shader::current->validateDrawState(cmd.primitiveMode, cmd.texture);
  1133. }
  1134. if (shouldresize)
  1135. {
  1136. for (int i = 0; i < 2; i++)
  1137. {
  1138. if (state.vb[i]->getSize() < buffersizes[i])
  1139. {
  1140. state.vb[i]->release();
  1141. state.vb[i] = newStreamBuffer(BUFFERUSAGE_VERTEX, buffersizes[i]);
  1142. }
  1143. }
  1144. if (state.indexBuffer->getSize() < buffersizes[2])
  1145. {
  1146. state.indexBuffer->release();
  1147. state.indexBuffer = newStreamBuffer(BUFFERUSAGE_INDEX, buffersizes[2]);
  1148. }
  1149. }
  1150. if (cmd.indexMode != TRIANGLEINDEX_NONE)
  1151. {
  1152. if (state.indexBufferMap.data == nullptr)
  1153. state.indexBufferMap = state.indexBuffer->map(reqIndexSize);
  1154. uint16 *indices = (uint16 *) state.indexBufferMap.data;
  1155. fillIndices(cmd.indexMode, state.vertexCount, cmd.vertexCount, indices);
  1156. state.indexBufferMap.data += reqIndexSize;
  1157. }
  1158. BatchedVertexData d;
  1159. for (int i = 0; i < 2; i++)
  1160. {
  1161. if (newdatasizes[i] > 0)
  1162. {
  1163. if (state.vbMap[i].data == nullptr)
  1164. state.vbMap[i] = state.vb[i]->map(newdatasizes[i]);
  1165. d.stream[i] = state.vbMap[i].data;
  1166. state.vbMap[i].data += newdatasizes[i];
  1167. }
  1168. }
  1169. if (state.vertexCount > 0)
  1170. drawCallsBatched++;
  1171. state.vertexCount += cmd.vertexCount;
  1172. state.indexCount += reqIndexCount;
  1173. return d;
  1174. }
  1175. void Graphics::flushBatchedDraws()
  1176. {
  1177. auto &sbstate = batchedDrawState;
  1178. if (sbstate.vertexCount == 0 && sbstate.indexCount == 0)
  1179. return;
  1180. VertexAttributes attributes;
  1181. BufferBindings buffers;
  1182. size_t usedsizes[3] = {0, 0, 0};
  1183. for (int i = 0; i < 2; i++)
  1184. {
  1185. if (sbstate.formats[i] == CommonFormat::NONE)
  1186. continue;
  1187. attributes.setCommonFormat(sbstate.formats[i], (uint8) i);
  1188. usedsizes[i] = getFormatStride(sbstate.formats[i]) * sbstate.vertexCount;
  1189. size_t offset = sbstate.vb[i]->unmap(usedsizes[i]);
  1190. buffers.set(i, sbstate.vb[i], offset);
  1191. sbstate.vbMap[i] = StreamBuffer::MapInfo();
  1192. }
  1193. if (attributes.enableBits == 0)
  1194. return;
  1195. Colorf nc = getColor();
  1196. if (attributes.isEnabled(ATTRIB_COLOR))
  1197. setColor(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
  1198. pushIdentityTransform();
  1199. if (sbstate.indexCount > 0)
  1200. {
  1201. usedsizes[2] = sizeof(uint16) * sbstate.indexCount;
  1202. DrawIndexedCommand cmd(&attributes, &buffers, sbstate.indexBuffer);
  1203. cmd.primitiveType = sbstate.primitiveMode;
  1204. cmd.indexCount = sbstate.indexCount;
  1205. cmd.indexType = INDEX_UINT16;
  1206. cmd.indexBufferOffset = sbstate.indexBuffer->unmap(usedsizes[2]);
  1207. cmd.texture = sbstate.texture;
  1208. draw(cmd);
  1209. sbstate.indexBufferMap = StreamBuffer::MapInfo();
  1210. }
  1211. else
  1212. {
  1213. DrawCommand cmd(&attributes, &buffers);
  1214. cmd.primitiveType = sbstate.primitiveMode;
  1215. cmd.vertexStart = 0;
  1216. cmd.vertexCount = sbstate.vertexCount;
  1217. cmd.texture = sbstate.texture;
  1218. draw(cmd);
  1219. }
  1220. for (int i = 0; i < 2; i++)
  1221. {
  1222. if (usedsizes[i] > 0)
  1223. sbstate.vb[i]->markUsed(usedsizes[i]);
  1224. }
  1225. if (usedsizes[2] > 0)
  1226. sbstate.indexBuffer->markUsed(usedsizes[2]);
  1227. popTransform();
  1228. if (attributes.isEnabled(ATTRIB_COLOR))
  1229. setColor(nc);
  1230. batchedDrawState.vertexCount = 0;
  1231. batchedDrawState.indexCount = 0;
  1232. }
  1233. void Graphics::flushBatchedDrawsGlobal()
  1234. {
  1235. Graphics *instance = getInstance<Graphics>(M_GRAPHICS);
  1236. if (instance != nullptr)
  1237. instance->flushBatchedDraws();
  1238. }
  1239. /**
  1240. * Drawing
  1241. **/
  1242. void Graphics::draw(Drawable *drawable, const Matrix4 &m)
  1243. {
  1244. drawable->draw(this, m);
  1245. }
  1246. void Graphics::draw(Texture *texture, Quad *quad, const Matrix4 &m)
  1247. {
  1248. texture->draw(this, quad, m);
  1249. }
  1250. void Graphics::drawLayer(Texture *texture, int layer, const Matrix4 &m)
  1251. {
  1252. texture->drawLayer(this, layer, m);
  1253. }
  1254. void Graphics::drawLayer(Texture *texture, int layer, Quad *quad, const Matrix4 &m)
  1255. {
  1256. texture->drawLayer(this, layer, quad, m);
  1257. }
  1258. void Graphics::drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount)
  1259. {
  1260. mesh->drawInstanced(this, m, instancecount);
  1261. }
  1262. void Graphics::drawShaderVertices(PrimitiveType primtype, int vertexcount, int instancecount, Texture *maintexture)
  1263. {
  1264. flushBatchedDraws();
  1265. if (!capabilities.features[FEATURE_GLSL3])
  1266. throw love::Exception("drawShaderVertices is not supported on this system (GLSL3 support is required.)");
  1267. if (Shader::isDefaultActive() || !Shader::current)
  1268. throw love::Exception("drawShaderVertices can only be used with a custom shader.");
  1269. if (vertexcount < 0 || instancecount < 0)
  1270. throw love::Exception("drawShaderVertices vertex and instance count parameters must not be negative.");
  1271. Shader::current->validateDrawState(primtype, maintexture);
  1272. VertexAttributes attributes;
  1273. BufferBindings buffers;
  1274. DrawCommand cmd(&attributes, &buffers);
  1275. cmd.primitiveType = primtype;
  1276. cmd.vertexCount = vertexcount;
  1277. cmd.instanceCount = std::max(1, instancecount);
  1278. cmd.texture = maintexture;
  1279. draw(cmd);
  1280. }
  1281. void Graphics::drawShaderVertices(Buffer *indexbuffer, int indexcount, int instancecount, int startindex, Texture *maintexture)
  1282. {
  1283. flushBatchedDraws();
  1284. if (!capabilities.features[FEATURE_GLSL3])
  1285. throw love::Exception("drawShaderVertices is not supported on this system (GLSL3 support is required.)");
  1286. if (!(indexbuffer->getUsageFlags() & BUFFERUSAGEFLAG_INDEX))
  1287. throw love::Exception("The buffer passed to drawShaderVertices must be an index buffer.");
  1288. if (startindex < 0)
  1289. throw love::Exception("drawShaderVertices startindex parameter must not be negative.");
  1290. if (indexcount < 0 || instancecount < 0)
  1291. throw love::Exception("drawShaderVertices index and instance count parameters must not be negative.");
  1292. if ((size_t)(startindex + indexcount) > indexbuffer->getArrayLength() * indexbuffer->getDataMembers().size())
  1293. throw love::Exception("drawShaderVertices startindex and index count parameters do not fit in the given index buffer.");
  1294. if (Shader::isDefaultActive() || !Shader::current)
  1295. throw love::Exception("drawShaderVertices can only be used with a custom shader.");
  1296. Shader::current->validateDrawState(PRIMITIVE_TRIANGLES, maintexture);
  1297. VertexAttributes attributes;
  1298. BufferBindings buffers;
  1299. DrawIndexedCommand cmd(&attributes, &buffers, indexbuffer);
  1300. cmd.primitiveType = PRIMITIVE_TRIANGLES;
  1301. cmd.indexCount = indexcount;
  1302. cmd.instanceCount = std::max(1, instancecount);
  1303. cmd.indexType = getIndexDataType(indexbuffer->getDataMember(0).decl.format);
  1304. cmd.indexBufferOffset = startindex * getIndexDataSize(cmd.indexType);
  1305. cmd.texture = maintexture;
  1306. draw(cmd);
  1307. }
  1308. void Graphics::print(const std::vector<Font::ColoredString> &str, const Matrix4 &m)
  1309. {
  1310. checkSetDefaultFont();
  1311. if (states.back().font.get() != nullptr)
  1312. print(str, states.back().font.get(), m);
  1313. }
  1314. void Graphics::print(const std::vector<Font::ColoredString> &str, Font *font, const Matrix4 &m)
  1315. {
  1316. font->print(this, str, m, states.back().color);
  1317. }
  1318. void Graphics::printf(const std::vector<Font::ColoredString> &str, float wrap, Font::AlignMode align, const Matrix4 &m)
  1319. {
  1320. checkSetDefaultFont();
  1321. if (states.back().font.get() != nullptr)
  1322. printf(str, states.back().font.get(), wrap, align, m);
  1323. }
  1324. void Graphics::printf(const std::vector<Font::ColoredString> &str, Font *font, float wrap, Font::AlignMode align, const Matrix4 &m)
  1325. {
  1326. font->printf(this, str, wrap, align, m, states.back().color);
  1327. }
  1328. /**
  1329. * Primitives (points, shapes, lines).
  1330. **/
  1331. void Graphics::points(const Vector2 *positions, const Colorf *colors, size_t numpoints)
  1332. {
  1333. const Matrix4 &t = getTransform();
  1334. bool is2D = t.isAffine2DTransform();
  1335. BatchedDrawCommand cmd;
  1336. cmd.primitiveMode = PRIMITIVE_POINTS;
  1337. cmd.formats[0] = getSinglePositionFormat(is2D);
  1338. cmd.formats[1] = CommonFormat::RGBAub;
  1339. cmd.vertexCount = (int) numpoints;
  1340. cmd.standardShaderType = Shader::STANDARD_POINTS;
  1341. BatchedVertexData data = requestBatchedDraw(cmd);
  1342. if (is2D)
  1343. t.transformXY((Vector2 *) data.stream[0], positions, cmd.vertexCount);
  1344. else
  1345. t.transformXY0((Vector3 *) data.stream[0], positions, cmd.vertexCount);
  1346. Color32 *colordata = (Color32 *) data.stream[1];
  1347. if (colors)
  1348. {
  1349. Colorf nc = getColor();
  1350. gammaCorrectColor(nc);
  1351. if (isGammaCorrect())
  1352. {
  1353. for (int i = 0; i < cmd.vertexCount; i++)
  1354. {
  1355. Colorf ci = colors[i];
  1356. gammaCorrectColor(ci);
  1357. ci *= nc;
  1358. unGammaCorrectColor(ci);
  1359. colordata[i] = toColor32(ci);
  1360. }
  1361. }
  1362. else
  1363. {
  1364. for (int i = 0; i < cmd.vertexCount; i++)
  1365. colordata[i] = toColor32(nc * colors[i]);
  1366. }
  1367. }
  1368. else
  1369. {
  1370. Color32 c = toColor32(getColor());
  1371. for (int i = 0; i < cmd.vertexCount; i++)
  1372. colordata[i] = c;
  1373. }
  1374. }
  1375. int Graphics::calculateEllipsePoints(float rx, float ry) const
  1376. {
  1377. int points = (int) sqrtf(((rx + ry) / 2.0f) * 20.0f * (float) pixelScaleStack.back());
  1378. return std::max(points, 8);
  1379. }
  1380. void Graphics::polyline(const Vector2 *vertices, size_t count)
  1381. {
  1382. float halfwidth = getLineWidth() * 0.5f;
  1383. LineJoin linejoin = getLineJoin();
  1384. LineStyle linestyle = getLineStyle();
  1385. float pixelsize = 1.0f / std::max((float) pixelScaleStack.back(), 0.000001f);
  1386. if (linejoin == LINE_JOIN_NONE)
  1387. {
  1388. NoneJoinPolyline line;
  1389. line.render(vertices, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH);
  1390. line.draw(this);
  1391. }
  1392. else if (linejoin == LINE_JOIN_BEVEL)
  1393. {
  1394. BevelJoinPolyline line;
  1395. line.render(vertices, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH);
  1396. line.draw(this);
  1397. }
  1398. else if (linejoin == LINE_JOIN_MITER)
  1399. {
  1400. MiterJoinPolyline line;
  1401. line.render(vertices, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH);
  1402. line.draw(this);
  1403. }
  1404. }
  1405. void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h)
  1406. {
  1407. Vector2 coords[] = {Vector2(x,y), Vector2(x,y+h), Vector2(x+w,y+h), Vector2(x+w,y), Vector2(x,y)};
  1408. polygon(mode, coords, 5);
  1409. }
  1410. void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry, int points)
  1411. {
  1412. if (rx <= 0 || ry <= 0)
  1413. {
  1414. rectangle(mode, x, y, w, h);
  1415. return;
  1416. }
  1417. // Radius values that are more than half the rectangle's size aren't handled
  1418. // correctly (for now)...
  1419. if (w >= 0.02f)
  1420. rx = std::min(rx, w / 2.0f - 0.01f);
  1421. if (h >= 0.02f)
  1422. ry = std::min(ry, h / 2.0f - 0.01f);
  1423. points = std::max(points / 4, 1);
  1424. const float half_pi = static_cast<float>(LOVE_M_PI / 2);
  1425. float angle_shift = half_pi / ((float) points + 1.0f);
  1426. int num_coords = (points + 2) * 4;
  1427. Vector2 *coords = getScratchBuffer<Vector2>(num_coords + 1);
  1428. float phi = .0f;
  1429. for (int i = 0; i <= points + 2; ++i, phi += angle_shift)
  1430. {
  1431. coords[i].x = x + rx * (1 - cosf(phi));
  1432. coords[i].y = y + ry * (1 - sinf(phi));
  1433. }
  1434. phi = half_pi;
  1435. for (int i = points + 2; i <= 2 * (points + 2); ++i, phi += angle_shift)
  1436. {
  1437. coords[i].x = x + w - rx * (1 + cosf(phi));
  1438. coords[i].y = y + ry * (1 - sinf(phi));
  1439. }
  1440. phi = 2 * half_pi;
  1441. for (int i = 2 * (points + 2); i <= 3 * (points + 2); ++i, phi += angle_shift)
  1442. {
  1443. coords[i].x = x + w - rx * (1 + cosf(phi));
  1444. coords[i].y = y + h - ry * (1 + sinf(phi));
  1445. }
  1446. phi = 3 * half_pi;
  1447. for (int i = 3 * (points + 2); i <= 4 * (points + 2); ++i, phi += angle_shift)
  1448. {
  1449. coords[i].x = x + rx * (1 - cosf(phi));
  1450. coords[i].y = y + h - ry * (1 + sinf(phi));
  1451. }
  1452. coords[num_coords] = coords[0];
  1453. polygon(mode, coords, num_coords + 1);
  1454. }
  1455. void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry)
  1456. {
  1457. int points = calculateEllipsePoints(std::min(rx, std::abs(w/2)), std::min(ry, std::abs(h/2)));
  1458. rectangle(mode, x, y, w, h, rx, ry, points);
  1459. }
  1460. void Graphics::circle(DrawMode mode, float x, float y, float radius, int points)
  1461. {
  1462. ellipse(mode, x, y, radius, radius, points);
  1463. }
  1464. void Graphics::circle(DrawMode mode, float x, float y, float radius)
  1465. {
  1466. ellipse(mode, x, y, radius, radius);
  1467. }
  1468. void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b, int points)
  1469. {
  1470. float two_pi = (float) (LOVE_M_PI * 2);
  1471. if (points <= 0) points = 1;
  1472. float angle_shift = (two_pi / points);
  1473. float phi = .0f;
  1474. // 1 extra point at the end for a closed loop, and 1 extra point at the
  1475. // start in filled mode for the vertex in the center of the ellipse.
  1476. int extrapoints = 1 + (mode == DRAW_FILL ? 1 : 0);
  1477. Vector2 *polygoncoords = getScratchBuffer<Vector2>(points + extrapoints);
  1478. Vector2 *coords = polygoncoords;
  1479. if (mode == DRAW_FILL)
  1480. {
  1481. coords[0].x = x;
  1482. coords[0].y = y;
  1483. coords++;
  1484. }
  1485. for (int i = 0; i < points; ++i, phi += angle_shift)
  1486. {
  1487. coords[i].x = x + a * cosf(phi);
  1488. coords[i].y = y + b * sinf(phi);
  1489. }
  1490. coords[points] = coords[0];
  1491. // Last argument to polygon(): don't skip the last vertex in fill mode.
  1492. polygon(mode, polygoncoords, points + extrapoints, false);
  1493. }
  1494. void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b)
  1495. {
  1496. ellipse(mode, x, y, a, b, calculateEllipsePoints(a, b));
  1497. }
  1498. void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float radius, float angle1, float angle2, int points)
  1499. {
  1500. // Nothing to display with no points or equal angles. (Or is there with line mode?)
  1501. if (points <= 0 || angle1 == angle2)
  1502. return;
  1503. // Oh, you want to draw a circle?
  1504. if (fabs(angle1 - angle2) >= 2.0f * (float) LOVE_M_PI)
  1505. {
  1506. circle(drawmode, x, y, radius, points);
  1507. return;
  1508. }
  1509. float angle_shift = (angle2 - angle1) / points;
  1510. // Bail on precision issues.
  1511. if (angle_shift == 0.0)
  1512. return;
  1513. // Prevent the connecting line from being drawn if a closed line arc has a
  1514. // small angle. Avoids some visual issues when connected lines are at sharp
  1515. // angles, due to the miter line join drawing code.
  1516. if (drawmode == DRAW_LINE && arcmode == ARC_CLOSED && fabsf(angle1 - angle2) < LOVE_TORAD(4))
  1517. arcmode = ARC_OPEN;
  1518. // Quick fix for the last part of a filled open arc not being drawn (because
  1519. // polygon(DRAW_FILL, ...) doesn't work without a closed loop of vertices.)
  1520. if (drawmode == DRAW_FILL && arcmode == ARC_OPEN)
  1521. arcmode = ARC_CLOSED;
  1522. float phi = angle1;
  1523. Vector2 *coords = nullptr;
  1524. int num_coords = 0;
  1525. const auto createPoints = [&](Vector2 *coordinates)
  1526. {
  1527. for (int i = 0; i <= points; ++i, phi += angle_shift)
  1528. {
  1529. coordinates[i].x = x + radius * cosf(phi);
  1530. coordinates[i].y = y + radius * sinf(phi);
  1531. }
  1532. };
  1533. if (arcmode == ARC_PIE)
  1534. {
  1535. num_coords = points + 3;
  1536. coords = getScratchBuffer<Vector2>(num_coords);
  1537. coords[0] = coords[num_coords - 1] = Vector2(x, y);
  1538. createPoints(coords + 1);
  1539. }
  1540. else if (arcmode == ARC_OPEN)
  1541. {
  1542. num_coords = points + 1;
  1543. coords = getScratchBuffer<Vector2>(num_coords);
  1544. createPoints(coords);
  1545. }
  1546. else // ARC_CLOSED
  1547. {
  1548. num_coords = points + 2;
  1549. coords = getScratchBuffer<Vector2>(num_coords);
  1550. createPoints(coords);
  1551. // Connect the ends of the arc.
  1552. coords[num_coords - 1] = coords[0];
  1553. }
  1554. polygon(drawmode, coords, num_coords);
  1555. }
  1556. void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float radius, float angle1, float angle2)
  1557. {
  1558. float points = (float) calculateEllipsePoints(radius, radius);
  1559. // The amount of points is based on the fraction of the circle created by the arc.
  1560. float angle = fabsf(angle1 - angle2);
  1561. if (angle < 2.0f * (float) LOVE_M_PI)
  1562. points *= angle / (2.0f * (float) LOVE_M_PI);
  1563. arc(drawmode, arcmode, x, y, radius, angle1, angle2, (int) (points + 0.5f));
  1564. }
  1565. void Graphics::polygon(DrawMode mode, const Vector2 *coords, size_t count, bool skipLastFilledVertex)
  1566. {
  1567. // coords is an array of a closed loop of vertices, i.e.
  1568. // coords[count-1] == coords[0]
  1569. if (mode == DRAW_LINE)
  1570. {
  1571. polyline(coords, count);
  1572. }
  1573. else
  1574. {
  1575. const Matrix4 &t = getTransform();
  1576. bool is2D = t.isAffine2DTransform();
  1577. BatchedDrawCommand cmd;
  1578. cmd.formats[0] = getSinglePositionFormat(is2D);
  1579. cmd.formats[1] = CommonFormat::RGBAub;
  1580. cmd.indexMode = TRIANGLEINDEX_FAN;
  1581. cmd.vertexCount = (int)count - (skipLastFilledVertex ? 1 : 0);
  1582. BatchedVertexData data = requestBatchedDraw(cmd);
  1583. if (is2D)
  1584. t.transformXY((Vector2 *) data.stream[0], coords, cmd.vertexCount);
  1585. else
  1586. t.transformXY0((Vector3 *) data.stream[0], coords, cmd.vertexCount);
  1587. Color32 c = toColor32(getColor());
  1588. Color32 *colordata = (Color32 *) data.stream[1];
  1589. for (int i = 0; i < cmd.vertexCount; i++)
  1590. colordata[i] = c;
  1591. }
  1592. }
  1593. const Graphics::Capabilities &Graphics::getCapabilities() const
  1594. {
  1595. return capabilities;
  1596. }
  1597. Graphics::Stats Graphics::getStats() const
  1598. {
  1599. Stats stats;
  1600. getAPIStats(stats.shaderSwitches);
  1601. stats.drawCalls = drawCalls;
  1602. if (batchedDrawState.vertexCount > 0)
  1603. stats.drawCalls++;
  1604. stats.renderTargetSwitches = renderTargetSwitchCount;
  1605. stats.drawCallsBatched = drawCallsBatched;
  1606. stats.textures = Texture::textureCount;
  1607. stats.fonts = Font::fontCount;
  1608. stats.textureMemory = Texture::totalGraphicsMemory;
  1609. return stats;
  1610. }
  1611. size_t Graphics::getStackDepth() const
  1612. {
  1613. return stackTypeStack.size();
  1614. }
  1615. void Graphics::push(StackType type)
  1616. {
  1617. if (stackTypeStack.size() == MAX_USER_STACK_DEPTH)
  1618. throw Exception("Maximum stack depth reached (more pushes than pops?)");
  1619. pushTransform();
  1620. pixelScaleStack.push_back(pixelScaleStack.back());
  1621. if (type == STACK_ALL)
  1622. states.push_back(states.back());
  1623. stackTypeStack.push_back(type);
  1624. }
  1625. void Graphics::pop()
  1626. {
  1627. if (stackTypeStack.size() < 1)
  1628. throw Exception("Minimum stack depth reached (more pops than pushes?)");
  1629. popTransform();
  1630. pixelScaleStack.pop_back();
  1631. if (stackTypeStack.back() == STACK_ALL)
  1632. {
  1633. DisplayState &newstate = states[states.size() - 2];
  1634. restoreStateChecked(newstate);
  1635. // The last two states in the stack should be equal now.
  1636. states.pop_back();
  1637. }
  1638. stackTypeStack.pop_back();
  1639. }
  1640. /**
  1641. * Transform and stack functions.
  1642. **/
  1643. const Matrix4 &Graphics::getTransform() const
  1644. {
  1645. return transformStack.back();
  1646. }
  1647. const Matrix4 &Graphics::getDeviceProjection() const
  1648. {
  1649. return deviceProjectionMatrix;
  1650. }
  1651. void Graphics::pushTransform()
  1652. {
  1653. transformStack.push_back(transformStack.back());
  1654. }
  1655. void Graphics::pushIdentityTransform()
  1656. {
  1657. transformStack.push_back(Matrix4());
  1658. }
  1659. void Graphics::popTransform()
  1660. {
  1661. transformStack.pop_back();
  1662. }
  1663. void Graphics::rotate(float r)
  1664. {
  1665. transformStack.back().rotate(r);
  1666. }
  1667. void Graphics::scale(float x, float y)
  1668. {
  1669. transformStack.back().scale(x, y);
  1670. pixelScaleStack.back() *= (fabs(x) + fabs(y)) / 2.0;
  1671. }
  1672. void Graphics::translate(float x, float y)
  1673. {
  1674. transformStack.back().translate(x, y);
  1675. }
  1676. void Graphics::shear(float kx, float ky)
  1677. {
  1678. transformStack.back().shear(kx, ky);
  1679. }
  1680. void Graphics::origin()
  1681. {
  1682. transformStack.back().setIdentity();
  1683. pixelScaleStack.back() = 1;
  1684. }
  1685. void Graphics::applyTransform(const Matrix4 &m)
  1686. {
  1687. Matrix4 &current = transformStack.back();
  1688. current *= m;
  1689. float sx, sy;
  1690. current.getApproximateScale(sx, sy);
  1691. pixelScaleStack.back() = (sx + sy) / 2.0;
  1692. }
  1693. void Graphics::replaceTransform(const Matrix4 &m)
  1694. {
  1695. transformStack.back() = m;
  1696. float sx, sy;
  1697. m.getApproximateScale(sx, sy);
  1698. pixelScaleStack.back() = (sx + sy) / 2.0;
  1699. }
  1700. Vector2 Graphics::transformPoint(Vector2 point)
  1701. {
  1702. Vector2 p;
  1703. transformStack.back().transformXY(&p, &point, 1);
  1704. return p;
  1705. }
  1706. Vector2 Graphics::inverseTransformPoint(Vector2 point)
  1707. {
  1708. Vector2 p;
  1709. // TODO: We should probably cache the inverse transform so we don't have to
  1710. // re-calculate it every time this is called.
  1711. transformStack.back().inverse().transformXY(&p, &point, 1);
  1712. return p;
  1713. }
  1714. void Graphics::setOrthoProjection(float w, float h, float near, float far)
  1715. {
  1716. if (near >= far)
  1717. throw love::Exception("Orthographic projection Z far value must be greater than the Z near value.");
  1718. Matrix4 m = Matrix4::ortho(0.0f, w, 0.0f, h, near, far);
  1719. setCustomProjection(m);
  1720. }
  1721. void Graphics::setPerspectiveProjection(float verticalfov, float aspect, float near, float far)
  1722. {
  1723. if (near <= 0.0f)
  1724. throw love::Exception("Perspective projection Z near value must be greater than 0.");
  1725. if (near >= far)
  1726. throw love::Exception("Perspective projection Z far value must be greater than the Z near value.");
  1727. Matrix4 m = Matrix4::perspective(verticalfov, aspect, near, far);
  1728. setCustomProjection(m);
  1729. }
  1730. void Graphics::setCustomProjection(const Matrix4 &m)
  1731. {
  1732. flushBatchedDraws();
  1733. auto &state = states.back();
  1734. state.useCustomProjection = true;
  1735. state.customProjection = m;
  1736. updateDeviceProjection(m);
  1737. }
  1738. void Graphics::resetProjection()
  1739. {
  1740. flushBatchedDraws();
  1741. auto &state = states.back();
  1742. int w = getWidth();
  1743. int h = getHeight();
  1744. const auto &rt = state.renderTargets.getFirstTarget();
  1745. if (rt.texture.get())
  1746. {
  1747. w = rt.texture->getWidth(rt.mipmap);
  1748. h = rt.texture->getHeight(rt.mipmap);
  1749. }
  1750. state.useCustomProjection = false;
  1751. updateDeviceProjection(Matrix4::ortho(0.0f, w, 0.0f, h, -10.0f, 10.0f));
  1752. }
  1753. void Graphics::updateDeviceProjection(const Matrix4 &projection)
  1754. {
  1755. // Note: graphics implementations define computeDeviceProjection.
  1756. deviceProjectionMatrix = computeDeviceProjection(projection, isRenderTargetActive());
  1757. }
  1758. Matrix4 Graphics::calculateDeviceProjection(const Matrix4 &projection, uint32 flags) const
  1759. {
  1760. Matrix4 m = projection;
  1761. bool reverseZ = (flags & DEVICE_PROJECTION_REVERSE_Z) != 0;
  1762. if (flags & DEVICE_PROJECTION_FLIP_Y)
  1763. m.setRow(1, -m.getRow(1));
  1764. if (flags & DEVICE_PROJECTION_Z_01) // Go from Z [-1, 1] to Z [0, 1].
  1765. m.setRow(2, m.getRow(2) * (reverseZ ? -0.5f : 0.5f) + m.getRow(3));
  1766. else if (reverseZ)
  1767. m.setRow(2, -m.getRow(2));
  1768. return m;
  1769. }
  1770. STRINGMAP_CLASS_BEGIN(Graphics, Graphics::DrawMode, Graphics::DRAW_MAX_ENUM, drawMode)
  1771. {
  1772. { "line", Graphics::DRAW_LINE },
  1773. { "fill", Graphics::DRAW_FILL },
  1774. }
  1775. STRINGMAP_CLASS_END(Graphics, Graphics::DrawMode, Graphics::DRAW_MAX_ENUM, drawMode)
  1776. STRINGMAP_CLASS_BEGIN(Graphics, Graphics::ArcMode, Graphics::ARC_MAX_ENUM, arcMode)
  1777. {
  1778. { "open", Graphics::ARC_OPEN },
  1779. { "closed", Graphics::ARC_CLOSED },
  1780. { "pie", Graphics::ARC_PIE },
  1781. }
  1782. STRINGMAP_CLASS_END(Graphics, Graphics::ArcMode, Graphics::ARC_MAX_ENUM, arcMode)
  1783. STRINGMAP_CLASS_BEGIN(Graphics, Graphics::LineStyle, Graphics::LINE_MAX_ENUM, lineStyle)
  1784. {
  1785. { "smooth", Graphics::LINE_SMOOTH },
  1786. { "rough", Graphics::LINE_ROUGH }
  1787. }
  1788. STRINGMAP_CLASS_END(Graphics, Graphics::LineStyle, Graphics::LINE_MAX_ENUM, lineStyle)
  1789. STRINGMAP_CLASS_BEGIN(Graphics, Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM, lineJoin)
  1790. {
  1791. { "none", Graphics::LINE_JOIN_NONE },
  1792. { "miter", Graphics::LINE_JOIN_MITER },
  1793. { "bevel", Graphics::LINE_JOIN_BEVEL }
  1794. }
  1795. STRINGMAP_CLASS_END(Graphics, Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM, lineJoin)
  1796. STRINGMAP_CLASS_BEGIN(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, feature)
  1797. {
  1798. { "multirendertargetformats", Graphics::FEATURE_MULTI_RENDER_TARGET_FORMATS },
  1799. { "clampzero", Graphics::FEATURE_CLAMP_ZERO },
  1800. { "blendminmax", Graphics::FEATURE_BLEND_MINMAX },
  1801. { "lighten", Graphics::FEATURE_LIGHTEN },
  1802. { "fullnpot", Graphics::FEATURE_FULL_NPOT },
  1803. { "pixelshaderhighp", Graphics::FEATURE_PIXEL_SHADER_HIGHP },
  1804. { "shaderderivatives", Graphics::FEATURE_SHADER_DERIVATIVES },
  1805. { "glsl3", Graphics::FEATURE_GLSL3 },
  1806. { "glsl4", Graphics::FEATURE_GLSL4 },
  1807. { "instancing", Graphics::FEATURE_INSTANCING },
  1808. { "texelbuffer", Graphics::FEATURE_TEXEL_BUFFER },
  1809. { "indexbuffer32bit", Graphics::FEATURE_INDEX_BUFFER_32BIT },
  1810. { "copybuffer", Graphics::FEATURE_COPY_BUFFER },
  1811. { "copybuffertotexture", Graphics::FEATURE_COPY_BUFFER_TO_TEXTURE },
  1812. { "copytexturetobuffer", Graphics::FEATURE_COPY_TEXTURE_TO_BUFFER },
  1813. { "copyrendertargettobuffer", Graphics::FEATURE_COPY_RENDER_TARGET_TO_BUFFER },
  1814. }
  1815. STRINGMAP_CLASS_END(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, feature)
  1816. STRINGMAP_CLASS_BEGIN(Graphics, Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM, systemLimit)
  1817. {
  1818. { "pointsize", Graphics::LIMIT_POINT_SIZE },
  1819. { "texturesize", Graphics::LIMIT_TEXTURE_SIZE },
  1820. { "texturelayers", Graphics::LIMIT_TEXTURE_LAYERS },
  1821. { "volumetexturesize", Graphics::LIMIT_VOLUME_TEXTURE_SIZE },
  1822. { "cubetexturesize", Graphics::LIMIT_CUBE_TEXTURE_SIZE },
  1823. { "texelbuffersize", Graphics::LIMIT_TEXEL_BUFFER_SIZE },
  1824. { "shaderstoragebuffersize", Graphics::LIMIT_SHADER_STORAGE_BUFFER_SIZE },
  1825. { "threadgroupsx", Graphics::LIMIT_THREADGROUPS_X },
  1826. { "threadgroupsy", Graphics::LIMIT_THREADGROUPS_Y },
  1827. { "threadgroupsz", Graphics::LIMIT_THREADGROUPS_Z },
  1828. { "rendertargets", Graphics::LIMIT_RENDER_TARGETS },
  1829. { "texturemsaa", Graphics::LIMIT_TEXTURE_MSAA },
  1830. { "anisotropy", Graphics::LIMIT_ANISOTROPY },
  1831. }
  1832. STRINGMAP_CLASS_END(Graphics, Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM, systemLimit)
  1833. STRINGMAP_CLASS_BEGIN(Graphics, Graphics::StackType, Graphics::STACK_MAX_ENUM, stackType)
  1834. {
  1835. { "all", Graphics::STACK_ALL },
  1836. { "transform", Graphics::STACK_TRANSFORM },
  1837. }
  1838. STRINGMAP_CLASS_END(Graphics, Graphics::StackType, Graphics::STACK_MAX_ENUM, stackType)
  1839. STRINGMAP_BEGIN(Renderer, RENDERER_MAX_ENUM, renderer)
  1840. {
  1841. { "opengl", RENDERER_OPENGL },
  1842. { "metal", RENDERER_METAL },
  1843. }
  1844. STRINGMAP_END(Renderer, RENDERER_MAX_ENUM, renderer)
  1845. } // graphics
  1846. } // love