Graphics.cpp 26 KB

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