Graphics.cpp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. /**
  2. * Copyright (c) 2006-2009 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 "Graphics.h"
  21. // LOVE
  22. #include <common/config.h>
  23. namespace love
  24. {
  25. namespace graphics
  26. {
  27. namespace opengl
  28. {
  29. Graphics::Graphics()
  30. : currentFont(0)
  31. {
  32. // Indicates that there is no screen
  33. // created yet.
  34. currentMode.width = 0;
  35. currentMode.height = 0;
  36. // Windows should be centered.
  37. SDL_putenv("SDL_VIDEO_CENTERED=center");
  38. if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
  39. throw Exception(SDL_GetError());
  40. }
  41. Graphics::~Graphics()
  42. {
  43. if(currentFont != 0)
  44. currentFont->release();
  45. SDL_QuitSubSystem(SDL_INIT_VIDEO);
  46. }
  47. const char * Graphics::getName() const
  48. {
  49. return "love.graphics.opengl";
  50. }
  51. bool Graphics::checkMode(int width, int height, bool fullscreen)
  52. {
  53. Uint32 sdlflags = fullscreen ? (SDL_OPENGL | SDL_FULLSCREEN) : SDL_OPENGL;
  54. // Check if mode is supported
  55. int bpp = SDL_VideoModeOK(width, height, 32, sdlflags);
  56. return (bpp >= 16);
  57. }
  58. DisplayState Graphics::saveState()
  59. {
  60. DisplayState s;
  61. //create a table in which to store the color data in float format, before converting it
  62. float color[4];
  63. //get the color
  64. glGetFloatv(GL_CURRENT_COLOR, color);
  65. s.color.r = (GLubyte)(color[0]*255.0f);
  66. s.color.g = (GLubyte)(color[1]*255.0f);
  67. s.color.b = (GLubyte)(color[2]*255.0f);
  68. s.color.a = (GLubyte)(color[3]*255.0f);
  69. //get the background color
  70. glGetFloatv(GL_COLOR_CLEAR_VALUE, color);
  71. s.backgroundColor.r = (GLubyte)(color[0]*255.0f);
  72. s.backgroundColor.g = (GLubyte)(color[1]*255.0f);
  73. s.backgroundColor.b = (GLubyte)(color[2]*255.0f);
  74. s.backgroundColor.a = (GLubyte)(color[3]*255.0f);
  75. //store modes here
  76. int mode;
  77. //get blend mode
  78. glGetIntegerv(GL_BLEND_DST, &mode);
  79. //following syntax seems better than if-else every time
  80. s.blendMode = (mode == GL_ONE) ? Graphics::BLEND_ADDITIVE : Graphics::BLEND_ALPHA;
  81. //get color mode
  82. glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &mode);
  83. s.colorMode = (mode == GL_MODULATE) ? Graphics::COLOR_MODULATE : Graphics::COLOR_REPLACE;
  84. //get the line width (directly to corresponding variable)
  85. glGetFloatv(GL_LINE_WIDTH, &s.lineWidth);
  86. //get line style
  87. s.lineStyle = (glIsEnabled(GL_LINE_SMOOTH) == GL_TRUE) ? Graphics::LINE_SMOOTH : Graphics::LINE_ROUGH;
  88. //get line stipple
  89. s.stipple = (glIsEnabled(GL_LINE_SMOOTH) == GL_TRUE) ? true : false;
  90. if (s.stipple)
  91. {
  92. //get the stipple repeat
  93. glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &s.stippleRepeat);
  94. //get the stipple pattern
  95. glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &s.stipplePattern);
  96. }
  97. //get the point size
  98. glGetFloatv(GL_POINT_SIZE, &s.pointSize);
  99. //get point style
  100. s.pointStyle = (glIsEnabled(GL_POINT_SMOOTH) == GL_TRUE) ? Graphics::POINT_SMOOTH : Graphics::POINT_ROUGH;
  101. //get scissor status
  102. s.scissor = (glIsEnabled(GL_SCISSOR_TEST) == GL_TRUE) ? true : false;
  103. //do we have scissor, if so, store the box
  104. if (s.scissor)
  105. glGetIntegerv(GL_SCISSOR_BOX, s.scissorBox);
  106. return s;
  107. }
  108. void Graphics::restoreState(const DisplayState & s)
  109. {
  110. setColor(s.color);
  111. setBackgroundColor(s.backgroundColor);
  112. setBlendMode(s.blendMode);
  113. setColorMode(s.colorMode);
  114. setLine(s.lineWidth, s.lineStyle);
  115. if (s.stipple)
  116. setLineStipple(s.stipplePattern, s.stippleRepeat);
  117. else
  118. setLineStipple();
  119. setPoint(s.pointSize, s.pointStyle);
  120. if (s.scissor)
  121. setScissor(s.scissorBox[0], s.scissorBox[1], s.scissorBox[2], s.scissorBox[3]);
  122. else
  123. setScissor();
  124. }
  125. bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int fsaa)
  126. {
  127. // This operation destroys the OpenGL context, so
  128. // we must save the state.
  129. DisplayState tempState;
  130. if (isCreated())
  131. tempState = saveState();
  132. // Unlad all volatile objects. These must be reloaded after
  133. // the display mode change.
  134. Volatile::unloadAll();
  135. // Get caption.
  136. // Special case for fullscreen -> windowed. Windows XP did not
  137. // work well with "normal" display mode change in this case.
  138. // The application window does leave fullscreen, but the desktop
  139. // resolution does not revert to the correct one. Restarting the
  140. // SDL video subsystem does the trick, though.
  141. if( currentMode.fullscreen && !fullscreen )
  142. {
  143. // Restart.
  144. SDL_QuitSubSystem(SDL_INIT_VIDEO);
  145. if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
  146. {
  147. std::cout << "Could not init SDL_VIDEO: " << SDL_GetError() << std::endl;
  148. return false;
  149. }
  150. }
  151. // Set caption.
  152. // Set GL attributes
  153. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 0);
  154. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 0);
  155. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 0);
  156. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  157. SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, (vsync ? 1 : 0));
  158. // FSAA
  159. if(fsaa > 0)
  160. {
  161. SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 ) ;
  162. SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, fsaa ) ;
  163. }
  164. // Fullscreen?
  165. Uint32 sdlflags = fullscreen ? (SDL_OPENGL | SDL_FULLSCREEN) : SDL_OPENGL;
  166. // Have SDL set the video mode.
  167. if(SDL_SetVideoMode(width, height, 32, sdlflags ) == 0)
  168. {
  169. std::cerr << "Could not set video mode: " << SDL_GetError() << std::endl;
  170. return false;
  171. }
  172. // Check if FSAA failed or not
  173. if(fsaa > 0)
  174. {
  175. GLint buffers;
  176. GLint samples;
  177. glGetIntegerv( GL_SAMPLE_BUFFERS_ARB, & buffers ) ;
  178. glGetIntegerv( GL_SAMPLES_ARB, & samples ) ;
  179. // Don't fail because of this, but issue a warning.
  180. if ( ! buffers || (samples != fsaa))
  181. std::cerr << "Warning, quality setting failed! (Result: buffers: " << buffers << ", samples: " << samples << std::endl;
  182. }
  183. // Okay, setup OpenGL.
  184. // Enable blending
  185. glEnable(GL_BLEND);
  186. // "Normal" blending
  187. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  188. // Enable line/point smoothing.
  189. glEnable(GL_LINE_SMOOTH);
  190. glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  191. glEnable(GL_POINT_SMOOTH);
  192. glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
  193. // TODO:
  194. //reset();
  195. // Enable textures
  196. glEnable(GL_TEXTURE_2D);
  197. // Set the viewport to top-left corner
  198. glViewport(0,0, width, height);
  199. // Reset the projection matrix
  200. glMatrixMode(GL_PROJECTION);
  201. glLoadIdentity();
  202. // Set up orthographic view (no depth)
  203. glOrtho(0.0, width, height,0.0, -1.0, 1.0);
  204. // Reset modelview matrix
  205. glMatrixMode(GL_MODELVIEW);
  206. glLoadIdentity();
  207. // Set the new display mode as the current display mode.
  208. currentMode.width = width;
  209. currentMode.height = height;
  210. currentMode.colorDepth = 32;
  211. currentMode.fsaa = fsaa;
  212. currentMode.fullscreen = fullscreen;
  213. currentMode.vsync = vsync;
  214. // Reload all volatile objects.
  215. if(!Volatile::loadAll())
  216. std::cerr << "Could not reload all volatile objects." << std::endl;
  217. // Restore the display state.
  218. restoreState(tempState);
  219. return true;
  220. }
  221. bool Graphics::toggleFullscreen()
  222. {
  223. // Try to do the change.
  224. if(!setMode(currentMode.width,
  225. currentMode.height,
  226. !currentMode.fullscreen,
  227. currentMode.vsync,
  228. currentMode.fsaa))
  229. return false;
  230. currentMode.fullscreen = !currentMode.fullscreen;
  231. return true;
  232. }
  233. void Graphics::reset()
  234. {
  235. DisplayState s;
  236. restoreState(s);
  237. }
  238. void Graphics::clear()
  239. {
  240. glClear(GL_COLOR_BUFFER_BIT);
  241. glLoadIdentity();
  242. }
  243. void Graphics::present()
  244. {
  245. SDL_GL_SwapBuffers();
  246. }
  247. void Graphics::setCaption(const char * caption)
  248. {
  249. SDL_WM_SetCaption(caption, 0);
  250. }
  251. int Graphics::getCaption(lua_State * L)
  252. {
  253. char * title = 0;
  254. SDL_WM_GetCaption(&title, 0);
  255. lua_pushstring(L, title);
  256. return 1;
  257. }
  258. int Graphics::getWidth()
  259. {
  260. return currentMode.width;
  261. }
  262. int Graphics::getHeight()
  263. {
  264. return currentMode.height;
  265. }
  266. bool Graphics::isCreated()
  267. {
  268. return (currentMode.width > 0) || (currentMode.height > 0);
  269. }
  270. int Graphics::getModes(lua_State * L)
  271. {
  272. SDL_Rect ** modes = SDL_ListModes(0, SDL_OPENGL | SDL_FULLSCREEN);
  273. if(modes == (SDL_Rect **)0 || modes == (SDL_Rect **)-1)
  274. return 0;
  275. int index = 1;
  276. lua_newtable(L);
  277. for(int i=0;modes[i];++i)
  278. {
  279. lua_pushinteger(L, index);
  280. lua_newtable(L);
  281. // Inner table attribs.
  282. lua_pushstring(L, "width");
  283. lua_pushinteger(L, modes[i]->w);
  284. lua_settable(L, -3);
  285. lua_pushstring(L, "height");
  286. lua_pushinteger(L, modes[i]->h);
  287. lua_settable(L, -3);
  288. // Inner table attribs end.
  289. lua_settable(L, -3);
  290. index++;
  291. }
  292. return 1;
  293. }
  294. void Graphics::setScissor(int x, int y, int width, int height)
  295. {
  296. glEnable(GL_SCISSOR_TEST);
  297. glScissor(x, getHeight() - (y + height), width, height); // Compensates for the fact that our y-coordinate is reverse of OpenGLs.
  298. }
  299. void Graphics::setScissor()
  300. {
  301. glDisable(GL_SCISSOR_TEST);
  302. }
  303. int Graphics::getScissor(lua_State * L)
  304. {
  305. if(glIsEnabled(GL_SCISSOR_TEST) == GL_FALSE)
  306. return 0;
  307. GLint scissor[4];
  308. glGetIntegerv(GL_SCISSOR_BOX, scissor);
  309. lua_pushnumber(L, scissor[0]);
  310. lua_pushnumber(L, getHeight() - (scissor[1] + scissor[3])); // Compensates for the fact that our y-coordinate is reverse of OpenGLs.
  311. lua_pushnumber(L, scissor[2]);
  312. lua_pushnumber(L, scissor[3]);
  313. return 4;
  314. }
  315. Image * Graphics::newImage(love::image::ImageData * data)
  316. {
  317. // Create the image.
  318. Image * image = new Image(data);
  319. bool success;
  320. try {
  321. success = image->load();
  322. } catch (love::Exception & e) {
  323. image->release();
  324. throw love::Exception(e.what());
  325. }
  326. if (!success) {
  327. image->release();
  328. return 0;
  329. }
  330. return image;
  331. }
  332. Quad * Graphics::newQuad(int x, int y, int w, int h, int sw, int sh)
  333. {
  334. Quad::Viewport v;
  335. v.x = x;
  336. v.y = y;
  337. v.w = w;
  338. v.h = h;
  339. return new Quad(v, sw, sh);
  340. }
  341. Font * Graphics::newFont(Data * data, int size)
  342. {
  343. Font * font = new TrueTypeFont(data, size);
  344. // Load it and check for errors.
  345. if(!font->load())
  346. {
  347. delete font;
  348. return 0;
  349. }
  350. return font;
  351. }
  352. Font * Graphics::newImageFont(Image * image, const char * glyphs, float spacing)
  353. {
  354. Font * font = new ImageFont(image, std::string(glyphs));
  355. // Load it and check for errors.
  356. if(!font->load())
  357. {
  358. delete font;
  359. return 0;
  360. }
  361. return font;
  362. }
  363. SpriteBatch * Graphics::newSpriteBatch(Image * image, int size, int usage)
  364. {
  365. return new SpriteBatch(image, size, usage);
  366. }
  367. ParticleSystem * Graphics::newParticleSystem(Image * image, int size)
  368. {
  369. return new ParticleSystem(image, size);
  370. }
  371. void Graphics::setColor(Color c)
  372. {
  373. glColor4ubv(&c.r);
  374. }
  375. Color Graphics::getColor()
  376. {
  377. float c[4];
  378. glGetFloatv(GL_CURRENT_COLOR, c);
  379. Color t;
  380. t.r = (unsigned char)(255.0f*c[0]);
  381. t.g = (unsigned char)(255.0f*c[1]);
  382. t.b = (unsigned char)(255.0f*c[2]);
  383. t.a = (unsigned char)(255.0f*c[3]);
  384. return t;
  385. }
  386. void Graphics::setBackgroundColor(Color c)
  387. {
  388. glClearColor((float)c.r/255.0f, (float)c.g/255.0f, (float)c.b/255.0f, 1.0f);
  389. }
  390. Color Graphics::getBackgroundColor()
  391. {
  392. float c[4];
  393. glGetFloatv(GL_COLOR_CLEAR_VALUE, c);
  394. Color t;
  395. t.r = (unsigned char)(255.0f*c[0]);
  396. t.g = (unsigned char)(255.0f*c[1]);
  397. t.b = (unsigned char)(255.0f*c[2]);
  398. t.a = (unsigned char)(255.0f*c[3]);
  399. return t;
  400. }
  401. void Graphics::setFont( Font * font )
  402. {
  403. if(currentFont != 0)
  404. currentFont->release();
  405. currentFont = font;
  406. if(font != 0)
  407. currentFont->retain();
  408. }
  409. void Graphics::setFont( Data * data, int size )
  410. {
  411. if(currentFont != 0)
  412. currentFont->release();
  413. currentFont = new TrueTypeFont(data, size);
  414. currentFont->load();
  415. }
  416. Font * Graphics::getFont()
  417. {
  418. return currentFont;
  419. }
  420. void Graphics::setBlendMode( int mode )
  421. {
  422. if(mode == BLEND_ADDITIVE)
  423. glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  424. else // mode == BLEND_ALPHA
  425. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  426. }
  427. void Graphics::setColorMode ( int mode )
  428. {
  429. if(mode == COLOR_MODULATE)
  430. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  431. else // mode = COLOR_REPLACE
  432. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  433. }
  434. int Graphics::getBlendMode()
  435. {
  436. GLint dst, src;
  437. glGetIntegerv(GL_BLEND_DST, &dst);
  438. glGetIntegerv(GL_BLEND_SRC, &src);
  439. if(src == GL_SRC_ALPHA && dst == GL_ONE)
  440. return BLEND_ADDITIVE;
  441. else // src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA
  442. return BLEND_ALPHA;
  443. }
  444. int Graphics::getColorMode()
  445. {
  446. GLint mode;
  447. glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &mode);
  448. if(mode == GL_MODULATE)
  449. return COLOR_MODULATE;
  450. else // // mode == GL_REPLACE
  451. return COLOR_REPLACE;
  452. }
  453. void Graphics::setLineWidth( float width )
  454. {
  455. glLineWidth(width);
  456. }
  457. void Graphics::setLineStyle( int style )
  458. {
  459. if(style == LINE_ROUGH)
  460. glDisable (GL_LINE_SMOOTH);
  461. else // type == LINE_SMOOTH
  462. {
  463. glEnable (GL_LINE_SMOOTH);
  464. glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
  465. }
  466. }
  467. void Graphics::setLine( float width, int style )
  468. {
  469. glLineWidth(width);
  470. if(style == 0)
  471. return;
  472. if(style == LINE_ROUGH)
  473. glDisable (GL_LINE_SMOOTH);
  474. else // type == LINE_SMOOTH
  475. {
  476. glEnable (GL_LINE_SMOOTH);
  477. glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
  478. }
  479. }
  480. void Graphics::setLineStipple()
  481. {
  482. glDisable(GL_LINE_STIPPLE);
  483. }
  484. void Graphics::setLineStipple(unsigned short pattern, int repeat)
  485. {
  486. glEnable(GL_LINE_STIPPLE);
  487. glLineStipple((GLint)repeat, (GLshort)pattern);
  488. }
  489. float Graphics::getLineWidth()
  490. {
  491. float w;
  492. glGetFloatv(GL_LINE_WIDTH, &w);
  493. return w;
  494. }
  495. int Graphics::getLineStyle()
  496. {
  497. if(glIsEnabled(GL_LINE_SMOOTH) == GL_TRUE)
  498. return LINE_SMOOTH;
  499. else
  500. return LINE_ROUGH;
  501. }
  502. int Graphics::getLineStipple(lua_State * L)
  503. {
  504. if(glIsEnabled(GL_LINE_STIPPLE) == GL_FALSE)
  505. return 0;
  506. GLint factor, pattern;
  507. glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &pattern);
  508. glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &factor);
  509. lua_pushinteger(L, pattern);
  510. lua_pushinteger(L, factor);
  511. return 2;
  512. }
  513. void Graphics::setPointSize( float size )
  514. {
  515. glPointSize((GLfloat)size);
  516. }
  517. void Graphics::setPointStyle( int style )
  518. {
  519. if( style == POINT_SMOOTH )
  520. glEnable(GL_POINT_SMOOTH);
  521. else // love::POINT_ROUGH
  522. glDisable(GL_POINT_SMOOTH);
  523. }
  524. void Graphics::setPoint( float size, int style )
  525. {
  526. if( style == POINT_SMOOTH )
  527. glEnable(GL_POINT_SMOOTH);
  528. else // POINT_ROUGH
  529. glDisable(GL_POINT_SMOOTH);
  530. glPointSize((GLfloat)size);
  531. }
  532. float Graphics::getPointSize()
  533. {
  534. GLfloat size;
  535. glGetFloatv(GL_POINT_SIZE, &size);
  536. return (float)size;
  537. }
  538. int Graphics::getPointStyle()
  539. {
  540. if(glIsEnabled(GL_POINT_SMOOTH) == GL_TRUE)
  541. return POINT_SMOOTH;
  542. else
  543. return POINT_ROUGH;
  544. }
  545. int Graphics::getMaxPointSize()
  546. {
  547. GLint max;
  548. glGetIntegerv(GL_POINT_SIZE_MAX, &max);
  549. return (int)max;
  550. }
  551. void Graphics::print( const char * str, float x, float y )
  552. {
  553. if(currentFont != 0)
  554. {
  555. std::string text(str);
  556. if(text.find("\n") == std::string::npos)
  557. currentFont->print(text, x, y);
  558. else
  559. {
  560. int lines = 0;
  561. text = "";
  562. for(unsigned int i = 0; i < strlen(str); i++)
  563. {
  564. if(str[i] == '\n')
  565. {
  566. currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()));
  567. text = "";
  568. lines++;
  569. }
  570. else
  571. text += str[i];
  572. }
  573. if(text != "") // Print the last text (if applicable).
  574. currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()));
  575. }
  576. }
  577. }
  578. void Graphics::print( const char * str, float x, float y , float angle)
  579. {
  580. if(currentFont != 0)
  581. {
  582. std::string text(str);
  583. currentFont->print(text, x, y, angle, 1, 1);
  584. }
  585. }
  586. void Graphics::print( const char * str, float x, float y , float angle, float s)
  587. {
  588. if(currentFont != 0)
  589. {
  590. std::string text(str);
  591. currentFont->print(text, x, y, angle, s, s);
  592. }
  593. }
  594. void Graphics::print( const char * str, float x, float y , float angle, float sx, float sy)
  595. {
  596. if(currentFont != 0)
  597. {
  598. std::string text(str);
  599. currentFont->print(text, x, y, angle, sx, sy);
  600. }
  601. }
  602. void Graphics::printf( const char * str, float x, float y, float wrap, int align)
  603. {
  604. if(currentFont != 0)
  605. {
  606. std::string text = "";
  607. float width = 0;
  608. float lines = 0;
  609. for(unsigned int i = 0; i < strlen(str); i++)
  610. {
  611. if(str[i] == '\n')
  612. {
  613. switch(align)
  614. {
  615. case ALIGN_LEFT:
  616. currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) );
  617. break;
  618. case ALIGN_RIGHT:
  619. currentFont->print(text, (x + (wrap - currentFont->getWidth(text))), y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) );
  620. break;
  621. case ALIGN_CENTER:
  622. currentFont->print(text, ceil(x + ((wrap - currentFont->getWidth(text)) / 2)), ceil(y + (lines * currentFont->getHeight() * currentFont->getLineHeight())) );
  623. break;
  624. default: // A copy of the left align code. Kept separate in case an error message is wanted.
  625. currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) );
  626. break;
  627. }
  628. text = "";
  629. width = 0;
  630. lines++;
  631. }
  632. else
  633. {
  634. width += currentFont->getWidth(str[i]);
  635. if(width > wrap && text.find(" ") != std::string::npos) // If there doesn't exist a space, then ignore the wrap limit.
  636. {
  637. // Seek back to the nearest space and print that.
  638. unsigned int space = (unsigned int)text.find_last_of(' ');
  639. std::string temp = text.substr(0, space);
  640. switch(align)
  641. {
  642. case ALIGN_LEFT:
  643. currentFont->print(temp, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) );
  644. break;
  645. case ALIGN_RIGHT:
  646. currentFont->print(temp, (x + (wrap - currentFont->getWidth(temp))), y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) );
  647. break;
  648. case ALIGN_CENTER:
  649. currentFont->print(temp, ceil(x + ((wrap - currentFont->getWidth(temp)) / 2)), ceil(y + (lines * currentFont->getHeight() * currentFont->getLineHeight())) );
  650. break;
  651. default: // A copy of the left align code. Kept separate in case an error message is wanted.
  652. currentFont->print(temp, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) );
  653. break;
  654. }
  655. text = text.substr(space + 1);
  656. width = currentFont->getWidth(text);
  657. lines++;
  658. }
  659. text += str[i];
  660. }
  661. } // for
  662. if(text != "") // Print the last text (if applicable).
  663. {
  664. switch(align)
  665. {
  666. case ALIGN_LEFT:
  667. currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) );
  668. break;
  669. case ALIGN_RIGHT:
  670. currentFont->print(text, (x + (wrap - currentFont->getWidth(text))), y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) );
  671. break;
  672. case ALIGN_CENTER:
  673. currentFont->print(text, ceil(x + ((wrap - currentFont->getWidth(text)) / 2)), ceil(y + (lines * currentFont->getHeight() * currentFont->getLineHeight())) );
  674. break;
  675. default: // A copy of the left align code. Kept separate in case an error message is wanted.
  676. currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()));
  677. break;
  678. }
  679. }
  680. }
  681. }
  682. /**
  683. * Primitives
  684. **/
  685. void Graphics::point( float x, float y )
  686. {
  687. glDisable(GL_TEXTURE_2D);
  688. glBegin(GL_POINTS);
  689. glVertex2f(x, y);
  690. glEnd();
  691. glEnable(GL_TEXTURE_2D);
  692. }
  693. void Graphics::line( float x1, float y1, float x2, float y2 )
  694. {
  695. glDisable(GL_TEXTURE_2D);
  696. glPushMatrix();
  697. glBegin(GL_LINES);
  698. glVertex2f(x1, y1);
  699. glVertex2f(x2, y2);
  700. glEnd();
  701. glPopMatrix();
  702. glEnable(GL_TEXTURE_2D);
  703. }
  704. void Graphics::triangle( int type, float x1, float y1, float x2, float y2, float x3, float y3 )
  705. {
  706. glDisable(GL_CULL_FACE);
  707. glDisable(GL_TEXTURE_2D);
  708. glPushMatrix();
  709. switch(type)
  710. {
  711. case DRAW_LINE:
  712. glBegin(GL_LINE_LOOP);
  713. glVertex2f(x1, y1);
  714. glVertex2f(x2, y2);
  715. glVertex2f(x3, y3);
  716. glEnd();
  717. break;
  718. default:
  719. case DRAW_FILL:
  720. glBegin(GL_TRIANGLES);
  721. glVertex2f(x1, y1);
  722. glVertex2f(x2, y2);
  723. glVertex2f(x3, y3);
  724. glEnd();
  725. break;
  726. }
  727. glPopMatrix();
  728. glEnable(GL_TEXTURE_2D);
  729. glEnable(GL_CULL_FACE);
  730. }
  731. void Graphics::rectangle( int type, float x, float y, float w, float h )
  732. {
  733. glDisable(GL_TEXTURE_2D);
  734. glPushMatrix();
  735. switch(type)
  736. {
  737. case DRAW_LINE:
  738. glBegin(GL_LINE_LOOP);
  739. glVertex2f(x, y);
  740. glVertex2f(x, y+h);
  741. glVertex2f(x+w, y+h);
  742. glVertex2f(x+w, y);
  743. glEnd();
  744. break;
  745. default:
  746. case DRAW_FILL:
  747. glBegin(GL_QUADS);
  748. glVertex2f(x, y);
  749. glVertex2f(x, y+h);
  750. glVertex2f(x+w, y+h);
  751. glVertex2f(x+w, y);
  752. glEnd();
  753. break;
  754. }
  755. glPopMatrix();
  756. glEnable(GL_TEXTURE_2D);
  757. }
  758. void Graphics::quad( int type, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4 )
  759. {
  760. glDisable(GL_CULL_FACE);
  761. glDisable(GL_TEXTURE_2D);
  762. glPushMatrix();
  763. switch(type)
  764. {
  765. case DRAW_LINE:
  766. glBegin(GL_LINE_LOOP);
  767. glVertex2f(x1, y1);
  768. glVertex2f(x2, y2);
  769. glVertex2f(x3, y3);
  770. glVertex2f(x4, y4);
  771. glEnd();
  772. break;
  773. default:
  774. case DRAW_FILL:
  775. glBegin(GL_QUADS);
  776. glVertex2f(x1, y1);
  777. glVertex2f(x2, y2);
  778. glVertex2f(x3, y3);
  779. glVertex2f(x4, y4);
  780. glEnd();
  781. break;
  782. }
  783. glPopMatrix();
  784. glEnable(GL_TEXTURE_2D);
  785. glEnable(GL_CULL_FACE);
  786. }
  787. void Graphics::circle( int type, float x, float y, float radius, int points )
  788. {
  789. float two_pi = 3.14159265f * 2;
  790. if(points <= 0) points = 1;
  791. float angle_shift = (two_pi / points);
  792. glDisable(GL_TEXTURE_2D);
  793. glPushMatrix();
  794. glTranslatef(x, y, 0.0f);
  795. switch(type)
  796. {
  797. case DRAW_LINE:
  798. glBegin(GL_LINE_LOOP);
  799. for(float i = 0; i < two_pi; i+= angle_shift)
  800. glVertex2f(radius * sin(i),radius * cos(i));
  801. glEnd();
  802. break;
  803. default:
  804. case DRAW_FILL:
  805. glBegin(GL_TRIANGLE_FAN);
  806. for(float i = 0; i < two_pi; i+= angle_shift)
  807. glVertex2f(radius * sin(i),radius * cos(i));
  808. glEnd();
  809. break;
  810. }
  811. glPopMatrix();
  812. glEnable(GL_TEXTURE_2D);
  813. }
  814. int Graphics::polygon( lua_State * L )
  815. {
  816. // Get number of params.
  817. int n = lua_gettop(L);
  818. // Need at least two params.
  819. if( n < 2 )
  820. return luaL_error(L, "Error: function needs at least two parameters.");
  821. // The first one MUST be a number.
  822. if( !lua_isnumber(L, 1) )
  823. return luaL_error(L, "Error: first parameter must be a number.");
  824. // Get rendering mode. (line/fill)
  825. int mode = (int)lua_tonumber(L, 1);
  826. // Get the type of the second argument.
  827. int luatype = lua_type(L, 2);
  828. // Perform additional type checking.
  829. switch(luatype)
  830. {
  831. case LUA_TNUMBER:
  832. if( n-1 < 6 ) return luaL_error(L, "Error: function requires at least 3 vertices.");
  833. if( ((n-1)%2) != 0 ) return luaL_error(L, "Error: number of vertices must be a multiple of two.");
  834. break;
  835. case LUA_TTABLE:
  836. if( (lua_objlen(L, 2)%2) != 0 ) return luaL_error(L, "Error: number of vertices must be a multiple of two.");
  837. break;
  838. default:
  839. return luaL_error(L, "Error: number type or table expected.");
  840. }
  841. glDisable(GL_CULL_FACE);
  842. glDisable(GL_TEXTURE_2D);
  843. glBegin((mode==DRAW_LINE) ? GL_LINE_LOOP : GL_POLYGON);
  844. switch(luatype)
  845. {
  846. case LUA_TNUMBER:
  847. for(int i = 2; i<n; i+=2)
  848. glVertex2f((GLfloat)lua_tonumber(L, i), (GLfloat)lua_tonumber(L, i+1));
  849. break;
  850. case LUA_TTABLE:
  851. lua_pushnil(L);
  852. while (true)
  853. {
  854. if(lua_next(L, 2) == 0) break;
  855. GLfloat x = (GLfloat)lua_tonumber(L, -1);
  856. lua_pop(L, 1); // pop value
  857. if(lua_next(L, 2) == 0) break;
  858. GLfloat y = (GLfloat)lua_tonumber(L, -1);
  859. lua_pop(L, 1); // pop value
  860. glVertex2f(x, y);
  861. }
  862. break;
  863. }
  864. glEnd();
  865. glEnable(GL_CULL_FACE);
  866. glEnable(GL_TEXTURE_2D);
  867. return 0;
  868. }
  869. int Graphics::polygong( lua_State * L )
  870. {
  871. // Get number of params.
  872. int n = lua_gettop(L);
  873. // Need at least two params.
  874. if( n < 2 )
  875. return luaL_error(L, "Error: function needs at least two parameters.");
  876. // The first one MUST be a number.
  877. if( !lua_isnumber(L, 1) )
  878. return luaL_error(L, "Error: first parameter must be a number.");
  879. int vertc = 0, colorc = 0;
  880. if( n == 3 )
  881. {
  882. if((!lua_istable(L, 2) || !lua_istable(L, 3)))
  883. return luaL_error(L, "Error: two tables expected.");
  884. vertc = (int)lua_objlen(L, 2);
  885. colorc = (int)lua_objlen(L, 3);
  886. if( (vertc <= 0 || colorc <= 0))
  887. return luaL_error(L, "Error: empty table.");
  888. }
  889. // Get rendering mode. (line/fill)
  890. int mode = (int)lua_tonumber(L, 1);
  891. GLenum glmode = (mode==DRAW_LINE) ? GL_LINE_LOOP : GL_POLYGON;
  892. // Get the type of the second argument.
  893. int luatype = lua_type(L, 2);
  894. if(!(luatype == LUA_TTABLE || luatype == LUA_TNUMBER))
  895. return luaL_error(L, "Error: expected number or table values.");
  896. glPushAttrib(GL_CURRENT_BIT);
  897. glDisable(GL_CULL_FACE);
  898. glDisable(GL_TEXTURE_2D);
  899. switch(luatype)
  900. {
  901. case LUA_TTABLE:
  902. if( n == 2 )
  903. {
  904. glBegin(glmode);
  905. lua_pushnil(L);
  906. while(true)
  907. {
  908. if(lua_next(L, 2) == 0) break;
  909. GLfloat x = (GLfloat)lua_tonumber(L, -1);
  910. lua_pop(L, 1);
  911. if(lua_next(L, 2) == 0) break;
  912. GLfloat y = (GLfloat)lua_tonumber(L, -1);
  913. lua_pop(L, 1);
  914. if(lua_next(L, 2) == 0) break;
  915. GLubyte r = (GLubyte)lua_tonumber(L, -1);
  916. lua_pop(L, 1);
  917. if(lua_next(L, 2) == 0) break;
  918. GLubyte g = (GLubyte)lua_tonumber(L, -1);
  919. lua_pop(L, 1);
  920. if(lua_next(L, 2) == 0) break;
  921. GLubyte b = (GLubyte)lua_tonumber(L, -1);
  922. lua_pop(L, 1);
  923. if(lua_next(L, 2) == 0) break;
  924. GLubyte a = (GLubyte)lua_tonumber(L, -1);
  925. lua_pop(L, 1);
  926. glColor4ub(r, g, b, a);
  927. glVertex2f(x, y);
  928. }
  929. glEnd();
  930. }
  931. else if(n == 3)
  932. {
  933. // Allocate memory.
  934. GLfloat * verts = new GLfloat[vertc];
  935. GLubyte * colors = new GLubyte[colorc];
  936. int verti = 0, colori = 0;
  937. // Get verts.
  938. lua_pushnil(L);
  939. while(lua_next(L, 2))
  940. {
  941. verts[verti++] = (GLfloat)lua_tonumber(L, -1);
  942. lua_pop(L, 1);
  943. }
  944. // Get colors.
  945. lua_pushnil(L);
  946. while(lua_next(L, 3))
  947. {
  948. colors[colori++] = (GLubyte)lua_tonumber(L, -1);
  949. lua_pop(L, 1);
  950. }
  951. glEnable(GL_VERTEX_ARRAY);
  952. glEnable(GL_COLOR_ARRAY);
  953. glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
  954. glVertexPointer(2, GL_FLOAT, 0, verts);
  955. glDrawArrays(glmode, 0, (GLint)(vertc/2));
  956. glDisable(GL_VERTEX_ARRAY);
  957. glDisable(GL_COLOR_ARRAY);
  958. delete [] verts;
  959. delete [] colors;
  960. }
  961. break;
  962. case LUA_TNUMBER:
  963. // Assume params to be packed like this: x, y, r, g, b, a, x, y, r, ...
  964. glBegin(glmode);
  965. for(int i = 2; i < (n-1); i+=6)
  966. {
  967. glColor4ub((GLubyte)lua_tonumber(L, i+2), (GLubyte)lua_tonumber(L, i+3), (GLubyte)lua_tonumber(L, i+4), (GLubyte)lua_tonumber(L, i+5));
  968. glVertex2f((GLfloat)lua_tonumber(L, i), (GLfloat)lua_tonumber(L, i+1));
  969. }
  970. glEnd();
  971. break;
  972. }
  973. glEnable(GL_CULL_FACE);
  974. glEnable(GL_TEXTURE_2D);
  975. glPopAttrib();
  976. return 0;
  977. }
  978. love::image::ImageData * Graphics::newScreenshot(love::image::Image * image)
  979. {
  980. int w = getWidth();
  981. int h = getHeight();
  982. int row = 4*w;
  983. int size = row*h;
  984. GLubyte * pixels = new GLubyte[size];
  985. GLubyte * screenshot = new GLubyte[size];
  986. glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  987. // OpenGL sucks and reads pixels from the lower-left. Let's fix that.
  988. GLubyte *src = pixels - row, *dst = screenshot + size;
  989. for (int i = 0; i < h; ++i) {
  990. memcpy(dst-=row, src+=row, row);
  991. }
  992. love::image::ImageData * img = image->newImageData(w, h, (void*)screenshot);
  993. delete [] pixels;
  994. delete [] screenshot;
  995. return img;
  996. }
  997. void Graphics::push()
  998. {
  999. glPushMatrix();
  1000. }
  1001. void Graphics::pop()
  1002. {
  1003. glPopMatrix();
  1004. }
  1005. void Graphics::rotate(float r)
  1006. {
  1007. glRotatef(r, 0, 0, 1);
  1008. }
  1009. void Graphics::scale(float x, float y)
  1010. {
  1011. glScalef(x, y, 1);
  1012. }
  1013. void Graphics::translate(float x, float y)
  1014. {
  1015. glTranslatef(x, y, 0);
  1016. }
  1017. void Graphics::drawTest(Image * image, float x, float y, float a, float sx, float sy, float ox, float oy)
  1018. {
  1019. image->bind();
  1020. // Buffer for transforming the image.
  1021. vertex buf[4];
  1022. Matrix t;
  1023. t.translate(x, y);
  1024. t.rotate(a);
  1025. t.scale(sx, sy);
  1026. t.translate(ox, oy);
  1027. t.transform(buf, image->getVertices(), 4);
  1028. const vertex * vertices = image->getVertices();
  1029. glEnableClientState(GL_VERTEX_ARRAY);
  1030. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  1031. glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)&buf[0].x);
  1032. glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)&vertices[0].s);
  1033. glDrawArrays(GL_QUADS, 0, 4);
  1034. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  1035. glDisableClientState(GL_VERTEX_ARRAY);
  1036. }
  1037. } // opengl
  1038. } // graphics
  1039. } // love