Graphics.cpp 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130
  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. // Window 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( Graphics::BlendMode 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 ( Graphics::ColorMode 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. Graphics::BlendMode 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. Graphics::ColorMode 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(Graphics::LineStyle 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, Graphics::LineStyle 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. Graphics::LineStyle 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( Graphics::PointStyle 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, Graphics::PointStyle 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. Graphics::PointStyle 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, AlignMode 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(DrawMode mode, 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(mode)
  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(DrawMode mode, float x, float y, float w, float h )
  732. {
  733. glDisable(GL_TEXTURE_2D);
  734. glPushMatrix();
  735. switch(mode)
  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(DrawMode mode, 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(mode)
  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(DrawMode mode, 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(mode)
  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. DrawMode mode;
  822. const char * str = luaL_checkstring(L, 1);
  823. if(!getConstant(str, mode))
  824. return luaL_error(L, "Invalid draw mode: %s", str);
  825. // Get the type of the second argument.
  826. int luatype = lua_type(L, 2);
  827. // Perform additional type checking.
  828. switch(luatype)
  829. {
  830. case LUA_TNUMBER:
  831. if( n-1 < 6 ) return luaL_error(L, "Error: function requires at least 3 vertices.");
  832. if( ((n-1)%2) != 0 ) return luaL_error(L, "Error: number of vertices must be a multiple of two.");
  833. break;
  834. case LUA_TTABLE:
  835. if( (lua_objlen(L, 2)%2) != 0 ) return luaL_error(L, "Error: number of vertices must be a multiple of two.");
  836. break;
  837. default:
  838. return luaL_error(L, "Error: number type or table expected.");
  839. }
  840. glDisable(GL_CULL_FACE);
  841. glDisable(GL_TEXTURE_2D);
  842. glBegin((mode==DRAW_LINE) ? GL_LINE_LOOP : GL_POLYGON);
  843. switch(luatype)
  844. {
  845. case LUA_TNUMBER:
  846. for(int i = 2; i<n; i+=2)
  847. glVertex2f((GLfloat)lua_tonumber(L, i), (GLfloat)lua_tonumber(L, i+1));
  848. break;
  849. case LUA_TTABLE:
  850. lua_pushnil(L);
  851. while (true)
  852. {
  853. if(lua_next(L, 2) == 0) break;
  854. GLfloat x = (GLfloat)lua_tonumber(L, -1);
  855. lua_pop(L, 1); // pop value
  856. if(lua_next(L, 2) == 0) break;
  857. GLfloat y = (GLfloat)lua_tonumber(L, -1);
  858. lua_pop(L, 1); // pop value
  859. glVertex2f(x, y);
  860. }
  861. break;
  862. }
  863. glEnd();
  864. glEnable(GL_CULL_FACE);
  865. glEnable(GL_TEXTURE_2D);
  866. return 0;
  867. }
  868. love::image::ImageData * Graphics::newScreenshot(love::image::Image * image)
  869. {
  870. int w = getWidth();
  871. int h = getHeight();
  872. int row = 4*w;
  873. int size = row*h;
  874. GLubyte * pixels = new GLubyte[size];
  875. GLubyte * screenshot = new GLubyte[size];
  876. glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  877. // OpenGL sucks and reads pixels from the lower-left. Let's fix that.
  878. GLubyte *src = pixels - row, *dst = screenshot + size;
  879. for (int i = 0; i < h; ++i) {
  880. memcpy(dst-=row, src+=row, row);
  881. }
  882. love::image::ImageData * img = image->newImageData(w, h, (void*)screenshot);
  883. delete [] pixels;
  884. delete [] screenshot;
  885. return img;
  886. }
  887. void Graphics::push()
  888. {
  889. glPushMatrix();
  890. }
  891. void Graphics::pop()
  892. {
  893. glPopMatrix();
  894. }
  895. void Graphics::rotate(float r)
  896. {
  897. glRotatef(r, 0, 0, 1);
  898. }
  899. void Graphics::scale(float x, float y)
  900. {
  901. glScalef(x, y, 1);
  902. }
  903. void Graphics::translate(float x, float y)
  904. {
  905. glTranslatef(x, y, 0);
  906. }
  907. void Graphics::drawTest(Image * image, float x, float y, float a, float sx, float sy, float ox, float oy)
  908. {
  909. image->bind();
  910. // Buffer for transforming the image.
  911. vertex buf[4];
  912. Matrix t;
  913. t.translate(x, y);
  914. t.rotate(a);
  915. t.scale(sx, sy);
  916. t.translate(ox, oy);
  917. t.transform(buf, image->getVertices(), 4);
  918. const vertex * vertices = image->getVertices();
  919. glEnableClientState(GL_VERTEX_ARRAY);
  920. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  921. glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)&buf[0].x);
  922. glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)&vertices[0].s);
  923. glDrawArrays(GL_QUADS, 0, 4);
  924. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  925. glDisableClientState(GL_VERTEX_ARRAY);
  926. }
  927. } // opengl
  928. } // graphics
  929. } // love