wrap_Graphics.cpp 37 KB

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