wrap_Graphics.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861
  1. /**
  2. * Copyright (c) 2006-2015 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. #include "wrap_Graphics.h"
  21. #include "OpenGL.h"
  22. #include "graphics/Texture.h"
  23. #include "image/ImageData.h"
  24. #include "image/Image.h"
  25. #include "font/Rasterizer.h"
  26. #include "filesystem/wrap_Filesystem.h"
  27. #include "scripts/graphics.lua.h"
  28. #include <cassert>
  29. #include <cstring>
  30. #include <algorithm>
  31. namespace love
  32. {
  33. namespace graphics
  34. {
  35. namespace opengl
  36. {
  37. #define instance() (Module::getInstance<Graphics>(Module::M_GRAPHICS))
  38. int w_reset(lua_State *)
  39. {
  40. instance()->reset();
  41. return 0;
  42. }
  43. int w_clear(lua_State *L)
  44. {
  45. std::vector<Color> colors(1);
  46. if (lua_isnoneornil(L, 1))
  47. colors[0].set(0, 0, 0, 0);
  48. else if (lua_istable(L, 1))
  49. {
  50. colors.resize((size_t) lua_gettop(L));
  51. for (int i = 0; i < lua_gettop(L); i++)
  52. {
  53. for (int j = 1; j <= 4; j++)
  54. lua_rawgeti(L, i + 1, j);
  55. colors[i].r = (unsigned char) luaL_checkinteger(L, -4);
  56. colors[i].g = (unsigned char) luaL_checkinteger(L, -3);
  57. colors[i].b = (unsigned char) luaL_checkinteger(L, -2);
  58. colors[i].a = (unsigned char) luaL_optinteger(L, -1, 255);
  59. lua_pop(L, 4);
  60. }
  61. }
  62. else
  63. {
  64. colors[0].r = (unsigned char) luaL_checkinteger(L, 1);
  65. colors[0].g = (unsigned char) luaL_checkinteger(L, 2);
  66. colors[0].b = (unsigned char) luaL_checkinteger(L, 3);
  67. colors[0].a = (unsigned char) luaL_optinteger(L, 4, 255);
  68. }
  69. luax_catchexcept(L, [&]() {
  70. if (colors.size() == 1)
  71. instance()->clear(colors[0]);
  72. else
  73. instance()->clear(colors);
  74. });
  75. return 0;
  76. }
  77. int w_discard(lua_State *L)
  78. {
  79. std::vector<bool> colorbuffers;
  80. if (lua_istable(L, 1))
  81. {
  82. for (size_t i = 1; i <= lua_objlen(L, 1); i++)
  83. {
  84. lua_rawgeti(L, 1, i);
  85. colorbuffers.push_back(luax_optboolean(L, -1, true));
  86. lua_pop(L, 1);
  87. }
  88. }
  89. else
  90. {
  91. bool discardcolor = luax_optboolean(L, 1, true);
  92. size_t numbuffers = std::max((size_t) 1, instance()->getCanvas().size());
  93. colorbuffers = std::vector<bool>(numbuffers, discardcolor);
  94. }
  95. bool stencil = luax_optboolean(L, 2, true);
  96. instance()->discard(colorbuffers, stencil);
  97. return 0;
  98. }
  99. int w_present(lua_State *)
  100. {
  101. instance()->present();
  102. return 0;
  103. }
  104. int w_isCreated(lua_State *L)
  105. {
  106. luax_pushboolean(L, instance()->isCreated());
  107. return 1;
  108. }
  109. int w_isActive(lua_State *L)
  110. {
  111. luax_pushboolean(L, instance()->isActive());
  112. return 1;
  113. }
  114. int w_getWidth(lua_State *L)
  115. {
  116. lua_pushinteger(L, instance()->getWidth());
  117. return 1;
  118. }
  119. int w_getHeight(lua_State *L)
  120. {
  121. lua_pushinteger(L, instance()->getHeight());
  122. return 1;
  123. }
  124. int w_getDimensions(lua_State *L)
  125. {
  126. lua_pushinteger(L, instance()->getWidth());
  127. lua_pushinteger(L, instance()->getHeight());
  128. return 2;
  129. }
  130. int w_setScissor(lua_State *L)
  131. {
  132. int nargs = lua_gettop(L);
  133. if (nargs == 0 || (nargs == 4 && lua_isnil(L, 1) && lua_isnil(L, 2)
  134. && lua_isnil(L, 3) && lua_isnil(L, 4)))
  135. {
  136. instance()->setScissor();
  137. return 0;
  138. }
  139. int x = luaL_checkint(L, 1);
  140. int y = luaL_checkint(L, 2);
  141. int w = luaL_checkint(L, 3);
  142. int h = luaL_checkint(L, 4);
  143. if (w < 0 || h < 0)
  144. return luaL_error(L, "Can't set scissor with negative width and/or height.");
  145. instance()->setScissor(x, y, w, h);
  146. return 0;
  147. }
  148. int w_getScissor(lua_State *L)
  149. {
  150. int x, y, w, h;
  151. if (!instance()->getScissor(x, y, w, h))
  152. return 0;
  153. lua_pushinteger(L, x);
  154. lua_pushinteger(L, y);
  155. lua_pushinteger(L, w);
  156. lua_pushinteger(L, h);
  157. return 4;
  158. }
  159. int w_stencil(lua_State *L)
  160. {
  161. luaL_checktype(L, 1, LUA_TFUNCTION);
  162. // Second argument: whether to keep the contents of the stencil buffer.
  163. if (lua_toboolean(L, 2) == 0)
  164. instance()->clearStencil();
  165. instance()->drawToStencilBuffer(true);
  166. // Call stencilfunc()
  167. lua_pushvalue(L, 1);
  168. lua_call(L, 0, 0);
  169. instance()->drawToStencilBuffer(false);
  170. return 0;
  171. }
  172. int w_setStencilTest(lua_State *L)
  173. {
  174. bool enable = luax_toboolean(L, 1);
  175. bool invert = luax_toboolean(L, 2);
  176. instance()->setStencilTest(enable, invert);
  177. return 0;
  178. }
  179. int w_getStencilTest(lua_State *L)
  180. {
  181. bool enabled, inverted;
  182. instance()->getStencilTest(enabled, inverted);
  183. luax_pushboolean(L, enabled);
  184. luax_pushboolean(L, inverted);
  185. return 2;
  186. }
  187. static const char *imageFlagName(Image::FlagType flagtype)
  188. {
  189. const char *name = nullptr;
  190. Image::getConstant(flagtype, name);
  191. return name;
  192. }
  193. int w_newImage(lua_State *L)
  194. {
  195. love::image::ImageData *data = nullptr;
  196. love::image::CompressedImageData *cdata = nullptr;
  197. Image::Flags flags;
  198. if (!lua_isnoneornil(L, 2))
  199. {
  200. luaL_checktype(L, 2, LUA_TTABLE);
  201. flags.mipmaps = luax_boolflag(L, 2, imageFlagName(Image::FLAG_TYPE_MIPMAPS), flags.mipmaps);
  202. flags.sRGB = luax_boolflag(L, 2, imageFlagName(Image::FLAG_TYPE_SRGB), flags.sRGB);
  203. }
  204. bool releasedata = false;
  205. // Convert to ImageData / CompressedImageData, if necessary.
  206. if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_ID) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_ID))
  207. {
  208. love::image::Image *image = Module::getInstance<love::image::Image>(Module::M_IMAGE);
  209. if (image == nullptr)
  210. return luaL_error(L, "Cannot load images without the love.image module.");
  211. love::filesystem::FileData *fdata = love::filesystem::luax_getfiledata(L, 1);
  212. if (image->isCompressed(fdata))
  213. {
  214. luax_catchexcept(L,
  215. [&]() { cdata = image->newCompressedData(fdata); },
  216. [&](bool) { fdata->release(); }
  217. );
  218. }
  219. else
  220. {
  221. luax_catchexcept(L,
  222. [&]() { data = image->newImageData(fdata); },
  223. [&](bool) { fdata->release(); }
  224. );
  225. }
  226. // Lua's GC won't release the image data, so we should do it ourselves.
  227. releasedata = true;
  228. }
  229. else if (luax_istype(L, 1, IMAGE_COMPRESSED_IMAGE_DATA_ID))
  230. cdata = luax_checktype<love::image::CompressedImageData>(L, 1, IMAGE_COMPRESSED_IMAGE_DATA_ID);
  231. else
  232. data = luax_checktype<love::image::ImageData>(L, 1, IMAGE_IMAGE_DATA_ID);
  233. if (!data && !cdata)
  234. return luaL_error(L, "Error creating image (could not load data.)");
  235. // Create the image.
  236. Image *image = nullptr;
  237. luax_catchexcept(L,
  238. [&]() {
  239. if (cdata)
  240. image = instance()->newImage(cdata, flags);
  241. else if (data)
  242. image = instance()->newImage(data, flags);
  243. },
  244. [&](bool) {
  245. if (releasedata && data)
  246. data->release();
  247. else if (releasedata && cdata)
  248. cdata->release();
  249. }
  250. );
  251. if (image == nullptr)
  252. return luaL_error(L, "Could not load image.");
  253. // Push the type.
  254. luax_pushtype(L, GRAPHICS_IMAGE_ID, image);
  255. image->release();
  256. return 1;
  257. }
  258. int w_newQuad(lua_State *L)
  259. {
  260. Quad::Viewport v;
  261. v.x = (float) luaL_checknumber(L, 1);
  262. v.y = (float) luaL_checknumber(L, 2);
  263. v.w = (float) luaL_checknumber(L, 3);
  264. v.h = (float) luaL_checknumber(L, 4);
  265. float sw = (float) luaL_checknumber(L, 5);
  266. float sh = (float) luaL_checknumber(L, 6);
  267. Quad *quad = instance()->newQuad(v, sw, sh);
  268. luax_pushtype(L, GRAPHICS_QUAD_ID, quad);
  269. quad->release();
  270. return 1;
  271. }
  272. int w_newFont(lua_State *L)
  273. {
  274. Font *font = nullptr;
  275. // Convert to Rasterizer, if necessary.
  276. if (!luax_istype(L, 1, FONT_RASTERIZER_ID))
  277. {
  278. std::vector<int> idxs;
  279. for (int i = 0; i < lua_gettop(L); i++)
  280. idxs.push_back(i + 1);
  281. luax_convobj(L, &idxs[0], (int) idxs.size(), "font", "newRasterizer");
  282. }
  283. love::font::Rasterizer *rasterizer = luax_checktype<love::font::Rasterizer>(L, 1, FONT_RASTERIZER_ID);
  284. luax_catchexcept(L, [&]() {
  285. font = instance()->newFont(rasterizer, instance()->getDefaultFilter()); }
  286. );
  287. // Push the type.
  288. luax_pushtype(L, GRAPHICS_FONT_ID, font);
  289. font->release();
  290. return 1;
  291. }
  292. int w_newImageFont(lua_State *L)
  293. {
  294. // filter for glyphs
  295. Texture::Filter filter = instance()->getDefaultFilter();
  296. // Convert to ImageData if necessary.
  297. if (luax_istype(L, 1, GRAPHICS_IMAGE_ID))
  298. {
  299. Image *i = luax_checktype<Image>(L, 1, GRAPHICS_IMAGE_ID);
  300. filter = i->getFilter();
  301. love::image::ImageData *id = i->getImageData();
  302. if (!id)
  303. return luaL_argerror(L, 1, "Image must not be compressed.");
  304. luax_pushtype(L, IMAGE_IMAGE_DATA_ID, id);
  305. lua_replace(L, 1);
  306. }
  307. // Convert to Rasterizer if necessary.
  308. if (!luax_istype(L, 1, FONT_RASTERIZER_ID))
  309. {
  310. luaL_checktype(L, 2, LUA_TSTRING);
  311. std::vector<int> idxs;
  312. for (int i = 0; i < lua_gettop(L); i++)
  313. idxs.push_back(i + 1);
  314. luax_convobj(L, &idxs[0], (int) idxs.size(), "font", "newImageRasterizer");
  315. }
  316. love::font::Rasterizer *rasterizer = luax_checktype<love::font::Rasterizer>(L, 1, FONT_RASTERIZER_ID);
  317. // Create the font.
  318. Font *font = instance()->newFont(rasterizer, filter);
  319. // Push the type.
  320. luax_pushtype(L, GRAPHICS_FONT_ID, font);
  321. font->release();
  322. return 1;
  323. }
  324. int w_newSpriteBatch(lua_State *L)
  325. {
  326. Texture *texture = luax_checktexture(L, 1);
  327. int size = luaL_optint(L, 2, 1000);
  328. Mesh::Usage usage = Mesh::USAGE_DYNAMIC;
  329. if (lua_gettop(L) > 2)
  330. {
  331. const char *usagestr = luaL_checkstring(L, 3);
  332. if (!Mesh::getConstant(usagestr, usage))
  333. return luaL_error(L, "Invalid SpriteBatch usage hint: %s", usagestr);
  334. }
  335. SpriteBatch *t = nullptr;
  336. luax_catchexcept(L,
  337. [&](){ t = instance()->newSpriteBatch(texture, size, usage); }
  338. );
  339. luax_pushtype(L, GRAPHICS_SPRITE_BATCH_ID, t);
  340. t->release();
  341. return 1;
  342. }
  343. int w_newParticleSystem(lua_State *L)
  344. {
  345. Texture *texture = luax_checktexture(L, 1);
  346. lua_Number size = luaL_optnumber(L, 2, 1000);
  347. ParticleSystem *t = 0;
  348. if (size < 1.0 || size > ParticleSystem::MAX_PARTICLES)
  349. return luaL_error(L, "Invalid ParticleSystem size");
  350. luax_catchexcept(L,
  351. [&](){ t = instance()->newParticleSystem(texture, int(size)); }
  352. );
  353. luax_pushtype(L, GRAPHICS_PARTICLE_SYSTEM_ID, t);
  354. t->release();
  355. return 1;
  356. }
  357. int w_newCanvas(lua_State *L)
  358. {
  359. // check if width and height are given. else default to screen dimensions.
  360. int width = luaL_optint(L, 1, instance()->getWidth());
  361. int height = luaL_optint(L, 2, instance()->getHeight());
  362. const char *str = luaL_optstring(L, 3, "normal");
  363. int msaa = luaL_optint(L, 4, 0);
  364. Canvas::Format format;
  365. if (!Canvas::getConstant(str, format))
  366. return luaL_error(L, "Invalid Canvas format: %s", str);
  367. Canvas *canvas = nullptr;
  368. luax_catchexcept(L,
  369. [&](){ canvas = instance()->newCanvas(width, height, format, msaa); }
  370. );
  371. if (canvas == nullptr)
  372. return luaL_error(L, "Canvas not created, but no error thrown. I don't even...");
  373. luax_pushtype(L, GRAPHICS_CANVAS_ID, canvas);
  374. canvas->release();
  375. return 1;
  376. }
  377. int w_newShader(lua_State *L)
  378. {
  379. // clamp stack to 2 elements
  380. lua_settop(L, 2);
  381. // read any filepath arguments
  382. for (int i = 1; i <= 2; i++)
  383. {
  384. if (!lua_isstring(L, i))
  385. continue;
  386. // call love.filesystem.isFile(arg_i)
  387. luax_getfunction(L, "filesystem", "isFile");
  388. lua_pushvalue(L, i);
  389. lua_call(L, 1, 1);
  390. bool isFile = luax_toboolean(L, -1);
  391. lua_pop(L, 1);
  392. if (isFile)
  393. {
  394. luax_getfunction(L, "filesystem", "read");
  395. lua_pushvalue(L, i);
  396. lua_call(L, 1, 1);
  397. lua_replace(L, i);
  398. }
  399. else
  400. {
  401. // Check if the argument looks like a filepath - we want a nicer
  402. // error for misspelled filepath arguments.
  403. size_t slen = 0;
  404. const char *str = lua_tolstring(L, i, &slen);
  405. if (slen > 0 && slen < 256 && !strchr(str, '\n'))
  406. {
  407. const char *ext = strchr(str, '.');
  408. if (ext != nullptr && !strchr(ext, ';') && !strchr(ext, ' '))
  409. return luaL_error(L, "Could not open file %s. Does not exist.", str);
  410. }
  411. }
  412. }
  413. bool has_arg1 = lua_isstring(L, 1) != 0;
  414. bool has_arg2 = lua_isstring(L, 2) != 0;
  415. // require at least one string argument
  416. if (!(has_arg1 || has_arg2))
  417. luaL_checkstring(L, 1);
  418. luax_getfunction(L, "graphics", "_shaderCodeToGLSL");
  419. // push vertexcode and pixelcode strings to the top of the stack
  420. lua_pushvalue(L, 1);
  421. lua_pushvalue(L, 2);
  422. // call effectCodeToGLSL, returned values will be at the top of the stack
  423. if (lua_pcall(L, 2, 2, 0) != 0)
  424. return luaL_error(L, "%s", lua_tostring(L, -1));
  425. Shader::ShaderSource source;
  426. // vertex shader code
  427. if (lua_isstring(L, -2))
  428. source.vertex = luax_checkstring(L, -2);
  429. else if (has_arg1 && has_arg2)
  430. return luaL_error(L, "Could not parse vertex shader code (missing 'position' function?)");
  431. // pixel shader code
  432. if (lua_isstring(L, -1))
  433. source.pixel = luax_checkstring(L, -1);
  434. else if (has_arg1 && has_arg2)
  435. return luaL_error(L, "Could not parse pixel shader code (missing 'effect' function?)");
  436. if (source.vertex.empty() && source.pixel.empty())
  437. {
  438. // Original args had source code, but effectCodeToGLSL couldn't translate it
  439. for (int i = 1; i <= 2; i++)
  440. {
  441. if (lua_isstring(L, i))
  442. return luaL_argerror(L, i, "missing 'position' or 'effect' function?");
  443. }
  444. }
  445. bool should_error = false;
  446. try
  447. {
  448. Shader *shader = instance()->newShader(source);
  449. luax_pushtype(L, GRAPHICS_SHADER_ID, shader);
  450. shader->release();
  451. }
  452. catch (love::Exception &e)
  453. {
  454. luax_getfunction(L, "graphics", "_transformGLSLErrorMessages");
  455. lua_pushstring(L, e.what());
  456. // Function pushes the new error string onto the stack.
  457. lua_pcall(L, 1, 1, 0);
  458. should_error = true;
  459. }
  460. if (should_error)
  461. return lua_error(L);
  462. return 1;
  463. }
  464. static Mesh::Usage luax_optmeshusage(lua_State *L, int idx, Mesh::Usage def)
  465. {
  466. const char *usagestr = lua_isnoneornil(L, idx) ? nullptr : luaL_checkstring(L, idx);
  467. if (usagestr && !Mesh::getConstant(usagestr, def))
  468. luaL_error(L, "Invalid mesh usage hint: %s", usagestr);
  469. return def;
  470. }
  471. static Mesh::DrawMode luax_optmeshdrawmode(lua_State *L, int idx, Mesh::DrawMode def)
  472. {
  473. const char *modestr = lua_isnoneornil(L, idx) ? nullptr : luaL_checkstring(L, idx);
  474. if (modestr && !Mesh::getConstant(modestr, def))
  475. luaL_error(L, "Invalid mesh draw mode: %s", modestr);
  476. return def;
  477. }
  478. template <typename T>
  479. static inline size_t writeVertexData(lua_State *L, int startidx, int components, char *data)
  480. {
  481. T *componentdata = (T *) data;
  482. for (int i = 0; i < components; i++)
  483. componentdata[i] = (T) luaL_checknumber(L, startidx + i);
  484. return sizeof(T) * components;
  485. }
  486. static Mesh *newStandardMesh(lua_State *L)
  487. {
  488. Mesh *t = nullptr;
  489. Mesh::DrawMode drawmode = luax_optmeshdrawmode(L, 2, Mesh::DRAWMODE_FAN);
  490. Mesh::Usage usage = luax_optmeshusage(L, 3, Mesh::USAGE_DYNAMIC);
  491. // First argument is a table of standard vertices, or the number of
  492. // standard vertices.
  493. if (lua_istable(L, 1))
  494. {
  495. size_t vertexcount = lua_objlen(L, 1);
  496. std::vector<Vertex> vertices;
  497. vertices.reserve(vertexcount);
  498. // Get the vertices from the table.
  499. for (size_t i = 1; i <= vertexcount; i++)
  500. {
  501. lua_rawgeti(L, 1, (int) i);
  502. if (lua_type(L, -1) != LUA_TTABLE)
  503. {
  504. luax_typerror(L, 1, "table of tables");
  505. return nullptr;
  506. }
  507. for (int j = 1; j <= 8; j++)
  508. lua_rawgeti(L, -j, j);
  509. Vertex v;
  510. v.x = (float) luaL_checknumber(L, -8);
  511. v.y = (float) luaL_checknumber(L, -7);
  512. v.s = (float) luaL_optnumber(L, -6, 0.0);
  513. v.t = (float) luaL_optnumber(L, -5, 0.0);
  514. v.r = (unsigned char) luaL_optinteger(L, -4, 255);
  515. v.g = (unsigned char) luaL_optinteger(L, -3, 255);
  516. v.b = (unsigned char) luaL_optinteger(L, -2, 255);
  517. v.a = (unsigned char) luaL_optinteger(L, -1, 255);
  518. lua_pop(L, 9);
  519. vertices.push_back(v);
  520. }
  521. luax_catchexcept(L, [&](){ t = instance()->newMesh(vertices, drawmode, usage); });
  522. }
  523. else
  524. {
  525. int count = luaL_checkint(L, 1);
  526. luax_catchexcept(L, [&](){ t = instance()->newMesh(count, drawmode, usage); });
  527. }
  528. return t;
  529. }
  530. static Mesh *newCustomMesh(lua_State *L)
  531. {
  532. Mesh *t = nullptr;
  533. // First argument is the vertex format, second is a table of vertices or
  534. // the number of vertices.
  535. std::vector<Mesh::AttribFormat> vertexformat;
  536. Mesh::DrawMode drawmode = luax_optmeshdrawmode(L, 3, Mesh::DRAWMODE_FAN);
  537. Mesh::Usage usage = luax_optmeshusage(L, 4, Mesh::USAGE_DYNAMIC);
  538. lua_rawgeti(L, 1, 1);
  539. if (!lua_istable(L, -1))
  540. {
  541. luaL_argerror(L, 1, "table of tables expected");
  542. return nullptr;
  543. }
  544. lua_pop(L, 1);
  545. // Per-vertex attribute formats.
  546. for (int i = 1; i <= (int) lua_objlen(L, 1); i++)
  547. {
  548. lua_rawgeti(L, 1, i);
  549. // {name, datatype, components}
  550. for (int j = 1; j <= 3; j++)
  551. lua_rawgeti(L, -j, j);
  552. Mesh::AttribFormat format;
  553. format.name = luaL_checkstring(L, -3);
  554. const char *tname = luaL_checkstring(L, -2);
  555. if (!Mesh::getConstant(tname, format.type))
  556. {
  557. luaL_error(L, "Invalid Mesh vertex data type name: %s", tname);
  558. return nullptr;
  559. }
  560. format.components = luaL_checkint(L, -1);
  561. if (format.components <= 0 || format.components > 4)
  562. {
  563. luaL_error(L, "Number of vertex attribute components must be between 1 and 4 (got %d)", format.components);
  564. return nullptr;
  565. }
  566. lua_pop(L, 4);
  567. vertexformat.push_back(format);
  568. }
  569. if (lua_isnumber(L, 2))
  570. {
  571. int vertexcount = luaL_checkint(L, 2);
  572. luax_catchexcept(L, [&](){ t = instance()->newMesh(vertexformat, vertexcount, drawmode, usage); });
  573. }
  574. else if (luax_istype(L, 2, DATA_ID))
  575. {
  576. // Vertex data comes directly from a Data object.
  577. Data *data = luax_checktype<Data>(L, 2, DATA_ID);
  578. luax_catchexcept(L, [&](){ t = instance()->newMesh(vertexformat, data->getData(), data->getSize(), drawmode, usage); });
  579. }
  580. else
  581. {
  582. // Table of vertices.
  583. lua_rawgeti(L, 2, 1);
  584. if (!lua_istable(L, -1))
  585. {
  586. luaL_argerror(L, 2, "expected table of tables");
  587. return nullptr;
  588. }
  589. lua_pop(L, 1);
  590. int vertexcomponents = 0;
  591. for (const Mesh::AttribFormat &format : vertexformat)
  592. vertexcomponents += format.components;
  593. size_t numvertices = lua_objlen(L, 2);
  594. luax_catchexcept(L, [&](){ t = instance()->newMesh(vertexformat, numvertices, drawmode, usage); });
  595. // Maximum possible data size for a single vertex attribute.
  596. char data[sizeof(float) * 4];
  597. for (size_t vertindex = 0; vertindex < numvertices; vertindex++)
  598. {
  599. // get vertices[vertindex]
  600. lua_rawgeti(L, 2, vertindex + 1);
  601. luaL_checktype(L, -1, LUA_TTABLE);
  602. if ((int) lua_objlen(L, -1) < vertexcomponents)
  603. {
  604. t->release();
  605. const char *err = "Invalid number of components in vertex #%d (expected %d components, got %d)";
  606. luaL_error(L, err, vertindex+1, vertexcomponents, lua_objlen(L, -1));
  607. return nullptr;
  608. }
  609. int n = 0;
  610. for (size_t i = 0; i < vertexformat.size(); i++)
  611. {
  612. int components = vertexformat[i].components;
  613. // get vertices[vertindex][n]
  614. for (int c = 0; c < components; c++)
  615. {
  616. n++;
  617. lua_rawgeti(L, -(c + 1), n);
  618. }
  619. // Fetch the values from Lua and store them in data buffer.
  620. switch (vertexformat[i].type)
  621. {
  622. case Mesh::DATA_BYTE:
  623. writeVertexData<uint8>(L, -components, components, data);
  624. break;
  625. case Mesh::DATA_FLOAT:
  626. default:
  627. writeVertexData<float>(L, -components, components, data);
  628. break;
  629. }
  630. lua_pop(L, components);
  631. luax_catchexcept(L,
  632. [&](){ t->setVertexAttribute(vertindex, i, data, sizeof(float) * 4); },
  633. [&](bool diderror){ if (diderror) t->release(); }
  634. );
  635. }
  636. lua_pop(L, 1); // pop vertices[vertindex]
  637. }
  638. t->flush();
  639. }
  640. return t;
  641. }
  642. int w_newMesh(lua_State *L)
  643. {
  644. // Check first argument: table or number of vertices.
  645. int arg1type = lua_type(L, 1);
  646. if (arg1type != LUA_TTABLE && arg1type != LUA_TNUMBER)
  647. luaL_argerror(L, 1, "table or number expected");
  648. Mesh *t = nullptr;
  649. int arg2type = lua_type(L, 2);
  650. if (arg1type == LUA_TTABLE && (arg2type == LUA_TTABLE || arg2type == LUA_TNUMBER || arg2type == LUA_TUSERDATA))
  651. t = newCustomMesh(L);
  652. else
  653. t = newStandardMesh(L);
  654. luax_pushtype(L, GRAPHICS_MESH_ID, t);
  655. t->release();
  656. return 1;
  657. }
  658. int w_newText(lua_State *L)
  659. {
  660. Font *font = luax_checkfont(L, 1);
  661. Text *t = nullptr;
  662. if (lua_isnoneornil(L, 2))
  663. luax_catchexcept(L, [&](){ t = instance()->newText(font); });
  664. else
  665. {
  666. std::string text = luax_checkstring(L, 2);
  667. luax_catchexcept(L, [&](){ t = instance()->newText(font, text); });
  668. }
  669. luax_pushtype(L, GRAPHICS_TEXT_ID, t);
  670. t->release();
  671. return 1;
  672. }
  673. int w_setColor(lua_State *L)
  674. {
  675. Color c;
  676. if (lua_istable(L, 1))
  677. {
  678. for (int i = 1; i <= 4; i++)
  679. lua_rawgeti(L, 1, i);
  680. c.r = (unsigned char)luaL_checkint(L, -4);
  681. c.g = (unsigned char)luaL_checkint(L, -3);
  682. c.b = (unsigned char)luaL_checkint(L, -2);
  683. c.a = (unsigned char)luaL_optint(L, -1, 255);
  684. lua_pop(L, 4);
  685. }
  686. else
  687. {
  688. c.r = (unsigned char)luaL_checkint(L, 1);
  689. c.g = (unsigned char)luaL_checkint(L, 2);
  690. c.b = (unsigned char)luaL_checkint(L, 3);
  691. c.a = (unsigned char)luaL_optint(L, 4, 255);
  692. }
  693. instance()->setColor(c);
  694. return 0;
  695. }
  696. int w_getColor(lua_State *L)
  697. {
  698. Color c = instance()->getColor();
  699. lua_pushinteger(L, c.r);
  700. lua_pushinteger(L, c.g);
  701. lua_pushinteger(L, c.b);
  702. lua_pushinteger(L, c.a);
  703. return 4;
  704. }
  705. int w_setBackgroundColor(lua_State *L)
  706. {
  707. Color c;
  708. if (lua_istable(L, 1))
  709. {
  710. for (int i = 1; i <= 4; i++)
  711. lua_rawgeti(L, 1, i);
  712. c.r = (unsigned char)luaL_checkint(L, -4);
  713. c.g = (unsigned char)luaL_checkint(L, -3);
  714. c.b = (unsigned char)luaL_checkint(L, -2);
  715. c.a = (unsigned char)luaL_optint(L, -1, 255);
  716. lua_pop(L, 4);
  717. }
  718. else
  719. {
  720. c.r = (unsigned char)luaL_checkint(L, 1);
  721. c.g = (unsigned char)luaL_checkint(L, 2);
  722. c.b = (unsigned char)luaL_checkint(L, 3);
  723. c.a = (unsigned char)luaL_optint(L, 4, 255);
  724. }
  725. instance()->setBackgroundColor(c);
  726. return 0;
  727. }
  728. int w_getBackgroundColor(lua_State *L)
  729. {
  730. Color c = instance()->getBackgroundColor();
  731. lua_pushinteger(L, c.r);
  732. lua_pushinteger(L, c.g);
  733. lua_pushinteger(L, c.b);
  734. lua_pushinteger(L, c.a);
  735. return 4;
  736. }
  737. int w_setNewFont(lua_State *L)
  738. {
  739. int ret = w_newFont(L);
  740. Font *font = luax_checktype<Font>(L, -1, GRAPHICS_FONT_ID);
  741. instance()->setFont(font);
  742. return ret;
  743. }
  744. int w_setFont(lua_State *L)
  745. {
  746. Font *font = luax_checktype<Font>(L, 1, GRAPHICS_FONT_ID);
  747. instance()->setFont(font);
  748. return 0;
  749. }
  750. int w_getFont(lua_State *L)
  751. {
  752. Font *f = nullptr;
  753. luax_catchexcept(L, [&](){ f = instance()->getFont(); });
  754. luax_pushtype(L, GRAPHICS_FONT_ID, f);
  755. return 1;
  756. }
  757. int w_setColorMask(lua_State *L)
  758. {
  759. Graphics::ColorMask mask;
  760. if (lua_gettop(L) <= 1 && lua_isnoneornil(L, 1))
  761. {
  762. // Enable all color components if no argument is given.
  763. mask.r = mask.g = mask.b = mask.a = true;
  764. }
  765. else
  766. {
  767. mask.r = luax_toboolean(L, 1);
  768. mask.g = luax_toboolean(L, 2);
  769. mask.b = luax_toboolean(L, 3);
  770. mask.a = luax_toboolean(L, 4);
  771. }
  772. instance()->setColorMask(mask);
  773. return 0;
  774. }
  775. int w_getColorMask(lua_State *L)
  776. {
  777. Graphics::ColorMask mask = instance()->getColorMask();
  778. luax_pushboolean(L, mask.r);
  779. luax_pushboolean(L, mask.g);
  780. luax_pushboolean(L, mask.b);
  781. luax_pushboolean(L, mask.a);
  782. return 4;
  783. }
  784. int w_setBlendMode(lua_State *L)
  785. {
  786. Graphics::BlendMode mode;
  787. const char *str = luaL_checkstring(L, 1);
  788. if (!Graphics::getConstant(str, mode))
  789. return luaL_error(L, "Invalid blend mode: %s", str);
  790. luax_catchexcept(L, [&](){ instance()->setBlendMode(mode); });
  791. return 0;
  792. }
  793. int w_getBlendMode(lua_State *L)
  794. {
  795. const char *str;
  796. Graphics::BlendMode mode;
  797. luax_catchexcept(L, [&](){ mode = instance()->getBlendMode(); });
  798. if (!Graphics::getConstant(mode, str))
  799. return luaL_error(L, "Unknown blend mode");
  800. lua_pushstring(L, str);
  801. return 1;
  802. }
  803. int w_setDefaultFilter(lua_State *L)
  804. {
  805. Texture::Filter f;
  806. const char *minstr = luaL_checkstring(L, 1);
  807. const char *magstr = luaL_optstring(L, 2, minstr);
  808. if (!Texture::getConstant(minstr, f.min))
  809. return luaL_error(L, "Invalid filter mode: %s", minstr);
  810. if (!Texture::getConstant(magstr, f.mag))
  811. return luaL_error(L, "Invalid filter mode: %s", magstr);
  812. f.anisotropy = (float) luaL_optnumber(L, 3, 1.0);
  813. instance()->setDefaultFilter(f);
  814. return 0;
  815. }
  816. int w_getDefaultFilter(lua_State *L)
  817. {
  818. const Texture::Filter &f = instance()->getDefaultFilter();
  819. const char *minstr;
  820. const char *magstr;
  821. if (!Texture::getConstant(f.min, minstr))
  822. return luaL_error(L, "Unknown minification filter mode");
  823. if (!Texture::getConstant(f.mag, magstr))
  824. return luaL_error(L, "Unknown magnification filter mode");
  825. lua_pushstring(L, minstr);
  826. lua_pushstring(L, magstr);
  827. lua_pushnumber(L, f.anisotropy);
  828. return 3;
  829. }
  830. int w_setDefaultMipmapFilter(lua_State *L)
  831. {
  832. Texture::FilterMode filter = Texture::FILTER_NONE;
  833. if (!lua_isnoneornil(L, 1))
  834. {
  835. const char *str = luaL_checkstring(L, 1);
  836. if (!Texture::getConstant(str, filter))
  837. return luaL_error(L, "Invalid filter mode: %s", str);
  838. }
  839. float sharpness = (float) luaL_optnumber(L, 2, 0);
  840. instance()->setDefaultMipmapFilter(filter, sharpness);
  841. return 0;
  842. }
  843. int w_getDefaultMipmapFilter(lua_State *L)
  844. {
  845. Texture::FilterMode filter;
  846. float sharpness;
  847. instance()->getDefaultMipmapFilter(&filter, &sharpness);
  848. const char *str;
  849. if (Texture::getConstant(filter, str))
  850. lua_pushstring(L, str);
  851. else
  852. lua_pushnil(L);
  853. lua_pushnumber(L, sharpness);
  854. return 2;
  855. }
  856. int w_setLineWidth(lua_State *L)
  857. {
  858. float width = (float)luaL_checknumber(L, 1);
  859. instance()->setLineWidth(width);
  860. return 0;
  861. }
  862. int w_setLineStyle(lua_State *L)
  863. {
  864. Graphics::LineStyle style;
  865. const char *str = luaL_checkstring(L, 1);
  866. if (!Graphics::getConstant(str, style))
  867. return luaL_error(L, "Invalid line style: %s", str);
  868. instance()->setLineStyle(style);
  869. return 0;
  870. }
  871. int w_setLineJoin(lua_State *L)
  872. {
  873. Graphics::LineJoin join;
  874. const char *str = luaL_checkstring(L, 1);
  875. if (!Graphics::getConstant(str, join))
  876. return luaL_error(L, "Invalid line join mode: %s", str);
  877. instance()->setLineJoin(join);
  878. return 0;
  879. }
  880. int w_getLineWidth(lua_State *L)
  881. {
  882. lua_pushnumber(L, instance()->getLineWidth());
  883. return 1;
  884. }
  885. int w_getLineStyle(lua_State *L)
  886. {
  887. Graphics::LineStyle style = instance()->getLineStyle();
  888. const char *str;
  889. if (!Graphics::getConstant(style, str))
  890. return luaL_error(L, "Unknown line style");
  891. lua_pushstring(L, str);
  892. return 1;
  893. }
  894. int w_getLineJoin(lua_State *L)
  895. {
  896. Graphics::LineJoin join = instance()->getLineJoin();
  897. const char *str;
  898. if (!Graphics::getConstant(join, str))
  899. return luaL_error(L, "Unknown line join");
  900. lua_pushstring(L, str);
  901. return 1;
  902. }
  903. int w_setPointSize(lua_State *L)
  904. {
  905. float size = (float)luaL_checknumber(L, 1);
  906. instance()->setPointSize(size);
  907. return 0;
  908. }
  909. int w_getPointSize(lua_State *L)
  910. {
  911. lua_pushnumber(L, instance()->getPointSize());
  912. return 1;
  913. }
  914. int w_setWireframe(lua_State *L)
  915. {
  916. instance()->setWireframe(luax_toboolean(L, 1));
  917. return 0;
  918. }
  919. int w_isWireframe(lua_State *L)
  920. {
  921. luax_pushboolean(L, instance()->isWireframe());
  922. return 1;
  923. }
  924. int w_newScreenshot(lua_State *L)
  925. {
  926. love::image::Image *image = luax_getmodule<love::image::Image>(L, MODULE_IMAGE_ID);
  927. bool copyAlpha = luax_optboolean(L, 1, false);
  928. love::image::ImageData *i = 0;
  929. luax_catchexcept(L, [&](){ i = instance()->newScreenshot(image, copyAlpha); });
  930. luax_pushtype(L, IMAGE_IMAGE_DATA_ID, i);
  931. i->release();
  932. return 1;
  933. }
  934. int w_setCanvas(lua_State *L)
  935. {
  936. // Disable stencil writes.
  937. instance()->drawToStencilBuffer(false);
  938. // called with none -> reset to default buffer
  939. if (lua_isnoneornil(L, 1))
  940. {
  941. instance()->setCanvas();
  942. return 0;
  943. }
  944. bool is_table = lua_istable(L, 1);
  945. std::vector<Canvas *> canvases;
  946. if (is_table)
  947. {
  948. for (int i = 1; i <= (int) lua_objlen(L, 1); i++)
  949. {
  950. lua_rawgeti(L, 1, i);
  951. canvases.push_back(luax_checkcanvas(L, -1));
  952. lua_pop(L, 1);
  953. }
  954. }
  955. else
  956. {
  957. for (int i = 1; i <= lua_gettop(L); i++)
  958. canvases.push_back(luax_checkcanvas(L, i));
  959. }
  960. luax_catchexcept(L, [&]() {
  961. if (canvases.size() > 0)
  962. instance()->setCanvas(canvases);
  963. else
  964. instance()->setCanvas();
  965. });
  966. return 0;
  967. }
  968. int w_getCanvas(lua_State *L)
  969. {
  970. const std::vector<Canvas *> canvases = instance()->getCanvas();
  971. int n = 0;
  972. for (Canvas *c : canvases)
  973. {
  974. luax_pushtype(L, GRAPHICS_CANVAS_ID, c);
  975. n++;
  976. }
  977. if (n == 0)
  978. {
  979. lua_pushnil(L);
  980. n = 1;
  981. }
  982. return n;
  983. }
  984. int w_setShader(lua_State *L)
  985. {
  986. if (lua_isnoneornil(L,1))
  987. {
  988. instance()->setShader();
  989. return 0;
  990. }
  991. Shader *shader = luax_checkshader(L, 1);
  992. instance()->setShader(shader);
  993. return 0;
  994. }
  995. int w_getShader(lua_State *L)
  996. {
  997. Shader *shader = instance()->getShader();
  998. if (shader)
  999. luax_pushtype(L, GRAPHICS_SHADER_ID, shader);
  1000. else
  1001. lua_pushnil(L);
  1002. return 1;
  1003. }
  1004. int w_setDefaultShaderCode(lua_State *L)
  1005. {
  1006. luaL_checktype(L, 1, LUA_TTABLE);
  1007. lua_getfield(L, 1, "opengl");
  1008. lua_rawgeti(L, -1, 1);
  1009. lua_rawgeti(L, -2, 2);
  1010. Shader::ShaderSource openglcode;
  1011. openglcode.vertex = luax_checkstring(L, -2);
  1012. openglcode.pixel = luax_checkstring(L, -1);
  1013. lua_pop(L, 3);
  1014. lua_getfield(L, 1, "opengles");
  1015. lua_rawgeti(L, -1, 1);
  1016. lua_rawgeti(L, -2, 2);
  1017. Shader::ShaderSource openglescode;
  1018. openglescode.vertex = luax_checkstring(L, -2);
  1019. openglescode.pixel = luax_checkstring(L, -1);
  1020. lua_pop(L, 3);
  1021. Shader::defaultCode[Graphics::RENDERER_OPENGL] = openglcode;
  1022. Shader::defaultCode[Graphics::RENDERER_OPENGLES] = openglescode;
  1023. return 0;
  1024. }
  1025. int w_getSupported(lua_State *L)
  1026. {
  1027. lua_createtable(L, 0, (int) Graphics::SUPPORT_MAX_ENUM);
  1028. for (int i = 0; i < (int) Graphics::SUPPORT_MAX_ENUM; i++)
  1029. {
  1030. Graphics::Support feature = (Graphics::Support) i;
  1031. const char *name = nullptr;
  1032. if (!Graphics::getConstant(feature, name))
  1033. continue;
  1034. luax_pushboolean(L, instance()->isSupported(feature));
  1035. lua_setfield(L, -2, name);
  1036. }
  1037. return 1;
  1038. }
  1039. int w_getCanvasFormats(lua_State *L)
  1040. {
  1041. lua_createtable(L, 0, (int) Canvas::FORMAT_MAX_ENUM);
  1042. for (int i = 0; i < (int) Canvas::FORMAT_MAX_ENUM; i++)
  1043. {
  1044. Canvas::Format format = (Canvas::Format) i;
  1045. const char *name = nullptr;
  1046. if (!Canvas::getConstant(format, name))
  1047. continue;
  1048. luax_pushboolean(L, Canvas::isFormatSupported(format));
  1049. lua_setfield(L, -2, name);
  1050. }
  1051. return 1;
  1052. }
  1053. int w_getCompressedImageFormats(lua_State *L)
  1054. {
  1055. lua_createtable(L, 0, (int) image::CompressedImageData::FORMAT_MAX_ENUM);
  1056. for (int i = 0; i < (int) image::CompressedImageData::FORMAT_MAX_ENUM; i++)
  1057. {
  1058. image::CompressedImageData::Format format = (image::CompressedImageData::Format) i;
  1059. const char *name = nullptr;
  1060. if (format == image::CompressedImageData::FORMAT_UNKNOWN)
  1061. continue;
  1062. if (!image::CompressedImageData::getConstant(format, name))
  1063. continue;
  1064. luax_pushboolean(L, Image::hasCompressedTextureSupport(format, false));
  1065. lua_setfield(L, -2, name);
  1066. }
  1067. return 1;
  1068. }
  1069. int w_getRendererInfo(lua_State *L)
  1070. {
  1071. Graphics::RendererInfo info;
  1072. luax_catchexcept(L, [&](){ info = instance()->getRendererInfo(); });
  1073. luax_pushstring(L, info.name);
  1074. luax_pushstring(L, info.version);
  1075. luax_pushstring(L, info.vendor);
  1076. luax_pushstring(L, info.device);
  1077. return 4;
  1078. }
  1079. int w_getSystemLimits(lua_State *L)
  1080. {
  1081. lua_createtable(L, 0, (int) Graphics::LIMIT_MAX_ENUM);
  1082. for (int i = 0; i < (int) Graphics::LIMIT_MAX_ENUM; i++)
  1083. {
  1084. Graphics::SystemLimit limittype = (Graphics::SystemLimit) i;
  1085. const char *name = nullptr;
  1086. if (!Graphics::getConstant(limittype, name))
  1087. continue;
  1088. lua_pushnumber(L, instance()->getSystemLimit(limittype));
  1089. lua_setfield(L, -2, name);
  1090. }
  1091. return 1;
  1092. }
  1093. int w_getStats(lua_State *L)
  1094. {
  1095. Graphics::Stats stats = instance()->getStats();
  1096. lua_createtable(L, 0, (int) Graphics::STAT_MAX_ENUM);
  1097. const char *sname = nullptr;
  1098. Graphics::getConstant(Graphics::STAT_DRAW_CALLS, sname);
  1099. lua_pushinteger(L, stats.drawCalls);
  1100. lua_setfield(L, -2, sname);
  1101. Graphics::getConstant(Graphics::STAT_CANVAS_SWITCHES, sname);
  1102. lua_pushinteger(L, stats.canvasSwitches);
  1103. lua_setfield(L, -2, sname);
  1104. Graphics::getConstant(Graphics::STAT_CANVASES, sname);
  1105. lua_pushinteger(L, stats.canvases);
  1106. lua_setfield(L, -2, sname);
  1107. Graphics::getConstant(Graphics::STAT_IMAGES, sname);
  1108. lua_pushinteger(L, stats.images);
  1109. lua_setfield(L, -2, sname);
  1110. Graphics::getConstant(Graphics::STAT_FONTS, sname);
  1111. lua_pushinteger(L, stats.fonts);
  1112. lua_setfield(L, -2, sname);
  1113. Graphics::getConstant(Graphics::STAT_TEXTURE_MEMORY, sname);
  1114. lua_pushnumber(L, (lua_Number) stats.textureMemory);
  1115. lua_setfield(L, -2, sname);
  1116. return 1;
  1117. }
  1118. int w_draw(lua_State *L)
  1119. {
  1120. Drawable *drawable = nullptr;
  1121. Texture *texture = nullptr;
  1122. Quad *quad = nullptr;
  1123. int startidx = 2;
  1124. if (luax_istype(L, 2, GRAPHICS_QUAD_ID))
  1125. {
  1126. texture = luax_checktexture(L, 1);
  1127. quad = luax_totype<Quad>(L, 2, GRAPHICS_QUAD_ID);
  1128. startidx = 3;
  1129. }
  1130. else if (lua_isnil(L, 2) && !lua_isnoneornil(L, 3))
  1131. {
  1132. return luax_typerror(L, 2, "Quad");
  1133. }
  1134. else
  1135. {
  1136. drawable = luax_checktype<Drawable>(L, 1, GRAPHICS_DRAWABLE_ID);
  1137. startidx = 2;
  1138. }
  1139. float x = (float) luaL_optnumber(L, startidx + 0, 0.0);
  1140. float y = (float) luaL_optnumber(L, startidx + 1, 0.0);
  1141. float a = (float) luaL_optnumber(L, startidx + 2, 0.0);
  1142. float sx = (float) luaL_optnumber(L, startidx + 3, 1.0);
  1143. float sy = (float) luaL_optnumber(L, startidx + 4, sx);
  1144. float ox = (float) luaL_optnumber(L, startidx + 5, 0.0);
  1145. float oy = (float) luaL_optnumber(L, startidx + 6, 0.0);
  1146. float kx = (float) luaL_optnumber(L, startidx + 7, 0.0);
  1147. float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
  1148. luax_catchexcept(L, [&]() {
  1149. if (texture && quad)
  1150. texture->drawq(quad, x, y, a, sx, sy, ox, oy, kx, ky);
  1151. else if (drawable)
  1152. drawable->draw(x, y, a, sx, sy, ox, oy, kx, ky);
  1153. });
  1154. return 0;
  1155. }
  1156. int w_print(lua_State *L)
  1157. {
  1158. std::string str = luax_checkstring(L, 1);
  1159. float x = (float)luaL_optnumber(L, 2, 0.0);
  1160. float y = (float)luaL_optnumber(L, 3, 0.0);
  1161. float angle = (float)luaL_optnumber(L, 4, 0.0f);
  1162. float sx = (float)luaL_optnumber(L, 5, 1.0f);
  1163. float sy = (float)luaL_optnumber(L, 6, sx);
  1164. float ox = (float)luaL_optnumber(L, 7, 0.0f);
  1165. float oy = (float)luaL_optnumber(L, 8, 0.0f);
  1166. float kx = (float)luaL_optnumber(L, 9, 0.0f);
  1167. float ky = (float)luaL_optnumber(L, 10, 0.0f);
  1168. luax_catchexcept(L,
  1169. [&](){ instance()->print(str, x, y, angle, sx, sy, ox, oy, kx,ky); }
  1170. );
  1171. return 0;
  1172. }
  1173. int w_printf(lua_State *L)
  1174. {
  1175. std::string str = luax_checkstring(L, 1);
  1176. float x = (float)luaL_checknumber(L, 2);
  1177. float y = (float)luaL_checknumber(L, 3);
  1178. float wrap = (float)luaL_checknumber(L, 4);
  1179. float angle = 0.0f;
  1180. float sx = 1.0f, sy = 1.0f;
  1181. float ox = 0.0f, oy = 0.0f;
  1182. float kx = 0.0f, ky = 0.0f;
  1183. Font::AlignMode align = Font::ALIGN_LEFT;
  1184. if (lua_gettop(L) >= 5)
  1185. {
  1186. if (!lua_isnil(L, 5))
  1187. {
  1188. const char *str = luaL_checkstring(L, 5);
  1189. if (!Font::getConstant(str, align))
  1190. return luaL_error(L, "Incorrect alignment: %s", str);
  1191. }
  1192. angle = (float) luaL_optnumber(L, 6, 0.0f);
  1193. sx = (float) luaL_optnumber(L, 7, 1.0f);
  1194. sy = (float) luaL_optnumber(L, 8, sx);
  1195. ox = (float) luaL_optnumber(L, 9, 0.0f);
  1196. oy = (float) luaL_optnumber(L, 10, 0.0f);
  1197. kx = (float) luaL_optnumber(L, 11, 0.0f);
  1198. ky = (float) luaL_optnumber(L, 12, 0.0f);
  1199. }
  1200. luax_catchexcept(L,
  1201. [&](){ instance()->printf(str, x, y, wrap, align, angle, sx, sy, ox, oy, kx, ky); }
  1202. );
  1203. return 0;
  1204. }
  1205. int w_point(lua_State *L)
  1206. {
  1207. float x = (float)luaL_checknumber(L, 1);
  1208. float y = (float)luaL_checknumber(L, 2);
  1209. instance()->point(x, y);
  1210. return 0;
  1211. }
  1212. int w_line(lua_State *L)
  1213. {
  1214. int args = lua_gettop(L);
  1215. bool is_table = false;
  1216. if (args == 1 && lua_istable(L, 1))
  1217. {
  1218. args = (int) lua_objlen(L, 1);
  1219. is_table = true;
  1220. }
  1221. if (args % 2 != 0)
  1222. return luaL_error(L, "Number of vertex components must be a multiple of two");
  1223. else if (args < 4)
  1224. return luaL_error(L, "Need at least two vertices to draw a line");
  1225. float *coords = new float[args];
  1226. if (is_table)
  1227. {
  1228. for (int i = 0; i < args; ++i)
  1229. {
  1230. lua_rawgeti(L, 1, i + 1);
  1231. coords[i] = luax_tofloat(L, -1);
  1232. lua_pop(L, 1);
  1233. }
  1234. }
  1235. else
  1236. {
  1237. for (int i = 0; i < args; ++i)
  1238. coords[i] = luax_tofloat(L, i + 1);
  1239. }
  1240. instance()->polyline(coords, args);
  1241. delete[] coords;
  1242. return 0;
  1243. }
  1244. int w_rectangle(lua_State *L)
  1245. {
  1246. Graphics::DrawMode mode;
  1247. const char *str = luaL_checkstring(L, 1);
  1248. if (!Graphics::getConstant(str, mode))
  1249. return luaL_error(L, "Incorrect draw mode %s", str);
  1250. float x = (float)luaL_checknumber(L, 2);
  1251. float y = (float)luaL_checknumber(L, 3);
  1252. float w = (float)luaL_checknumber(L, 4);
  1253. float h = (float)luaL_checknumber(L, 5);
  1254. float rx = (float)luaL_optnumber(L, 6, 0.0);
  1255. float ry = (float)luaL_optnumber(L, 7, rx);
  1256. if (rx >= w / 2.0)
  1257. return luaL_error(L, "Invalid rectangle x-axis radius (must be less than half the width)");
  1258. if (ry >= h / 2.0)
  1259. return luaL_error(L, "Invalid rectangle y-axis radius (must be less than half the height)");
  1260. int points;
  1261. if (lua_isnoneornil(L, 8))
  1262. points = std::max(rx, ry) > 20.0 ? (int)(std::max(rx, ry) / 2) : 10;
  1263. else
  1264. points = luaL_checkint(L, 8);
  1265. instance()->rectangle(mode, x, y, w, h, rx, ry, points);
  1266. return 0;
  1267. }
  1268. int w_circle(lua_State *L)
  1269. {
  1270. Graphics::DrawMode mode;
  1271. const char *str = luaL_checkstring(L, 1);
  1272. if (!Graphics::getConstant(str, mode))
  1273. return luaL_error(L, "Incorrect draw mode %s", str);
  1274. float x = (float)luaL_checknumber(L, 2);
  1275. float y = (float)luaL_checknumber(L, 3);
  1276. float radius = (float)luaL_checknumber(L, 4);
  1277. int points;
  1278. if (lua_isnoneornil(L, 5))
  1279. points = radius > 10 ? (int)(radius) : 10;
  1280. else
  1281. points = luaL_checkint(L, 5);
  1282. instance()->circle(mode, x, y, radius, points);
  1283. return 0;
  1284. }
  1285. int w_ellipse(lua_State *L)
  1286. {
  1287. Graphics::DrawMode mode;
  1288. const char *str = luaL_checkstring(L, 1);
  1289. if (!Graphics::getConstant(str, mode))
  1290. return luaL_error(L, "Incorrect draw mode %s", str);
  1291. float x = (float)luaL_checknumber(L, 2);
  1292. float y = (float)luaL_checknumber(L, 3);
  1293. float a = (float)luaL_checknumber(L, 4);
  1294. float b = (float)luaL_optnumber(L, 5, a);
  1295. int points;
  1296. if (lua_isnoneornil(L, 6))
  1297. points = a + b > 30 ? (int)((a + b) / 2) : 15;
  1298. else
  1299. points = luaL_checkint(L, 6);
  1300. instance()->ellipse(mode, x, y, a, b, points);
  1301. return 0;
  1302. }
  1303. int w_arc(lua_State *L)
  1304. {
  1305. Graphics::DrawMode mode;
  1306. const char *str = luaL_checkstring(L, 1);
  1307. if (!Graphics::getConstant(str, mode))
  1308. return luaL_error(L, "Incorrect draw mode %s", str);
  1309. float x = (float)luaL_checknumber(L, 2);
  1310. float y = (float)luaL_checknumber(L, 3);
  1311. float radius = (float)luaL_checknumber(L, 4);
  1312. float angle1 = (float)luaL_checknumber(L, 5);
  1313. float angle2 = (float)luaL_checknumber(L, 6);
  1314. int points;
  1315. if (lua_isnoneornil(L, 7))
  1316. points = radius > 10 ? (int)(radius) : 10;
  1317. else
  1318. points = luaL_checkint(L, 7);
  1319. instance()->arc(mode, x, y, radius, angle1, angle2, points);
  1320. return 0;
  1321. }
  1322. int w_polygon(lua_State *L)
  1323. {
  1324. int args = lua_gettop(L) - 1;
  1325. Graphics::DrawMode mode;
  1326. const char *str = luaL_checkstring(L, 1);
  1327. if (!Graphics::getConstant(str, mode))
  1328. return luaL_error(L, "Invalid draw mode: %s", str);
  1329. bool is_table = false;
  1330. float *coords;
  1331. if (args == 1 && lua_istable(L, 2))
  1332. {
  1333. args = (int) lua_objlen(L, 2);
  1334. is_table = true;
  1335. }
  1336. if (args % 2 != 0)
  1337. return luaL_error(L, "Number of vertex components must be a multiple of two");
  1338. else if (args < 6)
  1339. return luaL_error(L, "Need at least three vertices to draw a polygon");
  1340. // fetch coords
  1341. coords = new float[args + 2];
  1342. if (is_table)
  1343. {
  1344. for (int i = 0; i < args; ++i)
  1345. {
  1346. lua_rawgeti(L, 2, i + 1);
  1347. coords[i] = luax_tofloat(L, -1);
  1348. lua_pop(L, 1);
  1349. }
  1350. }
  1351. else
  1352. {
  1353. for (int i = 0; i < args; ++i)
  1354. coords[i] = luax_tofloat(L, i + 2);
  1355. }
  1356. // make a closed loop
  1357. coords[args] = coords[0];
  1358. coords[args+1] = coords[1];
  1359. instance()->polygon(mode, coords, args+2);
  1360. delete[] coords;
  1361. return 0;
  1362. }
  1363. int w_push(lua_State *L)
  1364. {
  1365. Graphics::StackType stype = Graphics::STACK_TRANSFORM;
  1366. const char *sname = lua_isnoneornil(L, 1) ? nullptr : luaL_checkstring(L, 1);
  1367. if (sname && !Graphics::getConstant(sname, stype))
  1368. return luaL_error(L, "Invalid graphics stack type: %s", sname);
  1369. luax_catchexcept(L, [&](){ instance()->push(stype); });
  1370. return 0;
  1371. }
  1372. int w_pop(lua_State *L)
  1373. {
  1374. luax_catchexcept(L, [&](){ instance()->pop(); });
  1375. return 0;
  1376. }
  1377. int w_rotate(lua_State *L)
  1378. {
  1379. float angle = (float)luaL_checknumber(L, 1);
  1380. instance()->rotate(angle);
  1381. return 0;
  1382. }
  1383. int w_scale(lua_State *L)
  1384. {
  1385. float sx = (float)luaL_optnumber(L, 1, 1.0f);
  1386. float sy = (float)luaL_optnumber(L, 2, sx);
  1387. instance()->scale(sx, sy);
  1388. return 0;
  1389. }
  1390. int w_translate(lua_State *L)
  1391. {
  1392. float x = (float)luaL_checknumber(L, 1);
  1393. float y = (float)luaL_checknumber(L, 2);
  1394. instance()->translate(x, y);
  1395. return 0;
  1396. }
  1397. int w_shear(lua_State *L)
  1398. {
  1399. float kx = (float)luaL_checknumber(L, 1);
  1400. float ky = (float)luaL_checknumber(L, 2);
  1401. instance()->shear(kx, ky);
  1402. return 0;
  1403. }
  1404. int w_origin(lua_State * /*L*/)
  1405. {
  1406. instance()->origin();
  1407. return 0;
  1408. }
  1409. // List of functions to wrap.
  1410. static const luaL_Reg functions[] =
  1411. {
  1412. { "reset", w_reset },
  1413. { "clear", w_clear },
  1414. { "discard", w_discard },
  1415. { "present", w_present },
  1416. { "newImage", w_newImage },
  1417. { "newQuad", w_newQuad },
  1418. { "newFont", w_newFont },
  1419. { "newImageFont", w_newImageFont },
  1420. { "newSpriteBatch", w_newSpriteBatch },
  1421. { "newParticleSystem", w_newParticleSystem },
  1422. { "newCanvas", w_newCanvas },
  1423. { "newShader", w_newShader },
  1424. { "newMesh", w_newMesh },
  1425. { "newText", w_newText },
  1426. { "setColor", w_setColor },
  1427. { "getColor", w_getColor },
  1428. { "setBackgroundColor", w_setBackgroundColor },
  1429. { "getBackgroundColor", w_getBackgroundColor },
  1430. { "setNewFont", w_setNewFont },
  1431. { "setFont", w_setFont },
  1432. { "getFont", w_getFont },
  1433. { "setColorMask", w_setColorMask },
  1434. { "getColorMask", w_getColorMask },
  1435. { "setBlendMode", w_setBlendMode },
  1436. { "getBlendMode", w_getBlendMode },
  1437. { "setDefaultFilter", w_setDefaultFilter },
  1438. { "getDefaultFilter", w_getDefaultFilter },
  1439. { "setDefaultMipmapFilter", w_setDefaultMipmapFilter },
  1440. { "getDefaultMipmapFilter", w_getDefaultMipmapFilter },
  1441. { "setLineWidth", w_setLineWidth },
  1442. { "setLineStyle", w_setLineStyle },
  1443. { "setLineJoin", w_setLineJoin },
  1444. { "getLineWidth", w_getLineWidth },
  1445. { "getLineStyle", w_getLineStyle },
  1446. { "getLineJoin", w_getLineJoin },
  1447. { "setPointSize", w_setPointSize },
  1448. { "getPointSize", w_getPointSize },
  1449. { "setWireframe", w_setWireframe },
  1450. { "isWireframe", w_isWireframe },
  1451. { "newScreenshot", w_newScreenshot },
  1452. { "setCanvas", w_setCanvas },
  1453. { "getCanvas", w_getCanvas },
  1454. { "setShader", w_setShader },
  1455. { "getShader", w_getShader },
  1456. { "_setDefaultShaderCode", w_setDefaultShaderCode },
  1457. { "getSupported", w_getSupported },
  1458. { "getCanvasFormats", w_getCanvasFormats },
  1459. { "getCompressedImageFormats", w_getCompressedImageFormats },
  1460. { "getRendererInfo", w_getRendererInfo },
  1461. { "getSystemLimits", w_getSystemLimits },
  1462. { "getStats", w_getStats },
  1463. { "draw", w_draw },
  1464. { "print", w_print },
  1465. { "printf", w_printf },
  1466. { "isCreated", w_isCreated },
  1467. { "isActive", w_isActive },
  1468. { "getWidth", w_getWidth },
  1469. { "getHeight", w_getHeight },
  1470. { "getDimensions", w_getDimensions },
  1471. { "setScissor", w_setScissor },
  1472. { "getScissor", w_getScissor },
  1473. { "stencil", w_stencil },
  1474. { "setStencilTest", w_setStencilTest },
  1475. { "getStencilTest", w_getStencilTest },
  1476. { "point", w_point },
  1477. { "line", w_line },
  1478. { "rectangle", w_rectangle },
  1479. { "circle", w_circle },
  1480. { "ellipse", w_ellipse },
  1481. { "arc", w_arc },
  1482. { "polygon", w_polygon },
  1483. { "push", w_push },
  1484. { "pop", w_pop },
  1485. { "rotate", w_rotate },
  1486. { "scale", w_scale },
  1487. { "translate", w_translate },
  1488. { "shear", w_shear },
  1489. { "origin", w_origin },
  1490. { 0, 0 }
  1491. };
  1492. // Types for this module.
  1493. static const lua_CFunction types[] =
  1494. {
  1495. luaopen_font,
  1496. luaopen_image,
  1497. luaopen_quad,
  1498. luaopen_spritebatch,
  1499. luaopen_particlesystem,
  1500. luaopen_canvas,
  1501. luaopen_shader,
  1502. luaopen_mesh,
  1503. luaopen_text,
  1504. 0
  1505. };
  1506. extern "C" int luaopen_love_graphics(lua_State *L)
  1507. {
  1508. Graphics *instance = instance();
  1509. if (instance == nullptr)
  1510. {
  1511. luax_catchexcept(L, [&](){ instance = new Graphics(); });
  1512. }
  1513. else
  1514. instance->retain();
  1515. WrappedModule w;
  1516. w.module = instance;
  1517. w.name = "graphics";
  1518. w.type = MODULE_GRAPHICS_ID;
  1519. w.functions = functions;
  1520. w.types = types;
  1521. int n = luax_register_module(L, w);
  1522. if (luaL_loadbuffer(L, (const char *)graphics_lua, sizeof(graphics_lua), "graphics.lua") == 0)
  1523. lua_call(L, 0, 0);
  1524. return n;
  1525. }
  1526. } // opengl
  1527. } // graphics
  1528. } // love