wrap_Graphics.cpp 36 KB

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