SimpleOpenGL3App.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  1. #ifndef NO_OPENGL3
  2. #include "SimpleOpenGL3App.h"
  3. #include "ShapeData.h"
  4. #ifdef BT_USE_EGL
  5. #include "EGLOpenGLWindow.h"
  6. #else
  7. #endif //BT_USE_EGL
  8. #ifdef B3_USE_GLFW
  9. #include "GLFWOpenGLWindow.h"
  10. #else
  11. #ifdef __APPLE__
  12. #include "MacOpenGLWindow.h"
  13. #else
  14. #ifdef _WIN32
  15. #include "Win32OpenGLWindow.h"
  16. #else
  17. //let's cross the fingers it is Linux/X11
  18. #include "X11OpenGLWindow.h"
  19. #define BT_USE_X11 // for runtime backend selection, move to build?
  20. #endif //_WIN32
  21. #endif //__APPLE__
  22. #endif //B3_USE_GLFW
  23. #include <stdio.h>
  24. #include "GLPrimitiveRenderer.h"
  25. #include "GLInstancingRenderer.h"
  26. #include "Bullet3Common/b3Vector3.h"
  27. #include "Bullet3Common/b3Logging.h"
  28. #include "fontstash.h"
  29. #include "TwFonts.h"
  30. #include "opengl_fontstashcallbacks.h"
  31. #include <assert.h>
  32. #include "GLRenderToTexture.h"
  33. #include "Bullet3Common/b3Quaternion.h"
  34. #include <string.h> //memset
  35. #ifdef _WIN32
  36. #define popen _popen
  37. #define pclose _pclose
  38. #endif // _WIN32
  39. struct SimpleInternalData
  40. {
  41. GLuint m_fontTextureId;
  42. GLuint m_largeFontTextureId;
  43. struct sth_stash* m_fontStash;
  44. struct sth_stash* m_fontStash2;
  45. RenderCallbacks* m_renderCallbacks;
  46. RenderCallbacks* m_renderCallbacks2;
  47. int m_droidRegular;
  48. int m_droidRegular2;
  49. int m_textureId;
  50. const char* m_frameDumpPngFileName;
  51. FILE* m_ffmpegFile;
  52. GLRenderToTexture* m_renderTexture;
  53. void* m_userPointer;
  54. int m_upAxis; //y=1 or z=2 is supported
  55. int m_customViewPortWidth;
  56. int m_customViewPortHeight;
  57. int m_mp4Fps;
  58. SimpleInternalData()
  59. : m_fontTextureId(0),
  60. m_largeFontTextureId(0),
  61. m_fontStash(0),
  62. m_fontStash2(0),
  63. m_renderCallbacks(0),
  64. m_renderCallbacks2(0),
  65. m_droidRegular(0),
  66. m_droidRegular2(0),
  67. m_textureId(-1),
  68. m_frameDumpPngFileName(0),
  69. m_ffmpegFile(0),
  70. m_renderTexture(0),
  71. m_userPointer(0),
  72. m_upAxis(1),
  73. m_customViewPortWidth(-1),
  74. m_customViewPortHeight(-1),
  75. m_mp4Fps(60)
  76. {
  77. }
  78. };
  79. static SimpleOpenGL3App* gApp = 0;
  80. static void SimpleResizeCallback(float widthf, float heightf)
  81. {
  82. int width = (int)widthf;
  83. int height = (int)heightf;
  84. if (gApp && gApp->m_instancingRenderer)
  85. gApp->m_instancingRenderer->resize(width, height);
  86. if (gApp && gApp->m_primRenderer)
  87. gApp->m_primRenderer->setScreenSize(width, height);
  88. }
  89. static void SimpleKeyboardCallback(int key, int state)
  90. {
  91. if (key == B3G_ESCAPE && gApp && gApp->m_window)
  92. {
  93. gApp->m_window->setRequestExit();
  94. }
  95. else
  96. {
  97. //gApp->defaultKeyboardCallback(key,state);
  98. }
  99. }
  100. void SimpleMouseButtonCallback(int button, int state, float x, float y)
  101. {
  102. gApp->defaultMouseButtonCallback(button, state, x, y);
  103. }
  104. void SimpleMouseMoveCallback(float x, float y)
  105. {
  106. gApp->defaultMouseMoveCallback(x, y);
  107. }
  108. void SimpleWheelCallback(float deltax, float deltay)
  109. {
  110. gApp->defaultWheelCallback(deltax, deltay);
  111. }
  112. static GLuint BindFont(const CTexFont* _Font)
  113. {
  114. GLuint TexID = 0;
  115. glGenTextures(1, &TexID);
  116. glBindTexture(GL_TEXTURE_2D, TexID);
  117. glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
  118. glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
  119. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  120. glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
  121. glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
  122. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  123. glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, _Font->m_TexWidth, _Font->m_TexHeight, 0, GL_RED, GL_UNSIGNED_BYTE, _Font->m_TexBytes);
  124. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  125. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  126. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  127. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  128. glBindTexture(GL_TEXTURE_2D, 0);
  129. return TexID;
  130. }
  131. //static unsigned int s_indexData[INDEX_COUNT];
  132. //static GLuint s_indexArrayObject, s_indexBuffer;
  133. //static GLuint s_vertexArrayObject,s_vertexBuffer;
  134. extern unsigned char OpenSansData[];
  135. struct MyRenderCallbacks : public RenderCallbacks
  136. {
  137. GLInstancingRenderer* m_instancingRenderer;
  138. b3AlignedObjectArray<unsigned char> m_rgbaTexture;
  139. float m_color[4];
  140. float m_worldPosition[3];
  141. float m_worldOrientation[4];
  142. int m_textureIndex;
  143. MyRenderCallbacks(GLInstancingRenderer* instancingRenderer)
  144. : m_instancingRenderer(instancingRenderer),
  145. m_textureIndex(-1)
  146. {
  147. for (int i = 0; i < 4; i++)
  148. {
  149. m_color[i] = 1;
  150. m_worldOrientation[i] = 0;
  151. }
  152. m_worldPosition[0] = 0;
  153. m_worldPosition[1] = 0;
  154. m_worldPosition[2] = 0;
  155. m_worldOrientation[0] = 0;
  156. m_worldOrientation[1] = 0;
  157. m_worldOrientation[2] = 0;
  158. m_worldOrientation[3] = 1;
  159. }
  160. virtual ~MyRenderCallbacks()
  161. {
  162. m_rgbaTexture.clear();
  163. }
  164. virtual void setWorldPosition(float pos[3])
  165. {
  166. for (int i = 0; i < 3; i++)
  167. {
  168. m_worldPosition[i] = pos[i];
  169. }
  170. }
  171. virtual void setWorldOrientation(float orn[4])
  172. {
  173. for (int i = 0; i < 4; i++)
  174. {
  175. m_worldOrientation[i] = orn[i];
  176. }
  177. }
  178. virtual void setColorRGBA(float color[4])
  179. {
  180. for (int i = 0; i < 4; i++)
  181. {
  182. m_color[i] = color[i];
  183. }
  184. }
  185. virtual void updateTexture(sth_texture* texture, sth_glyph* glyph, int textureWidth, int textureHeight)
  186. {
  187. if (glyph)
  188. {
  189. m_rgbaTexture.resize(textureWidth * textureHeight * 3);
  190. for (int i = 0; i < textureWidth * textureHeight; i++)
  191. {
  192. m_rgbaTexture[i * 3 + 0] = texture->m_texels[i];
  193. m_rgbaTexture[i * 3 + 1] = texture->m_texels[i];
  194. m_rgbaTexture[i * 3 + 2] = texture->m_texels[i];
  195. }
  196. bool flipPixelsY = false;
  197. m_instancingRenderer->updateTexture(m_textureIndex, &m_rgbaTexture[0], flipPixelsY);
  198. }
  199. else
  200. {
  201. if (textureWidth && textureHeight)
  202. {
  203. texture->m_texels = (unsigned char*)malloc(textureWidth * textureHeight);
  204. memset(texture->m_texels, 0, textureWidth * textureHeight);
  205. if (m_textureIndex < 0)
  206. {
  207. m_rgbaTexture.resize(textureWidth * textureHeight * 3);
  208. bool flipPixelsY = false;
  209. m_textureIndex = m_instancingRenderer->registerTexture(&m_rgbaTexture[0], textureWidth, textureHeight, flipPixelsY);
  210. int strideInBytes = 9 * sizeof(float);
  211. int numVertices = sizeof(cube_vertices_textured) / strideInBytes;
  212. int numIndices = sizeof(cube_indices) / sizeof(int);
  213. float halfExtentsX = 1;
  214. float halfExtentsY = 1;
  215. float halfExtentsZ = 1;
  216. float textureScaling = 4;
  217. b3AlignedObjectArray<GfxVertexFormat1> verts;
  218. verts.resize(numVertices);
  219. for (int i = 0; i < numVertices; i++)
  220. {
  221. verts[i].x = halfExtentsX * cube_vertices_textured[i * 9];
  222. verts[i].y = halfExtentsY * cube_vertices_textured[i * 9 + 1];
  223. verts[i].z = halfExtentsZ * cube_vertices_textured[i * 9 + 2];
  224. verts[i].w = cube_vertices_textured[i * 9 + 3];
  225. verts[i].nx = cube_vertices_textured[i * 9 + 4];
  226. verts[i].ny = cube_vertices_textured[i * 9 + 5];
  227. verts[i].nz = cube_vertices_textured[i * 9 + 6];
  228. verts[i].u = cube_vertices_textured[i * 9 + 7] * textureScaling;
  229. verts[i].v = cube_vertices_textured[i * 9 + 8] * textureScaling;
  230. }
  231. int shapeId = m_instancingRenderer->registerShape(&verts[0].x, numVertices, cube_indices, numIndices, B3_GL_TRIANGLES, m_textureIndex);
  232. b3Vector3 pos = b3MakeVector3(0, 0, 0);
  233. b3Quaternion orn(0, 0, 0, 1);
  234. b3Vector4 color = b3MakeVector4(1, 1, 1, 1);
  235. b3Vector3 scaling = b3MakeVector3(.1, .1, .1);
  236. //m_instancingRenderer->registerGraphicsInstance(shapeId, pos, orn, color, scaling);
  237. m_instancingRenderer->writeTransforms();
  238. }
  239. else
  240. {
  241. b3Assert(0);
  242. }
  243. }
  244. else
  245. {
  246. delete texture->m_texels;
  247. texture->m_texels = 0;
  248. //there is no m_instancingRenderer->freeTexture (yet), all textures are released at reset/deletion of the renderer
  249. }
  250. }
  251. }
  252. virtual void render(sth_texture* texture)
  253. {
  254. int index = 0;
  255. float width = 1;
  256. b3AlignedObjectArray<unsigned int> indices;
  257. indices.resize(texture->nverts);
  258. for (int i = 0; i < indices.size(); i++)
  259. {
  260. indices[i] = i;
  261. }
  262. m_instancingRenderer->drawTexturedTriangleMesh(m_worldPosition, m_worldOrientation, &texture->newverts[0].position.p[0], texture->nverts, &indices[0], indices.size(), m_color, m_textureIndex);
  263. }
  264. };
  265. static void printGLString(const char* name, GLenum s)
  266. {
  267. const char* v = (const char*)glGetString(s);
  268. printf("%s = %s\n", name, v);
  269. }
  270. bool sOpenGLVerbose = true;
  271. SimpleOpenGL3App::SimpleOpenGL3App(const char* title, int width, int height, bool allowRetina, int windowType, int renderDevice, int maxNumObjectCapacity, int maxShapeCapacityInBytes)
  272. {
  273. gApp = this;
  274. m_data = new SimpleInternalData;
  275. if (windowType == 0)
  276. {
  277. m_window = new b3gDefaultOpenGLWindow();
  278. }
  279. else if (windowType == 1)
  280. {
  281. #ifdef BT_USE_X11
  282. m_window = new X11OpenGLWindow();
  283. #else
  284. b3Warning("X11 requires Linux. Loading default window instead. \n");
  285. m_window = new b3gDefaultOpenGLWindow();
  286. #endif
  287. }
  288. else if (windowType == 2)
  289. {
  290. #ifdef BT_USE_EGL
  291. m_window = new EGLOpenGLWindow();
  292. #else
  293. b3Warning("EGL window requires compilation with BT_USE_EGL.\n");
  294. b3Warning("Loading default window instead. \n");
  295. m_window = new b3gDefaultOpenGLWindow();
  296. #endif
  297. }
  298. else
  299. {
  300. b3Warning("Unknown window type %d must be (0=default, 1=X11, 2=EGL).\n", windowType);
  301. b3Warning("Loading default window instead. \n");
  302. m_window = new b3gDefaultOpenGLWindow();
  303. }
  304. m_window->setAllowRetina(allowRetina);
  305. b3gWindowConstructionInfo ci;
  306. ci.m_title = title;
  307. ci.m_width = width;
  308. ci.m_height = height;
  309. ci.m_renderDevice = renderDevice;
  310. m_window->createWindow(ci);
  311. m_window->setWindowTitle(title);
  312. b3Assert(glGetError() == GL_NO_ERROR);
  313. {
  314. printGLString("Version", GL_VERSION);
  315. printGLString("Vendor", GL_VENDOR);
  316. printGLString("Renderer", GL_RENDERER);
  317. }
  318. glClearColor(m_backgroundColorRGB[0],
  319. m_backgroundColorRGB[1],
  320. m_backgroundColorRGB[2],
  321. 1.f);
  322. m_window->startRendering();
  323. width = m_window->getWidth();
  324. height = m_window->getHeight();
  325. b3Assert(glGetError() == GL_NO_ERROR);
  326. //gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
  327. #ifdef USE_GLEW
  328. #ifndef __APPLE__
  329. #ifndef _WIN32
  330. #ifndef B3_USE_GLFW
  331. //some Linux implementations need the 'glewExperimental' to be true
  332. glewExperimental = GL_TRUE;
  333. #endif //B3_USE_GLFW
  334. #endif //_WIN32
  335. #ifndef B3_USE_GLFW
  336. if (glewInit() != GLEW_OK)
  337. exit(1); // or handle the error in a nicer way
  338. if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API.
  339. exit(1); // or handle the error in a nicer way
  340. #endif //B3_USE_GLFW
  341. #endif //__APPLE__
  342. #endif //USE_GLEW
  343. glGetError(); //don't remove this call, it is needed for Ubuntu
  344. b3Assert(glGetError() == GL_NO_ERROR);
  345. m_parameterInterface = 0;
  346. b3Assert(glGetError() == GL_NO_ERROR);
  347. m_instancingRenderer = new GLInstancingRenderer(maxNumObjectCapacity, maxShapeCapacityInBytes);
  348. m_primRenderer = new GLPrimitiveRenderer(width, height);
  349. m_renderer = m_instancingRenderer;
  350. m_window->setResizeCallback(SimpleResizeCallback);
  351. m_instancingRenderer->init();
  352. m_instancingRenderer->resize(width, height);
  353. m_primRenderer->setScreenSize(width, height);
  354. b3Assert(glGetError() == GL_NO_ERROR);
  355. m_instancingRenderer->InitShaders();
  356. m_window->setMouseMoveCallback(SimpleMouseMoveCallback);
  357. m_window->setMouseButtonCallback(SimpleMouseButtonCallback);
  358. m_window->setKeyboardCallback(SimpleKeyboardCallback);
  359. m_window->setWheelCallback(SimpleWheelCallback);
  360. TwGenerateDefaultFonts();
  361. m_data->m_fontTextureId = BindFont(g_DefaultNormalFont);
  362. m_data->m_largeFontTextureId = BindFont(g_DefaultLargeFont);
  363. {
  364. m_data->m_renderCallbacks = new OpenGL2RenderCallbacks(m_primRenderer);
  365. m_data->m_renderCallbacks2 = new MyRenderCallbacks(m_instancingRenderer);
  366. m_data->m_fontStash2 = sth_create(512, 512, m_data->m_renderCallbacks2);
  367. m_data->m_fontStash = sth_create(512, 512, m_data->m_renderCallbacks); //256,256);//,1024);//512,512);
  368. b3Assert(glGetError() == GL_NO_ERROR);
  369. if (!m_data->m_fontStash)
  370. {
  371. b3Warning("Could not create stash");
  372. //fprintf(stderr, "Could not create stash.\n");
  373. }
  374. if (!m_data->m_fontStash2)
  375. {
  376. b3Warning("Could not create fontStash2");
  377. }
  378. unsigned char* data2 = OpenSansData;
  379. unsigned char* data = (unsigned char*)data2;
  380. if (!(m_data->m_droidRegular = sth_add_font_from_memory(m_data->m_fontStash, data)))
  381. {
  382. b3Warning("error!\n");
  383. }
  384. if (!(m_data->m_droidRegular2 = sth_add_font_from_memory(m_data->m_fontStash2, data)))
  385. {
  386. b3Warning("error!\n");
  387. }
  388. b3Assert(glGetError() == GL_NO_ERROR);
  389. }
  390. }
  391. struct sth_stash* SimpleOpenGL3App::getFontStash()
  392. {
  393. return m_data->m_fontStash;
  394. }
  395. void SimpleOpenGL3App::drawText3D(const char* txt, float position[3], float orientation[4], float color[4], float size, int optionFlag)
  396. {
  397. B3_PROFILE("SimpleOpenGL3App::drawText3D");
  398. float viewMat[16];
  399. float projMat[16];
  400. CommonCameraInterface* cam = m_instancingRenderer->getActiveCamera();
  401. cam->getCameraViewMatrix(viewMat);
  402. cam->getCameraProjectionMatrix(projMat);
  403. float camPos[4];
  404. cam->getCameraPosition(camPos);
  405. //b3Vector3 cp= b3MakeVector3(camPos[0],camPos[2],camPos[1]);
  406. //b3Vector3 p = b3MakeVector3(worldPosX,worldPosY,worldPosZ);
  407. //float dist = (cp-p).length();
  408. //float dv = 0;//dist/1000.f;
  409. //
  410. //printf("str = %s\n",unicodeText);
  411. float dx = 0;
  412. //int measureOnly=0;
  413. glEnable(GL_BLEND);
  414. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  415. int viewport[4] = {0, 0, m_instancingRenderer->getScreenWidth(), m_instancingRenderer->getScreenHeight()};
  416. float posX = position[0];
  417. float posY = position[1];
  418. float posZ = position[2];
  419. float winx, winy, winz;
  420. if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
  421. {
  422. if (!projectWorldCoordToScreen(position[0], position[1], position[2], viewMat, projMat, viewport, &winx, &winy, &winz))
  423. {
  424. return;
  425. }
  426. posX = winx;
  427. posY = m_instancingRenderer->getScreenHeight() / 2 + (m_instancingRenderer->getScreenHeight() / 2) - winy;
  428. posZ = 0.f;
  429. }
  430. if (optionFlag & CommonGraphicsApp::eDrawText3D_TrueType)
  431. {
  432. bool measureOnly = false;
  433. float fontSize = 64; //512;//128;
  434. if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
  435. {
  436. sth_draw_text(m_data->m_fontStash,
  437. m_data->m_droidRegular, fontSize, posX, posY,
  438. txt, &dx, this->m_instancingRenderer->getScreenWidth(), this->m_instancingRenderer->getScreenHeight(), measureOnly, m_window->getRetinaScale(), color);
  439. sth_end_draw(m_data->m_fontStash);
  440. sth_flush_draw(m_data->m_fontStash);
  441. }
  442. else
  443. {
  444. glEnable(GL_BLEND);
  445. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  446. m_data->m_renderCallbacks2->setColorRGBA(color);
  447. m_data->m_renderCallbacks2->setWorldPosition(position);
  448. m_data->m_renderCallbacks2->setWorldOrientation(orientation);
  449. sth_draw_text3D(m_data->m_fontStash2,
  450. m_data->m_droidRegular2, fontSize, 0, 0, 0,
  451. txt, &dx, size, color, 0);
  452. sth_end_draw(m_data->m_fontStash2);
  453. sth_flush_draw(m_data->m_fontStash2);
  454. glDisable(GL_BLEND);
  455. }
  456. }
  457. else
  458. {
  459. //float width = 0.f;
  460. int pos = 0;
  461. //float color[]={0.2f,0.2,0.2f,1.f};
  462. glActiveTexture(GL_TEXTURE0);
  463. glBindTexture(GL_TEXTURE_2D, m_data->m_largeFontTextureId);
  464. //float width = r.x;
  465. //float extraSpacing = 0.;
  466. float startX = posX;
  467. float startY = posY + g_DefaultLargeFont->m_CharHeight * size;
  468. float z = position[2]; //2.f*winz-1.f;//*(far
  469. if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
  470. {
  471. posX = winx;
  472. posY = m_instancingRenderer->getScreenHeight() / 2 + (m_instancingRenderer->getScreenHeight() / 2) - winy;
  473. z = 2.f * winz - 1.f;
  474. startY = posY - g_DefaultLargeFont->m_CharHeight * size;
  475. }
  476. while (txt[pos])
  477. {
  478. int c = txt[pos];
  479. //r.h = g_DefaultNormalFont->m_CharHeight;
  480. //r.w = g_DefaultNormalFont->m_CharWidth[c]+extraSpacing;
  481. float endX = startX + g_DefaultLargeFont->m_CharWidth[c] * size;
  482. if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
  483. {
  484. endX = startX + g_DefaultLargeFont->m_CharWidth[c] * size;
  485. }
  486. float endY = posY;
  487. //float currentColor[]={1.f,1.,0.2f,1.f};
  488. // m_primRenderer->drawTexturedRect(startX, startY, endX, endY, currentColor,g_DefaultLargeFont->m_CharU0[c],g_DefaultLargeFont->m_CharV0[c],g_DefaultLargeFont->m_CharU1[c],g_DefaultLargeFont->m_CharV1[c]);
  489. float u0 = g_DefaultLargeFont->m_CharU0[c];
  490. float u1 = g_DefaultLargeFont->m_CharU1[c];
  491. float v0 = g_DefaultLargeFont->m_CharV0[c];
  492. float v1 = g_DefaultLargeFont->m_CharV1[c];
  493. //float color[4] = {currentColor[0],currentColor[1],currentColor[2],currentColor[3]};
  494. float x0 = startX;
  495. float x1 = endX;
  496. float y0 = startY;
  497. float y1 = endY;
  498. int screenWidth = m_instancingRenderer->getScreenWidth();
  499. int screenHeight = m_instancingRenderer->getScreenHeight();
  500. float identity[16] = {1, 0, 0, 0,
  501. 0, 1, 0, 0,
  502. 0, 0, 1, 0,
  503. 0, 0, 0, 1};
  504. if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
  505. {
  506. PrimVertex vertexData[4] = {
  507. PrimVertex(PrimVec4(-1.f + 2.f * x0 / float(screenWidth), 1.f - 2.f * y0 / float(screenHeight), z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u0, v0)),
  508. PrimVertex(PrimVec4(-1.f + 2.f * x0 / float(screenWidth), 1.f - 2.f * y1 / float(screenHeight), z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u0, v1)),
  509. PrimVertex(PrimVec4(-1.f + 2.f * x1 / float(screenWidth), 1.f - 2.f * y1 / float(screenHeight), z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u1, v1)),
  510. PrimVertex(PrimVec4(-1.f + 2.f * x1 / float(screenWidth), 1.f - 2.f * y0 / float(screenHeight), z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u1, v0))};
  511. m_primRenderer->drawTexturedRect3D(vertexData[0], vertexData[1], vertexData[2], vertexData[3], identity, identity, false);
  512. }
  513. else
  514. {
  515. PrimVertex vertexData[4] = {
  516. PrimVertex(PrimVec4(x0, y0, z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u0, v0)),
  517. PrimVertex(PrimVec4(x0, y1, z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u0, v1)),
  518. PrimVertex(PrimVec4(x1, y1, z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u1, v1)),
  519. PrimVertex(PrimVec4(x1, y0, z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u1, v0))};
  520. m_primRenderer->drawTexturedRect3D(vertexData[0], vertexData[1], vertexData[2], vertexData[3], viewMat, projMat, false);
  521. }
  522. //DrawTexturedRect(0,r,g_DefaultNormalFont->m_CharU0[c],g_DefaultNormalFont->m_CharV0[c],g_DefaultNormalFont->m_CharU1[c],g_DefaultNormalFont->m_CharV1[c]);
  523. // DrawFilledRect(r);
  524. startX = endX;
  525. //startY = endY;
  526. pos++;
  527. }
  528. glBindTexture(GL_TEXTURE_2D, 0);
  529. }
  530. glDisable(GL_BLEND);
  531. }
  532. void SimpleOpenGL3App::drawText3D(const char* txt, float worldPosX, float worldPosY, float worldPosZ, float size1)
  533. {
  534. float position[3] = {worldPosX, worldPosY, worldPosZ};
  535. float orientation[4] = {0, 0, 0, 1};
  536. float color[4] = {0, 0, 0, 1};
  537. int optionFlags = CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera;
  538. drawText3D(txt, position, orientation, color, size1, optionFlags);
  539. }
  540. void SimpleOpenGL3App::drawText(const char* txt, int posXi, int posYi, float size, float colorRGBA[4])
  541. {
  542. float posX = (float)posXi;
  543. float posY = (float)posYi;
  544. //
  545. //printf("str = %s\n",unicodeText);
  546. float dx = 0;
  547. //int measureOnly=0;
  548. glEnable(GL_BLEND);
  549. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  550. if (1) //m_useTrueTypeFont)
  551. {
  552. bool measureOnly = false;
  553. float fontSize = 64 * size; //512;//128;
  554. sth_draw_text(m_data->m_fontStash,
  555. m_data->m_droidRegular, fontSize, posX, posY,
  556. txt, &dx, this->m_instancingRenderer->getScreenWidth(),
  557. this->m_instancingRenderer->getScreenHeight(),
  558. measureOnly,
  559. m_window->getRetinaScale(), colorRGBA);
  560. sth_end_draw(m_data->m_fontStash);
  561. sth_flush_draw(m_data->m_fontStash);
  562. }
  563. else
  564. {
  565. //float width = 0.f;
  566. int pos = 0;
  567. //float color[]={0.2f,0.2,0.2f,1.f};
  568. glActiveTexture(GL_TEXTURE0);
  569. glBindTexture(GL_TEXTURE_2D, m_data->m_largeFontTextureId);
  570. //float width = r.x;
  571. //float extraSpacing = 0.;
  572. float startX = posX;
  573. float startY = posY;
  574. while (txt[pos])
  575. {
  576. int c = txt[pos];
  577. //r.h = g_DefaultNormalFont->m_CharHeight;
  578. //r.w = g_DefaultNormalFont->m_CharWidth[c]+extraSpacing;
  579. float endX = startX + g_DefaultLargeFont->m_CharWidth[c];
  580. float endY = startY + g_DefaultLargeFont->m_CharHeight;
  581. float currentColor[] = {0.2f, 0.2, 0.2f, 1.f};
  582. m_primRenderer->drawTexturedRect(startX, startY, endX, endY, currentColor, g_DefaultLargeFont->m_CharU0[c], g_DefaultLargeFont->m_CharV0[c], g_DefaultLargeFont->m_CharU1[c], g_DefaultLargeFont->m_CharV1[c]);
  583. //DrawTexturedRect(0,r,g_DefaultNormalFont->m_CharU0[c],g_DefaultNormalFont->m_CharV0[c],g_DefaultNormalFont->m_CharU1[c],g_DefaultNormalFont->m_CharV1[c]);
  584. // DrawFilledRect(r);
  585. startX = endX;
  586. //startY = endY;
  587. pos++;
  588. }
  589. glBindTexture(GL_TEXTURE_2D, 0);
  590. }
  591. glDisable(GL_BLEND);
  592. }
  593. void SimpleOpenGL3App::drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0, float v0, float u1, float v1, int useRGBA)
  594. {
  595. glEnable(GL_BLEND);
  596. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  597. m_primRenderer->drawTexturedRect(x0, y0, x1, y1, color, u0, v0, u1, v1, useRGBA);
  598. glDisable(GL_BLEND);
  599. }
  600. int SimpleOpenGL3App::registerCubeShape(float halfExtentsX, float halfExtentsY, float halfExtentsZ, int textureIndex, float textureScaling)
  601. {
  602. int strideInBytes = 9 * sizeof(float);
  603. int numVertices = sizeof(cube_vertices_textured) / strideInBytes;
  604. int numIndices = sizeof(cube_indices) / sizeof(int);
  605. b3AlignedObjectArray<GfxVertexFormat1> verts;
  606. verts.resize(numVertices);
  607. for (int i = 0; i < numVertices; i++)
  608. {
  609. verts[i].x = halfExtentsX * cube_vertices_textured[i * 9];
  610. verts[i].y = halfExtentsY * cube_vertices_textured[i * 9 + 1];
  611. verts[i].z = halfExtentsZ * cube_vertices_textured[i * 9 + 2];
  612. verts[i].w = cube_vertices_textured[i * 9 + 3];
  613. verts[i].nx = cube_vertices_textured[i * 9 + 4];
  614. verts[i].ny = cube_vertices_textured[i * 9 + 5];
  615. verts[i].nz = cube_vertices_textured[i * 9 + 6];
  616. verts[i].u = cube_vertices_textured[i * 9 + 7] * textureScaling;
  617. verts[i].v = cube_vertices_textured[i * 9 + 8] * textureScaling;
  618. }
  619. int shapeId = m_instancingRenderer->registerShape(&verts[0].x, numVertices, cube_indices, numIndices, B3_GL_TRIANGLES, textureIndex);
  620. return shapeId;
  621. }
  622. void SimpleOpenGL3App::registerGrid(int cells_x, int cells_z, float color0[4], float color1[4])
  623. {
  624. b3Vector3 cubeExtents = b3MakeVector3(0.5, 0.5, 0.5);
  625. double halfHeight = 0.1;
  626. cubeExtents[m_data->m_upAxis] = halfHeight;
  627. int cubeId = registerCubeShape(cubeExtents[0], cubeExtents[1], cubeExtents[2]);
  628. b3Quaternion orn(0, 0, 0, 1);
  629. b3Vector3 center = b3MakeVector3(0, 0, 0, 1);
  630. b3Vector3 scaling = b3MakeVector3(1, 1, 1, 1);
  631. for (int i = 0; i < cells_x; i++)
  632. {
  633. for (int j = 0; j < cells_z; j++)
  634. {
  635. float* color = 0;
  636. if ((i + j) % 2 == 0)
  637. {
  638. color = (float*)color0;
  639. }
  640. else
  641. {
  642. color = (float*)color1;
  643. }
  644. if (this->m_data->m_upAxis == 1)
  645. {
  646. center = b3MakeVector3((i + 0.5f) - cells_x * 0.5f, -halfHeight, (j + 0.5f) - cells_z * 0.5f);
  647. }
  648. else
  649. {
  650. center = b3MakeVector3((i + 0.5f) - cells_x * 0.5f, (j + 0.5f) - cells_z * 0.5f, -halfHeight);
  651. }
  652. m_instancingRenderer->registerGraphicsInstance(cubeId, center, orn, color, scaling);
  653. }
  654. }
  655. }
  656. int SimpleOpenGL3App::registerGraphicsUnitSphereShape(EnumSphereLevelOfDetail lod, int textureId)
  657. {
  658. int red = 255;
  659. int green = 0;
  660. int blue = 128;
  661. if (textureId<0)
  662. {
  663. if (m_data->m_textureId < 0)
  664. {
  665. int texWidth = 1024;
  666. int texHeight = 1024;
  667. b3AlignedObjectArray<unsigned char> texels;
  668. texels.resize(texWidth * texHeight * 3);
  669. for (int i = 0; i < texWidth * texHeight * 3; i++)
  670. texels[i] = 255;
  671. for (int i = 0; i < texWidth; i++)
  672. {
  673. for (int j = 0; j < texHeight; j++)
  674. {
  675. int a = i < texWidth / 2 ? 1 : 0;
  676. int b = j < texWidth / 2 ? 1 : 0;
  677. if (a == b)
  678. {
  679. texels[(i + j * texWidth) * 3 + 0] = red;
  680. texels[(i + j * texWidth) * 3 + 1] = green;
  681. texels[(i + j * texWidth) * 3 + 2] = blue;
  682. // texels[(i+j*texWidth)*4+3] = 255;
  683. }
  684. /*else
  685. {
  686. texels[i*3+0+j*texWidth] = 255;
  687. texels[i*3+1+j*texWidth] = 255;
  688. texels[i*3+2+j*texWidth] = 255;
  689. }
  690. */
  691. }
  692. }
  693. m_data->m_textureId = m_instancingRenderer->registerTexture(&texels[0], texWidth, texHeight);
  694. }
  695. textureId = m_data->m_textureId;
  696. }
  697. int strideInBytes = 9 * sizeof(float);
  698. int graphicsShapeIndex = -1;
  699. switch (lod)
  700. {
  701. case SPHERE_LOD_POINT_SPRITE:
  702. {
  703. int numVertices = sizeof(point_sphere_vertices) / strideInBytes;
  704. int numIndices = sizeof(point_sphere_indices) / sizeof(int);
  705. graphicsShapeIndex = m_instancingRenderer->registerShape(&point_sphere_vertices[0], numVertices, point_sphere_indices, numIndices, B3_GL_POINTS, textureId);
  706. break;
  707. }
  708. case SPHERE_LOD_LOW:
  709. {
  710. int numVertices = sizeof(low_sphere_vertices) / strideInBytes;
  711. int numIndices = sizeof(low_sphere_indices) / sizeof(int);
  712. graphicsShapeIndex = m_instancingRenderer->registerShape(&low_sphere_vertices[0], numVertices, low_sphere_indices, numIndices, B3_GL_TRIANGLES, textureId);
  713. break;
  714. }
  715. case SPHERE_LOD_MEDIUM:
  716. {
  717. int numVertices = sizeof(textured_detailed_sphere_vertices) / strideInBytes;
  718. int numIndices = sizeof(textured_detailed_sphere_indices) / sizeof(int);
  719. graphicsShapeIndex = m_instancingRenderer->registerShape(&textured_detailed_sphere_vertices[0], numVertices, textured_detailed_sphere_indices, numIndices, B3_GL_TRIANGLES, textureId);
  720. break;
  721. }
  722. case SPHERE_LOD_HIGH:
  723. default:
  724. {
  725. int numVertices = sizeof(textured_detailed_sphere_vertices) / strideInBytes;
  726. int numIndices = sizeof(textured_detailed_sphere_indices) / sizeof(int);
  727. graphicsShapeIndex = m_instancingRenderer->registerShape(&textured_detailed_sphere_vertices[0], numVertices, textured_detailed_sphere_indices, numIndices, B3_GL_TRIANGLES, textureId);
  728. break;
  729. }
  730. };
  731. return graphicsShapeIndex;
  732. }
  733. void SimpleOpenGL3App::drawGrid(DrawGridData data)
  734. {
  735. int gridSize = data.gridSize;
  736. float upOffset = data.upOffset;
  737. int upAxis = data.upAxis;
  738. float gridColor[4];
  739. gridColor[0] = data.gridColor[0];
  740. gridColor[1] = data.gridColor[1];
  741. gridColor[2] = data.gridColor[2];
  742. gridColor[3] = data.gridColor[3];
  743. int sideAxis = -1;
  744. int forwardAxis = -1;
  745. switch (upAxis)
  746. {
  747. case 1:
  748. forwardAxis = 2;
  749. sideAxis = 0;
  750. break;
  751. case 2:
  752. forwardAxis = 1;
  753. sideAxis = 0;
  754. break;
  755. default:
  756. b3Assert(0);
  757. };
  758. //b3Vector3 gridColor = b3MakeVector3(0.5,0.5,0.5);
  759. b3AlignedObjectArray<unsigned int> indices;
  760. b3AlignedObjectArray<b3Vector3> vertices;
  761. int lineIndex = 0;
  762. for (int i = -gridSize; i <= gridSize; i++)
  763. {
  764. {
  765. b3Assert(glGetError() == GL_NO_ERROR);
  766. b3Vector3 from = b3MakeVector3(0, 0, 0);
  767. from[sideAxis] = float(i);
  768. from[upAxis] = upOffset;
  769. from[forwardAxis] = float(-gridSize);
  770. b3Vector3 to = b3MakeVector3(0, 0, 0);
  771. to[sideAxis] = float(i);
  772. to[upAxis] = upOffset;
  773. to[forwardAxis] = float(gridSize);
  774. vertices.push_back(from);
  775. indices.push_back(lineIndex++);
  776. vertices.push_back(to);
  777. indices.push_back(lineIndex++);
  778. // m_instancingRenderer->drawLine(from,to,gridColor);
  779. }
  780. b3Assert(glGetError() == GL_NO_ERROR);
  781. {
  782. b3Assert(glGetError() == GL_NO_ERROR);
  783. b3Vector3 from = b3MakeVector3(0, 0, 0);
  784. from[sideAxis] = float(-gridSize);
  785. from[upAxis] = upOffset;
  786. from[forwardAxis] = float(i);
  787. b3Vector3 to = b3MakeVector3(0, 0, 0);
  788. to[sideAxis] = float(gridSize);
  789. to[upAxis] = upOffset;
  790. to[forwardAxis] = float(i);
  791. vertices.push_back(from);
  792. indices.push_back(lineIndex++);
  793. vertices.push_back(to);
  794. indices.push_back(lineIndex++);
  795. // m_instancingRenderer->drawLine(from,to,gridColor);
  796. }
  797. }
  798. m_instancingRenderer->drawLines(&vertices[0].x,
  799. gridColor,
  800. vertices.size(), sizeof(b3Vector3), &indices[0], indices.size(), 1);
  801. m_instancingRenderer->drawLine(b3MakeVector3(0, 0, 0), b3MakeVector3(1, 0, 0), b3MakeVector3(1, 0, 0), 3);
  802. m_instancingRenderer->drawLine(b3MakeVector3(0, 0, 0), b3MakeVector3(0, 1, 0), b3MakeVector3(0, 1, 0), 3);
  803. m_instancingRenderer->drawLine(b3MakeVector3(0, 0, 0), b3MakeVector3(0, 0, 1), b3MakeVector3(0, 0, 1), 3);
  804. // void GLInstancingRenderer::drawPoints(const float* positions, const float color[4], int numPoints, int pointStrideInBytes, float pointDrawSize)
  805. //we don't use drawPoints because all points would have the same color
  806. // b3Vector3 points[3] = { b3MakeVector3(1, 0, 0), b3MakeVector3(0, 1, 0), b3MakeVector3(0, 0, 1) };
  807. // m_instancingRenderer->drawPoints(&points[0].x, b3MakeVector3(1, 0, 0), 3, sizeof(b3Vector3), 6);
  808. m_instancingRenderer->drawPoint(b3MakeVector3(1, 0, 0), b3MakeVector3(1, 0, 0), 6);
  809. m_instancingRenderer->drawPoint(b3MakeVector3(0, 1, 0), b3MakeVector3(0, 1, 0), 6);
  810. m_instancingRenderer->drawPoint(b3MakeVector3(0, 0, 1), b3MakeVector3(0, 0, 1), 6);
  811. }
  812. void SimpleOpenGL3App::setBackgroundColor(float red, float green, float blue)
  813. {
  814. CommonGraphicsApp::setBackgroundColor(red, green, blue);
  815. glClearColor(m_backgroundColorRGB[0], m_backgroundColorRGB[1], m_backgroundColorRGB[2], 1.f);
  816. }
  817. SimpleOpenGL3App::~SimpleOpenGL3App()
  818. {
  819. delete m_instancingRenderer;
  820. delete m_primRenderer;
  821. sth_delete(m_data->m_fontStash);
  822. delete m_data->m_renderCallbacks;
  823. sth_delete(m_data->m_fontStash2);
  824. delete m_data->m_renderCallbacks2;
  825. TwDeleteDefaultFonts();
  826. m_window->closeWindow();
  827. delete m_window;
  828. delete m_data;
  829. }
  830. void SimpleOpenGL3App::setViewport(int width, int height)
  831. {
  832. m_data->m_customViewPortWidth = width;
  833. m_data->m_customViewPortHeight = height;
  834. if (width >= 0)
  835. {
  836. glViewport(0, 0, width, height);
  837. }
  838. else
  839. {
  840. glViewport(0, 0, m_window->getRetinaScale() * m_instancingRenderer->getScreenWidth(), m_window->getRetinaScale() * m_instancingRenderer->getScreenHeight());
  841. }
  842. }
  843. void SimpleOpenGL3App::getScreenPixels(unsigned char* rgbaBuffer, int bufferSizeInBytes, float* depthBuffer, int depthBufferSizeInBytes)
  844. {
  845. int width = m_data->m_customViewPortWidth >= 0 ? m_data->m_customViewPortWidth : (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenWidth();
  846. int height = m_data->m_customViewPortHeight >= 0 ? m_data->m_customViewPortHeight : (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenHeight();
  847. b3Assert((width * height * 4) == bufferSizeInBytes);
  848. if ((width * height * 4) == bufferSizeInBytes)
  849. {
  850. glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgbaBuffer);
  851. int glstat;
  852. glstat = glGetError();
  853. b3Assert(glstat == GL_NO_ERROR);
  854. }
  855. b3Assert((width * height * sizeof(float)) == depthBufferSizeInBytes);
  856. if ((width * height * sizeof(float)) == depthBufferSizeInBytes)
  857. {
  858. glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthBuffer);
  859. int glstat;
  860. glstat = glGetError();
  861. b3Assert(glstat == GL_NO_ERROR);
  862. }
  863. }
  864. //#define STB_IMAGE_WRITE_IMPLEMENTATION
  865. #include "stb_image/stb_image_write.h"
  866. static void writeTextureToFile(int textureWidth, int textureHeight, const char* fileName, FILE* ffmpegVideo)
  867. {
  868. int numComponents = 4;
  869. //glPixelStorei(GL_PACK_ALIGNMENT,1);
  870. b3Assert(glGetError() == GL_NO_ERROR);
  871. //glReadBuffer(GL_BACK);//COLOR_ATTACHMENT0);
  872. float* orgPixels = (float*)malloc(textureWidth * textureHeight * numComponents * 4);
  873. glReadPixels(0, 0, textureWidth, textureHeight, GL_RGBA, GL_FLOAT, orgPixels);
  874. //it is useful to have the actual float values for debugging purposes
  875. //convert float->char
  876. char* pixels = (char*)malloc(textureWidth * textureHeight * numComponents);
  877. assert(glGetError() == GL_NO_ERROR);
  878. for (int j = 0; j < textureHeight; j++)
  879. {
  880. for (int i = 0; i < textureWidth; i++)
  881. {
  882. pixels[(j * textureWidth + i) * numComponents] = char(orgPixels[(j * textureWidth + i) * numComponents] * 255.f);
  883. pixels[(j * textureWidth + i) * numComponents + 1] = char(orgPixels[(j * textureWidth + i) * numComponents + 1] * 255.f);
  884. pixels[(j * textureWidth + i) * numComponents + 2] = char(orgPixels[(j * textureWidth + i) * numComponents + 2] * 255.f);
  885. pixels[(j * textureWidth + i) * numComponents + 3] = char(orgPixels[(j * textureWidth + i) * numComponents + 3] * 255.f);
  886. }
  887. }
  888. if (ffmpegVideo)
  889. {
  890. fwrite(pixels, textureWidth * textureHeight * numComponents, 1, ffmpegVideo);
  891. //fwrite(pixels, 100,1,ffmpegVideo);//textureWidth*textureHeight*numComponents, 1, ffmpegVideo);
  892. }
  893. else
  894. {
  895. if (1)
  896. {
  897. //swap the pixels
  898. unsigned char tmp;
  899. for (int j = 0; j < textureHeight / 2; j++)
  900. {
  901. for (int i = 0; i < textureWidth; i++)
  902. {
  903. for (int c = 0; c < numComponents; c++)
  904. {
  905. tmp = pixels[(j * textureWidth + i) * numComponents + c];
  906. pixels[(j * textureWidth + i) * numComponents + c] =
  907. pixels[((textureHeight - j - 1) * textureWidth + i) * numComponents + c];
  908. pixels[((textureHeight - j - 1) * textureWidth + i) * numComponents + c] = tmp;
  909. }
  910. }
  911. }
  912. }
  913. stbi_write_png(fileName, textureWidth, textureHeight, numComponents, pixels, textureWidth * numComponents);
  914. }
  915. free(pixels);
  916. free(orgPixels);
  917. }
  918. void SimpleOpenGL3App::swapBuffer()
  919. {
  920. if (m_data->m_frameDumpPngFileName)
  921. {
  922. int width = (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenWidth();
  923. int height = (int)m_window->getRetinaScale() * this->m_instancingRenderer->getScreenHeight();
  924. writeTextureToFile(width,
  925. height, m_data->m_frameDumpPngFileName,
  926. m_data->m_ffmpegFile);
  927. m_data->m_renderTexture->disable();
  928. if (m_data->m_ffmpegFile == 0)
  929. {
  930. m_data->m_frameDumpPngFileName = 0;
  931. }
  932. }
  933. m_window->endRendering();
  934. m_window->startRendering();
  935. }
  936. void SimpleOpenGL3App::setMp4Fps(int fps)
  937. {
  938. m_data->m_mp4Fps = fps;
  939. }
  940. // see also http://blog.mmacklin.com/2013/06/11/real-time-video-capture-with-ffmpeg/
  941. void SimpleOpenGL3App::dumpFramesToVideo(const char* mp4FileName)
  942. {
  943. if (mp4FileName)
  944. {
  945. int width = (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenWidth();
  946. int height = (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenHeight();
  947. char cmd[8192];
  948. sprintf(cmd,
  949. "ffmpeg -r %d -f rawvideo -pix_fmt rgba -s %dx%d -i - "
  950. "-threads 0 -y -b:v 50000k -c:v libx264 -preset slow -crf 22 -an -pix_fmt yuv420p -vf vflip %s",
  951. m_data->m_mp4Fps, width, height, mp4FileName);
  952. if (m_data->m_ffmpegFile)
  953. {
  954. pclose(m_data->m_ffmpegFile);
  955. }
  956. if (mp4FileName)
  957. {
  958. m_data->m_ffmpegFile = popen(cmd, "w");
  959. m_data->m_frameDumpPngFileName = mp4FileName;
  960. }
  961. }
  962. else
  963. {
  964. if (m_data->m_ffmpegFile)
  965. {
  966. fflush(m_data->m_ffmpegFile);
  967. pclose(m_data->m_ffmpegFile);
  968. m_data->m_frameDumpPngFileName = 0;
  969. }
  970. m_data->m_ffmpegFile = 0;
  971. }
  972. }
  973. void SimpleOpenGL3App::dumpNextFrameToPng(const char* filename)
  974. {
  975. // open pipe to ffmpeg's stdin in binary write mode
  976. m_data->m_frameDumpPngFileName = filename;
  977. //you could use m_renderTexture to allow to render at higher resolutions, such as 4k or so
  978. if (!m_data->m_renderTexture)
  979. {
  980. m_data->m_renderTexture = new GLRenderToTexture();
  981. GLuint renderTextureId;
  982. glGenTextures(1, &renderTextureId);
  983. // "Bind" the newly created texture : all future texture functions will modify this texture
  984. glBindTexture(GL_TEXTURE_2D, renderTextureId);
  985. // Give an empty image to OpenGL ( the last "0" )
  986. //glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, g_OpenGLWidth,g_OpenGLHeight, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);
  987. //glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA32F, g_OpenGLWidth,g_OpenGLHeight, 0,GL_RGBA, GL_FLOAT, 0);
  988. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F,
  989. m_instancingRenderer->getScreenWidth() * m_window->getRetinaScale(), m_instancingRenderer->getScreenHeight() * m_window->getRetinaScale(), 0, GL_RGBA, GL_FLOAT, 0);
  990. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  991. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  992. //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  993. //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  994. m_data->m_renderTexture->init(m_instancingRenderer->getScreenWidth() * m_window->getRetinaScale(), this->m_instancingRenderer->getScreenHeight() * m_window->getRetinaScale(), renderTextureId, RENDERTEXTURE_COLOR);
  995. }
  996. m_data->m_renderTexture->enable();
  997. }
  998. void SimpleOpenGL3App::setUpAxis(int axis)
  999. {
  1000. b3Assert((axis == 1) || (axis == 2)); //only Y or Z is supported at the moment
  1001. m_data->m_upAxis = axis;
  1002. }
  1003. int SimpleOpenGL3App::getUpAxis() const
  1004. {
  1005. return m_data->m_upAxis;
  1006. }
  1007. #endif //#ifndef NO_OPENGL3