OGLES2Navigation3D.cpp 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482
  1. /******************************************************************************
  2. @File OGLES2Navigation3D.cpp
  3. @Title Navigation
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Demonstrates a method of rendering a 3D navigation application
  8. using OpenGL ES 2.0 and various culling techniques
  9. ******************************************************************************/
  10. #include "PVRShell.h"
  11. #include "OGLES2Tools.h"
  12. #include <stddef.h>
  13. /******************************************************************************
  14. Defines
  15. ******************************************************************************/
  16. #ifdef _DEBUG
  17. #define ENABLE_CULLING_OPTIONS
  18. #define ENABLE_ADVANCED_OUTPUT
  19. #endif
  20. // Index the attributes that are bound to vertex shaders
  21. #define VERTEX_ARRAY 0
  22. #define NORMAL_ARRAY 1
  23. #define TEXCOORD_ARRAY 2
  24. /****************************************************************************
  25. ** Structures
  26. ****************************************************************************/
  27. /*!***********************************************************************
  28. * @Struct PVRTModelVertex
  29. ************************************************************************/
  30. struct PVRTModelVertex
  31. {
  32. PVRTVec3 position;
  33. PVRTVec3 normal;
  34. PVRTVec2 texcoord;
  35. };
  36. /*!***********************************************************************
  37. * @Struct PVRTBoundingBox2D
  38. * @Brief Structure describing a 2D bounding box. Supports all kind of
  39. * set operations and provides higher level functionality.
  40. ************************************************************************/
  41. struct PVRTBoundingBox2D
  42. {
  43. // Min and max coordinates
  44. PVRTVec2 minCoords;
  45. PVRTVec2 maxCoords;
  46. };
  47. /*!**************************************************************************
  48. * @Struct ModelTileObjectSet
  49. ****************************************************************************/
  50. struct ModelTileObjectSet
  51. {
  52. PVRTBoundingBox2D boundingbox;
  53. size_t numSubObjects;
  54. unsigned int *pNodeIdx;
  55. unsigned int *paNumIndices;
  56. unsigned int *paIndexOffsets;
  57. GLuint *pauiTextures;
  58. };
  59. /*!**************************************************************************
  60. * @Struct ModelTileLod
  61. * @Brief A model tile LOD stores the filename of the POD file and various
  62. * attributes like the number of (parent) objects it contains.
  63. * Furthermore it stores two OpenGL buffer object identifiers, one
  64. * for the vertex and another one for the index data.
  65. * The last members keep a list of visible nodes which are determined
  66. * in a seperate visibility update pass.
  67. ****************************************************************************/
  68. struct ModelTileLod
  69. {
  70. char *pszFilename;
  71. size_t numObjects;
  72. ModelTileObjectSet *paObjects;
  73. GLuint vbos[2];
  74. unsigned int *paVisibleNodes;
  75. unsigned int numVisibleNodes;
  76. bool bLoaded;
  77. };
  78. /*!**************************************************************************
  79. * @Struct ModelTile
  80. * @Brief A model tile is a container for all models located within a certain
  81. * region of the city defined by the bounding box. There can be several
  82. * levels of detail for each model tile.
  83. ****************************************************************************/
  84. struct ModelTile
  85. {
  86. PVRTBoundingBox2D boundingbox;
  87. size_t numLod;
  88. ModelTileLod *paLod;
  89. };
  90. /*!**************************************************************************
  91. * @Struct PositionOcclusionData
  92. * @Brief TODO
  93. ****************************************************************************/
  94. struct PositionOcclusionData
  95. {
  96. PVRTVec3 position;
  97. unsigned int numRefObjects;
  98. unsigned int *pRefTile;
  99. unsigned int *pNumRefObject;
  100. unsigned int **ppRefObjects;
  101. };
  102. /*!**************************************************************************
  103. * @Struct ShaderDescription
  104. * @Brief This structure describes a shader program and is just used to
  105. * conveniently store each available shader.
  106. ****************************************************************************/
  107. struct ShaderDescription
  108. {
  109. const char *pszVertShaderSrcFile;
  110. const char *pszVertShaderBinFile;
  111. const char *pszFragShaderSrcFile;
  112. const char *pszFragShaderBinFile;
  113. const unsigned int ui32NumAttributes;
  114. const char **pszAttributes;
  115. };
  116. /******************************************************************************
  117. Content file names
  118. ******************************************************************************/
  119. const char *g_pszAttributes[] = { "inVertex", "inNormal", "inTexCoord" };
  120. const ShaderDescription BuildingShaderDescription = { "BuildingVertShader.vsh", "BuildingVertShader.vsc", "BuildingFragShader.fsh", "BuildingFragShader.fsc", 3, (const char**)g_pszAttributes };
  121. const ShaderDescription SkyboxShaderDescription = { "SkyboxVertShader.vsh", "SkyboxVertShader.vsc", "SkyboxFragShader.fsh", "SkyboxFragShader.fsc", 1, (const char**)g_pszAttributes };
  122. // Textures
  123. const char c_szTextureNameSkybox[] = "Skybox.pvr";
  124. // Scene files
  125. const char c_szTrackFile[] = "cameratrack.pod";
  126. const char c_szModelIndexFilename[] = "modelindex.nav";
  127. const char c_szOcclusionDataFilename[] = "occlusiondata.nav";
  128. // Texture files required for the city model
  129. const char *c_paszTextures[] = { "006_RUS.PNG", "007_RUG.PNG", "008_RUG.PNG", "009_RUG.PNG", "011_GIE.PNG", "012_RSR.PNG", "016_FOC.PNG", "016_RTR.PNG", "017_FOD.PNG",
  130. "018_FOD.PNG", "019_FOC.PNG", "019_GOC.PNG", "019_RZG.PNG", "020_FOC.PNG", "021_FOC.PNG", "022_FOC.PNG", "022_RUG.PNG",
  131. "023_FOB.PNG", "023_RUG.PNG", "024_FOB.PNG", "025_FOC.PNG", "025_RUW.PNG", "026_FOD.PNG", "026_RUW.PNG", "027_FOD.PNG",
  132. "027_RUW.PNG", "028_GOF.PNG", "029_GCC.PNG", "030_GOC.PNG", "031_GOD.PNG", "032_FOC.PNG", "032_GOC.PNG", "033_FOA.PNG",
  133. "033_GOA.PNG", "034_FOC.PNG", "034_GOC.PNG", "035_FOC.PNG", "035_GOC.PNG", "036_FOC.PNG", "036_GOC.PNG", "037_FOC.PNG",
  134. "037_GOC.PNG", "041_FRB.PNG", "041_GRB.PNG", "044_GRC.PNG", "046_GRC.PNG", "055_GRC.PNG", "056_GRC.PNG", "060_FRC.PNG", "063_GRC.PNG",
  135. "064_GRC.PNG", "066_FCB.PNG", "066_GCB.PNG", "067_FCC.PNG", "067_GCC.PNG", "068_GCD.PNG", "069_FCA.PNG", "069_GCA.PNG",
  136. "070_GOD.PNG", "071_FRC.PNG", "072_FRC.PNG", "073_FRC.PNG", "074_FRC.PNG", "075_FRC.PNG", "076_FRC.PNG", "077_FRC.PNG",
  137. "080_GCB.PNG", "083_FRC.PNG", "085_GRC.PNG", "086_FOF.PNG", "086_GOF.PNG", "087_FCA.PNG", "087_GCA.PNG", "087_GCC.PNG",
  138. "054_GRC.PNG", "059_FRC.PNG", "061_FRD.PNG", "082_FCD.PNG", "088_FRC.PNG", "089_FRC.PNG", "092_GCA.PNG", "094_FOD.PNG", "095_FOD.PNG",
  139. "US_IL_CHICAGO_MMART_L.PNG", "US_IL_13443_CHICAGO_35EAST_L.PNG", "US_IL_13444_CHICAGO_LEOBURNETT_L.PNG",
  140. "US_IL_13447_CHICAGO_REIDMURDOCH_L.PNG", "US_IL_13448_CHICAGO_CARBIDE_L.PNG", "US_IL_13449_CHICAGO_CROWNFOUNTAIN_L.PNG",
  141. "US_IL_13451_CHICAGO_CULTURAL_L.PNG", "US_IL_13453_CHICAGO_PRUDENTIAL_PART1_L.PNG", "US_IL_13454_CHICAGO_UNITED_L.PNG",
  142. "US_IL_13458_CHICAGO_SMURFIT_L.PNG", "US_IL_13459_CHICAGO_LASALLE_L.PNG", "US_IL_13461_CHICAGO_UNITRIN_L.PNG", "US_IL_13462_CHICAGO_WILLOUGHBY_L.PNG",
  143. "US_IL_13490_CHICAGO_PRUDENTIAL_PART2_L.PNG", "US_IL_CHICAGO_AONCENTER_L.PNG", "US_IL_CHICAGO_ARTINSTITUTE_L.PNG", "US_IL_CHICAGO_BOARDOFTHETRADE_L.PNG",
  144. "US_IL_CHICAGO_BOEINGBUILDING_L.PNG", "US_IL_CHICAGO_CHICAGOTHEATRE_L.PNG", "US_IL_CHICAGO_CITYHALL_L.PNG", "US_IL_CHICAGO_DALEY_L.PNG",
  145. "US_IL_CHICAGO_HILTON_L.PNG", "US_IL_CHICAGO_JAMESTHOMPSON_L.PNG", "US_IL_CHICAGO_LIBRARY_L.PNG", "US_IL_CHICAGO_MILLENIUMPARK1_L.PNG",
  146. "US_IL_CHICAGO_MILLENIUMPARK2_L.PNG", "US_IL_CHICAGO_OGILVIE_L.PNG", "US_IL_CHICAGO_SEARSTOWER_L.PNG", "US_L_CONCRETE-COLOUR.PNG",
  147. "US_L_CONCRETE-DETAIL.PNG", "US_L_PARK-COLOUR.PNG", "US_L_WATER-COLOUR.PNG", "US_R_CONCRETE.PNG", "US_R_STREET-DASHED.PNG", "US_R_STREET-INNER-SHOULDER.PNG",
  148. "US_R_STREET-LANE-FILLER.PNG", "US_R_STREET-SOLID.PNG", "US_R_STREET-UNMARKED.PNG", "US_R_WALKWAY-SOLID.PNG", "US_R_WALKWAY-UNMARKED.PNG", "US_T_RAILROAD.PNG",
  149. "US_R_HIGHWAY-SOLID.PNG", "US_IL_CHICAGO_UNIONSTATION_L.PNG", "US_IL_13460_CHICAGO_TRUMP_L.PNG", "US_IL_13456_CHICAGO_SEVENTEENTH_L.PNG" };
  150. /*!****************************************************************************
  151. Class declarations
  152. ******************************************************************************/
  153. /*!***********************************************************************
  154. * @Class OGLES2Navigation3D
  155. * @Brief Navigation demo main class.
  156. ************************************************************************/
  157. class OGLES2Navigation3D : public PVRShell
  158. {
  159. // Print3D class used to display text
  160. CPVRTPrint3D m_Print3D;
  161. // Camera attributes
  162. CPVRTModelPOD m_CameraPod;
  163. unsigned int m_ActiveCameraTrack;
  164. float m_fFOV;
  165. float m_fAspectRatio;
  166. float m_fNearClipPlane;
  167. float m_fFarClipPlane;
  168. PVRTVec3 m_vCameraFrom;
  169. PVRTVec3 m_vCameraTo;
  170. PVRTVec3 m_vCameraUp;
  171. // Viewing matrices
  172. PVRTMat4 m_mViewMatrix;
  173. PVRTMat4 m_mProjectionMatrix;
  174. PVRTMat4 m_mViewProjectionMatrix;
  175. // 3D Models
  176. unsigned int m_uiNumModelTiles;
  177. ModelTile *m_paModelTiles;
  178. unsigned int *m_pauiVisibleTiles;
  179. unsigned int m_uiNumVisibleTiles;
  180. float m_afLodDistances[2];
  181. float m_afSquaredLodDistances[2];
  182. // Occlusion data
  183. PositionOcclusionData *m_paPositionOcclusionData;
  184. unsigned int m_uiNumOcclusionData;
  185. // Skybox
  186. GLuint m_uiSkyboxVBO;
  187. GLuint m_uiTextureIdSkybox;
  188. // Textures
  189. unsigned int m_uiNumTextures;
  190. GLuint *m_pauiTextureIds;
  191. // Shader objects
  192. struct Shader
  193. {
  194. GLuint uiId;
  195. GLuint uiVertexShaderId;
  196. GLuint uiFragmentShaderId;
  197. GLuint uiModelViewProjMatrixLoc;
  198. }
  199. m_SkyboxShader;
  200. struct ModelShader : Shader
  201. {
  202. GLuint uiLightDirectionLoc;
  203. }
  204. m_BuildingShader;
  205. // Time variables
  206. float m_fCameraAnimation;
  207. float m_fDebugTimeMultiplier;
  208. // General options
  209. bool m_bUseOcclusionData;
  210. bool m_bViewFrustumCulling;
  211. bool m_bPause;
  212. bool m_bRotate;
  213. public:
  214. virtual bool InitApplication();
  215. virtual bool InitView();
  216. virtual bool ReleaseView();
  217. virtual bool QuitApplication();
  218. virtual bool RenderScene();
  219. bool LoadTextures(CPVRTString* pErrorStr);
  220. bool LoadShader(CPVRTString* pErrorStr, const ShaderDescription &descr, Shader &shader);
  221. bool LoadShaders(CPVRTString* pErrorStr);
  222. bool ReleaseShader(Shader &shader);
  223. unsigned int UpdateTimer();
  224. void Update3dModelWorkingset();
  225. void HandleInput();
  226. void Render3dModels();
  227. void Render3dModelsOcclusion();
  228. void RenderSkyBox();
  229. void CreateModelVbo(const unsigned int tile, const unsigned int lod);
  230. void ReleaseModelVbo(const unsigned int tile, const unsigned int lod);
  231. void CalculateCameraMatrices();
  232. void GetCameraFrame(PVRTVec3 &from, PVRTVec3 &to, PVRTVec3 &up, float time);
  233. void ExtractViewFrustumPlanes(PVRTVec4 &left, PVRTVec4 &right, PVRTVec4 &front, PVRTVec4 &back) const;
  234. bool BoundingBoxIntersectsFrustum(const PVRTBoundingBox2D &bbox, const PVRTVec4 planes[4]) const;
  235. bool Load3dModelIndex(const char *pszFilename, CPVRTString* pErrorStr);
  236. void Release3dModelIndex();
  237. void Cache3dModelData();
  238. bool LoadOcclusionData(const char *pszFilename, CPVRTString* pErrorStr);
  239. void ReleaseOcclusionData();
  240. };
  241. /*!****************************************************************************
  242. @Function LoadTextures
  243. @Output pErrorStr A string describing the error on failure
  244. @Return bool true if no error occured
  245. @Description Loads the textures required for this training course
  246. ******************************************************************************/
  247. bool OGLES2Navigation3D::LoadTextures(CPVRTString* const pErrorStr)
  248. {
  249. if (PVRTTextureLoadFromPVR(c_szTextureNameSkybox, &m_uiTextureIdSkybox) != PVR_SUCCESS)
  250. {
  251. *pErrorStr = CPVRTString("ERROR: Could not open texture file ") + c_szTextureNameSkybox;
  252. return false;
  253. }
  254. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  255. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  256. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  257. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  258. m_uiNumTextures = sizeof(c_paszTextures)/sizeof(c_paszTextures[0]);
  259. m_pauiTextureIds = new GLuint[m_uiNumTextures];
  260. char buffer[512];
  261. for (unsigned int i=0; i < m_uiNumTextures; i++)
  262. {
  263. strcpy(buffer, c_paszTextures[i]);
  264. strcat(buffer, ".pvr");
  265. if (PVR_SUCCESS == PVRTTextureLoadFromPVR(buffer, &m_pauiTextureIds[i]))
  266. {
  267. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  268. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  269. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  270. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  271. }
  272. else
  273. {
  274. PVRShellOutputDebug("Failed to load texture: %s\n", buffer);
  275. }
  276. }
  277. return true;
  278. }
  279. /*!****************************************************************************
  280. @Function LoadShader
  281. @Output pErrorStr A string describing the error on failure
  282. @Input descr A struct containing all necessary information to
  283. load and build the shader
  284. @Output shader A struct containing all shader object identifiers
  285. @Return bool true if no error occured
  286. @Description Loads and compiles a shader and links it into a shader program
  287. ******************************************************************************/
  288. bool OGLES2Navigation3D::LoadShader(CPVRTString* pErrorStr, const ShaderDescription &descr, Shader &shader)
  289. {
  290. if (PVRTShaderLoadFromFile(descr.pszVertShaderBinFile, descr.pszVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &shader.uiVertexShaderId, pErrorStr) != PVR_SUCCESS)
  291. {
  292. *pErrorStr = descr.pszVertShaderSrcFile + CPVRTString(":\n") + *pErrorStr;
  293. return false;
  294. }
  295. if (PVRTShaderLoadFromFile(descr.pszFragShaderBinFile, descr.pszFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &shader.uiFragmentShaderId, pErrorStr) != PVR_SUCCESS)
  296. {
  297. *pErrorStr = descr.pszFragShaderSrcFile + CPVRTString(":\n") + *pErrorStr;
  298. return false;
  299. }
  300. // Set up and link to the shader program
  301. if (PVRTCreateProgram(&shader.uiId, shader.uiVertexShaderId, shader.uiFragmentShaderId, descr.pszAttributes, descr.ui32NumAttributes, pErrorStr))
  302. {
  303. *pErrorStr = descr.pszFragShaderSrcFile + CPVRTString(":\n") + *pErrorStr;
  304. return false;
  305. }
  306. return true;
  307. }
  308. /*!****************************************************************************
  309. @Function LoadShaders
  310. @Output pErrorStr A string describing the error on failure
  311. @Return bool true if no error occured
  312. @Description Loads and compiles shaders and links them to shader programs
  313. ******************************************************************************/
  314. bool OGLES2Navigation3D::LoadShaders(CPVRTString* pErrorStr)
  315. {
  316. // Load and compile the shaders from files.
  317. // Binary shaders are tried first, source shaders are used as fallback.
  318. // CityModelShader
  319. //
  320. if (!LoadShader(pErrorStr, BuildingShaderDescription, m_BuildingShader))
  321. {
  322. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  323. return false;
  324. }
  325. m_BuildingShader.uiModelViewProjMatrixLoc = glGetUniformLocation(m_BuildingShader.uiId, "ModelViewProjMatrix");
  326. m_BuildingShader.uiLightDirectionLoc = glGetUniformLocation(m_BuildingShader.uiId, "LightDirection");
  327. glUniform1i(glGetUniformLocation(m_BuildingShader.uiId, "sTexture"), 0);
  328. // SkyboxShader
  329. //
  330. if (!LoadShader(pErrorStr, SkyboxShaderDescription, m_SkyboxShader))
  331. {
  332. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  333. return false;
  334. }
  335. m_SkyboxShader.uiModelViewProjMatrixLoc = glGetUniformLocation(m_SkyboxShader.uiId, "ModelViewProjMatrix");
  336. glUniform1i(glGetUniformLocation(m_SkyboxShader.uiId, "sCubeMap"), 0);
  337. return true;
  338. }
  339. /*!****************************************************************************
  340. @Function InitApplication
  341. @Return bool true if no error occured
  342. @Description Code in InitApplication() will be called by PVRShell once per
  343. run, before the rendering context is created.
  344. Used to initialize variables that are not dependant on it
  345. (e.g. external modules, loading meshes, etc.)
  346. If the rendering context is lost, InitApplication() will
  347. not be called again.
  348. ******************************************************************************/
  349. bool OGLES2Navigation3D::InitApplication()
  350. {
  351. m_bPause = false;
  352. m_bUseOcclusionData = true;
  353. m_bViewFrustumCulling = true;
  354. m_paModelTiles = 0;
  355. m_pauiVisibleTiles = 0;
  356. m_paPositionOcclusionData = 0;
  357. m_pauiTextureIds = 0;
  358. m_uiNumTextures = 0;
  359. m_uiNumModelTiles = 0;
  360. m_uiNumVisibleTiles = 0;
  361. m_uiNumOcclusionData = 0;
  362. // Get and set the read path for content files
  363. CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
  364. CPVRTString errorStr;
  365. if (!Load3dModelIndex(c_szModelIndexFilename, &errorStr))
  366. {
  367. PVRShellOutputDebug(errorStr.c_str());
  368. return false;
  369. }
  370. if (!LoadOcclusionData(c_szOcclusionDataFilename, &errorStr))
  371. {
  372. PVRShellOutputDebug(errorStr.c_str());
  373. return false;
  374. }
  375. m_pauiVisibleTiles = new unsigned int[m_uiNumModelTiles];
  376. if (PVR_SUCCESS != m_CameraPod.ReadFromFile("cameratrack.pod"))
  377. {
  378. PVRShellSet(prefExitMessage, "Error: Failed to parse POD cameratrack.\n");
  379. return false;
  380. }
  381. m_ActiveCameraTrack = 0;
  382. m_fNearClipPlane = m_CameraPod.pCamera->fNear;
  383. m_fFarClipPlane = m_CameraPod.pCamera->fFar;
  384. m_fFOV = m_CameraPod.pCamera->fFOV;
  385. const int cmdargs = PVRShellGet(prefCommandLineOptNum);
  386. const SCmdLineOpt *pCmdLine = (const SCmdLineOpt *)PVRShellGet(prefCommandLineOpts);
  387. for (int i=0; i < cmdargs; i++)
  388. {
  389. if (strcmp(pCmdLine[i].pArg, "-far") == 0)
  390. {
  391. PVRShellOutputDebug("Info: Changing far clip plane from %.0f to %s\n", m_fFarClipPlane, pCmdLine[i].pVal);
  392. m_fFarClipPlane = (float)atoi(pCmdLine[i].pVal);
  393. }
  394. if (strcmp(pCmdLine[i].pArg, "-near") == 0)
  395. {
  396. PVRShellOutputDebug("Info: Changing near clip plane from %.0f to %s\n", m_fNearClipPlane, pCmdLine[i].pVal);
  397. m_fNearClipPlane = (float)atoi(pCmdLine[i].pVal);
  398. }
  399. }
  400. m_afLodDistances[0] = (m_CameraPod.pCamera->fFar + m_CameraPod.pCamera->fNear) * 0.5f;
  401. m_afLodDistances[1] = m_CameraPod.pCamera->fFar;
  402. m_afSquaredLodDistances[0] = m_afLodDistances[0] * m_afLodDistances[0];
  403. m_afSquaredLodDistances[1] = m_afLodDistances[1] * m_afLodDistances[1];
  404. // Set timer variables
  405. m_fCameraAnimation = 0.0f;
  406. m_fDebugTimeMultiplier = 0.015f;
  407. return true;
  408. }
  409. /*!****************************************************************************
  410. @Function QuitApplication
  411. @Return bool true if no error occured
  412. @Description Code in QuitApplication() will be called by PVRShell once per
  413. run, just before exiting the program.
  414. If the rendering context is lost, QuitApplication() will
  415. not be called.
  416. ******************************************************************************/
  417. bool OGLES2Navigation3D::QuitApplication()
  418. {
  419. Release3dModelIndex();
  420. ReleaseOcclusionData();
  421. delete [] m_pauiTextureIds;
  422. delete [] m_pauiVisibleTiles;
  423. return true;
  424. }
  425. /*!****************************************************************************
  426. @Function InitView
  427. @Return bool true if no error occured
  428. @Description Code in InitView() will be called by PVRShell upon
  429. initialization or after a change in the rendering context.
  430. Used to initialize variables that are dependant on the rendering
  431. context (e.g. textures, vertex buffers, etc.)
  432. ******************************************************************************/
  433. bool OGLES2Navigation3D::InitView()
  434. {
  435. m_fAspectRatio = PVRShellGet(prefWidth) / (float)PVRShellGet(prefHeight);
  436. CPVRTString ErrorStr;
  437. // Load textures
  438. if (!LoadTextures(&ErrorStr))
  439. {
  440. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  441. return false;
  442. }
  443. // Load and compile the shaders & link programs
  444. if (!LoadShaders(&ErrorStr))
  445. {
  446. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  447. return false;
  448. }
  449. // Is the screen rotated?
  450. m_bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  451. #ifdef _WIN32
  452. if (PVRShellGet(prefWidth) < PVRShellGet(prefHeight))
  453. m_bRotate = true;
  454. #endif
  455. // Initialize Print3D
  456. if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), m_bRotate) != PVR_SUCCESS)
  457. {
  458. PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
  459. return false;
  460. }
  461. Cache3dModelData();
  462. // Generate the skybox VBO
  463. GLfloat *pSkyboxVertices, *pSkyboxTexCoords;
  464. PVRTCreateSkybox(10.0f, true, 512, &pSkyboxVertices, &pSkyboxTexCoords);
  465. glGenBuffers(1, &m_uiSkyboxVBO);
  466. glBindBuffer(GL_ARRAY_BUFFER, m_uiSkyboxVBO);
  467. glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*3*24, pSkyboxVertices, GL_STATIC_DRAW);
  468. PVRTDestroySkybox(pSkyboxVertices, pSkyboxTexCoords);
  469. // No stencil test required
  470. glDisable(GL_STENCIL_TEST);
  471. // Disable blending by default
  472. glDisable(GL_BLEND);
  473. // Paint it black
  474. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  475. // Texture channel 0 will always be active
  476. glActiveTexture(GL_TEXTURE0);
  477. // Setup the viewport for the whole window
  478. glViewport(0, 0, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
  479. return true;
  480. }
  481. /*!****************************************************************************
  482. @Function ReleaseShader
  483. @Return bool true if no error occured
  484. @Description Releases a shader program including the individual shader objects.
  485. ******************************************************************************/
  486. bool OGLES2Navigation3D::ReleaseShader(Shader &shader)
  487. {
  488. glDeleteProgram(shader.uiId);
  489. glDeleteShader(shader.uiVertexShaderId);
  490. glDeleteShader(shader.uiFragmentShaderId);
  491. return true;
  492. }
  493. /*!****************************************************************************
  494. @Function ReleaseView
  495. @Return bool true if no error occured
  496. @Description Code in ReleaseView() will be called by PVRShell when the
  497. application quits or before a change in the rendering context.
  498. ******************************************************************************/
  499. bool OGLES2Navigation3D::ReleaseView()
  500. {
  501. // Delete textures
  502. glDeleteTextures(1, &m_uiTextureIdSkybox);
  503. glDeleteTextures(m_uiNumTextures, m_pauiTextureIds);
  504. // Delete program and shader objects
  505. ReleaseShader(m_BuildingShader);
  506. ReleaseShader(m_SkyboxShader);
  507. glDeleteBuffers(1, &m_uiSkyboxVBO);
  508. // Release Print3D Textures
  509. m_Print3D.ReleaseTextures();
  510. return true;
  511. }
  512. /*!****************************************************************************
  513. @Function RenderScene
  514. @Return bool true if no error occured
  515. @Description Main rendering loop function of the program. The shell will
  516. call this function every frame.
  517. eglSwapBuffers() will be performed by PVRShell automatically.
  518. PVRShell will also manage important OS events.
  519. The user has access to these events through an abstraction
  520. layer provided by PVRShell.
  521. ******************************************************************************/
  522. bool OGLES2Navigation3D::RenderScene()
  523. {
  524. // Handle user input and update the timer based variables
  525. HandleInput();
  526. unsigned int fps = UpdateTimer();
  527. // Update the camera interpolation and extract required matrices
  528. CalculateCameraMatrices();
  529. // Clear the color and depth buffer
  530. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  531. // Disable depth test to render the skybox
  532. glDisable(GL_DEPTH_TEST);
  533. RenderSkyBox();
  534. // Enable depth test and render buildings
  535. glEnable(GL_DEPTH_TEST);
  536. if (m_bUseOcclusionData)
  537. Render3dModelsOcclusion();
  538. else
  539. Render3dModels();
  540. glBindBuffer(GL_ARRAY_BUFFER, 0);
  541. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  542. // Displays the demo name and other information using the Print3D tool.
  543. // For a detailed explanation, see the training course IntroducingPVRTools
  544. m_Print3D.DisplayDefaultTitle("Navigation", NULL, ePVRTPrint3DLogoIMG);
  545. #ifdef ENABLE_ADVANCED_OUTPUT
  546. m_Print3D.Print3D(0.05f, 81.0f, 1.0f, 0xFFFFFFFF, "%dx%d FPS: %d", PVRShellGet(prefWidth), PVRShellGet(prefHeight), fps);
  547. #endif
  548. #ifdef ENABLE_CULLING_OPTIONS
  549. m_Print3D.Print3D(0.05f, 88.0f, 1.0f, 0xFFFFFFFF, "Occlusion culling: %s", (m_bUseOcclusionData ? "On" : "Off"));
  550. m_Print3D.Print3D(0.05f, 95.0f, 1.0f, 0xFFFFFFFF, "Frustum culling: %s", (m_bViewFrustumCulling ? "On" : "Off"));
  551. #endif
  552. m_Print3D.Flush();
  553. return true;
  554. }
  555. /*!****************************************************************************
  556. @Function UpdateTimer
  557. @Input none
  558. @Description Updates the values of the current time, previous time, current time
  559. in seconds, delta time and the FPS counter used in the program
  560. ******************************************************************************/
  561. unsigned int OGLES2Navigation3D::UpdateTimer()
  562. {
  563. static unsigned int framecounter = 0;
  564. static unsigned long ulPreviousTime = PVRShellGetTime();
  565. static unsigned long ulLastUpdate = PVRShellGetTime();
  566. static unsigned long ulLastFpsUpdate = PVRShellGetTime();
  567. static unsigned int fps = 60;
  568. unsigned long ulCurrentTime = PVRShellGetTime();
  569. unsigned long ulTimeDelta = ulCurrentTime - ulPreviousTime;
  570. ulPreviousTime = ulCurrentTime;
  571. // Update the visible object four times per second
  572. if (ulCurrentTime - ulLastUpdate > 100)
  573. {
  574. ulLastUpdate = ulCurrentTime;
  575. Update3dModelWorkingset();
  576. }
  577. if (ulCurrentTime - ulLastFpsUpdate > 1000)
  578. {
  579. ulLastFpsUpdate = ulCurrentTime;
  580. fps = framecounter;
  581. framecounter = 0;
  582. }
  583. else
  584. framecounter++;
  585. // Advance camera animation when not paused
  586. if (!m_bPause)
  587. {
  588. m_fCameraAnimation += ulTimeDelta * m_fDebugTimeMultiplier;
  589. // Start from beginning when the end is near
  590. if (m_fCameraAnimation > (m_CameraPod.nNumFrame - 1))
  591. {
  592. m_fCameraAnimation = 0.0f;
  593. // Jump to next camera track
  594. m_ActiveCameraTrack = ++m_ActiveCameraTrack % m_CameraPod.nNumCamera;
  595. }
  596. }
  597. return fps;
  598. }
  599. /*!****************************************************************************
  600. @Function Update3dModelWorkingset
  601. @Input none
  602. @Description Updates the visible object set based on the camera position and
  603. the intersections of the view frustum with the global map plane.
  604. ******************************************************************************/
  605. void OGLES2Navigation3D::Update3dModelWorkingset()
  606. {
  607. PVRTVec4 planes[4];
  608. ExtractViewFrustumPlanes(planes[0], planes[1], planes[2], planes[3]);
  609. const PVRTVec2 lodCenter(m_vCameraFrom);
  610. m_uiNumVisibleTiles = 0;
  611. // Update the object set for each layer
  612. for (unsigned int i=0; i < m_uiNumModelTiles; i++)
  613. {
  614. const PVRTBoundingBox2D bbox = m_paModelTiles[i].boundingbox;
  615. if (BoundingBoxIntersectsFrustum(bbox, planes))
  616. {
  617. const float distToCameraSquared = ((bbox.maxCoords + bbox.minCoords) * 0.5f - lodCenter).lenSqr();
  618. unsigned int lod = (unsigned int)(m_paModelTiles[i].numLod - 1);
  619. for (unsigned int j=0; j < m_paModelTiles[i].numLod; j++)
  620. {
  621. if (distToCameraSquared < m_afSquaredLodDistances[j])
  622. {
  623. lod = j;
  624. break;
  625. }
  626. }
  627. m_pauiVisibleTiles[m_uiNumVisibleTiles++] = i * 10 + lod;
  628. }
  629. }
  630. // Fine grained culling
  631. for (unsigned int i=0; i < m_uiNumVisibleTiles; i++)
  632. {
  633. const unsigned int model = m_pauiVisibleTiles[i] / 10;
  634. const unsigned int lod = m_pauiVisibleTiles[i] - model * 10;
  635. ModelTileLod *pLod = &m_paModelTiles[model].paLod[lod];
  636. pLod->numVisibleNodes = 0;
  637. if (m_bViewFrustumCulling)
  638. {
  639. // Check each node in each tile against the view frustum and add it to the list
  640. // of visible nodes if it is visible
  641. for (unsigned int j=0; j < pLod->numObjects; j++)
  642. if (BoundingBoxIntersectsFrustum(pLod->paObjects[j].boundingbox, planes))
  643. pLod->paVisibleNodes[pLod->numVisibleNodes++] = j;
  644. }
  645. else
  646. for (unsigned int j=0; j < pLod->numObjects; j++)
  647. pLod->paVisibleNodes[pLod->numVisibleNodes++] = j;
  648. }
  649. }
  650. /*!****************************************************************************
  651. @Function HandleInput
  652. @Description Handles user input.
  653. ******************************************************************************/
  654. void OGLES2Navigation3D::HandleInput()
  655. {
  656. // Handle user input
  657. if (PVRShellIsKeyPressed(PVRShellKeyNameDOWN))
  658. m_bPause = !m_bPause;
  659. if (PVRShellIsKeyPressed(PVRShellKeyNameUP))
  660. m_ActiveCameraTrack = ++m_ActiveCameraTrack % m_CameraPod.nNumCamera;
  661. #ifdef ENABLE_CULLING_OPTIONS
  662. if (PVRShellIsKeyPressed(PVRShellKeyNameLEFT))
  663. m_bViewFrustumCulling = !m_bViewFrustumCulling;
  664. if (PVRShellIsKeyPressed(PVRShellKeyNameRIGHT))
  665. m_bUseOcclusionData = !m_bUseOcclusionData;
  666. #endif
  667. if (PVRShellIsKeyPressed(PVRShellKeyNameACTION1))
  668. {
  669. PVRShellOutputDebug("Reloading shader ... \n");
  670. CPVRTString ErrorStr;
  671. ReleaseShader(m_BuildingShader);
  672. if (!LoadShader(&ErrorStr, BuildingShaderDescription, m_BuildingShader))
  673. PVRShellOutputDebug("Failed to reload shader: %s\n", ErrorStr.c_str());
  674. else
  675. PVRShellOutputDebug("Shader reload succesfull.\n");
  676. }
  677. #if 0
  678. if (PVRShellIsKeyPressed(PVRShellKeyNameRIGHT))
  679. m_fDebugTimeMultiplier *= 2.0f;
  680. if (PVRShellIsKeyPressed(PVRShellKeyNameLEFT))
  681. m_fDebugTimeMultiplier *= 0.5f;
  682. #endif
  683. }
  684. /*!****************************************************************************
  685. @Function Render3dModels
  686. @Description Draws a SPODMesh after the model view matrix has been set and
  687. the meterial prepared.
  688. ******************************************************************************/
  689. void OGLES2Navigation3D::Render3dModels()
  690. {
  691. PVRTVec4 planes[4];
  692. ExtractViewFrustumPlanes(planes[0], planes[1], planes[2], planes[3]);
  693. PVRTVec3 lightdir = PVRTVec3(0.5f, 0.5f, 1.0f).normalize();
  694. glUseProgram(m_BuildingShader.uiId);
  695. glUniformMatrix4fv(m_BuildingShader.uiModelViewProjMatrixLoc, 1, GL_FALSE, m_mViewProjectionMatrix.ptr());
  696. glUniform3fv(m_BuildingShader.uiLightDirectionLoc, 1, lightdir.ptr());
  697. // Enable the vertex attribute arrays
  698. glEnableVertexAttribArray(VERTEX_ARRAY);
  699. glEnableVertexAttribArray(NORMAL_ARRAY);
  700. glEnableVertexAttribArray(TEXCOORD_ARRAY);
  701. GLuint prevTexture = 0;
  702. for (unsigned int i=0; i < m_uiNumVisibleTiles; i++)
  703. {
  704. const unsigned int entry = m_pauiVisibleTiles[i];
  705. const unsigned int model = entry / 10;
  706. const unsigned int lod = entry - model * 10;
  707. const ModelTileLod *pLod = &m_paModelTiles[model].paLod[lod];
  708. if (!pLod->bLoaded)
  709. continue;
  710. glBindBuffer(GL_ARRAY_BUFFER, pLod->vbos[0]);
  711. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pLod->vbos[1]);
  712. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, sizeof(PVRTModelVertex), 0);
  713. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, sizeof(PVRTModelVertex), (const void*)offsetof(PVRTModelVertex, normal));
  714. glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, sizeof(PVRTModelVertex), (const void*)offsetof(PVRTModelVertex, texcoord));
  715. for (unsigned int j=0; j < pLod->numVisibleNodes; j++)
  716. {
  717. const ModelTileObjectSet *pObjectSet = &pLod->paObjects[pLod->paVisibleNodes[j]];
  718. // Ignore the object if it is not visible
  719. if (m_bViewFrustumCulling && !BoundingBoxIntersectsFrustum(pObjectSet->boundingbox, planes))
  720. continue;
  721. for (unsigned int k=0; k < pObjectSet->numSubObjects; k++)
  722. {
  723. if (pObjectSet->pauiTextures[k] != prevTexture)
  724. {
  725. glBindTexture(GL_TEXTURE_2D, pObjectSet->pauiTextures[k]);
  726. prevTexture = pObjectSet->pauiTextures[k];
  727. }
  728. glDrawElements(GL_TRIANGLES, (GLsizei)pObjectSet->paNumIndices[k], GL_UNSIGNED_SHORT, (void *)(pObjectSet->paIndexOffsets[k]*sizeof(GLushort)));
  729. }
  730. }
  731. }
  732. glDisableVertexAttribArray(VERTEX_ARRAY);
  733. glDisableVertexAttribArray(NORMAL_ARRAY);
  734. glDisableVertexAttribArray(TEXCOORD_ARRAY);
  735. }
  736. /*!****************************************************************************
  737. @Function Render3dModelsOcclusion
  738. @Description Draws a SPODMesh after the model view matrix has been set and
  739. the meterial prepared.
  740. ******************************************************************************/
  741. void OGLES2Navigation3D::Render3dModelsOcclusion()
  742. {
  743. // Find the nearest spot containing occlusion data
  744. unsigned int nearest_pos = 0;
  745. float nearest_pos_dist = 99999999999.9f;
  746. for (unsigned int i=0; i < m_uiNumOcclusionData; i++)
  747. {
  748. float dist = (m_paPositionOcclusionData[i].position - m_vCameraFrom).lenSqr();
  749. if (dist < nearest_pos_dist)
  750. {
  751. nearest_pos_dist = dist;
  752. nearest_pos = i;
  753. }
  754. }
  755. PVRTVec4 planes[4];
  756. ExtractViewFrustumPlanes(planes[0], planes[1], planes[2], planes[3]);
  757. PVRTVec3 lightdir = PVRTVec3(0.5f, 0.5f, 1.0f).normalize();
  758. glUseProgram(m_BuildingShader.uiId);
  759. glUniformMatrix4fv(m_BuildingShader.uiModelViewProjMatrixLoc, 1, GL_FALSE, m_mViewProjectionMatrix.ptr());
  760. glUniform3fv(m_BuildingShader.uiLightDirectionLoc, 1, lightdir.ptr());
  761. // Enable the vertex attribute arrays
  762. glEnableVertexAttribArray(VERTEX_ARRAY);
  763. glEnableVertexAttribArray(NORMAL_ARRAY);
  764. glEnableVertexAttribArray(TEXCOORD_ARRAY);
  765. GLuint prevTexture = 0;
  766. PositionOcclusionData *pRefData = &m_paPositionOcclusionData[nearest_pos];
  767. for (unsigned int i=0; i < pRefData->numRefObjects; i++)
  768. {
  769. const unsigned int numRefObjects = pRefData->pNumRefObject[i];
  770. const unsigned int refTile = pRefData->pRefTile[i];
  771. const unsigned int *pRefObjects = pRefData->ppRefObjects[i];
  772. const PVRTVec2 lodReferencePosition(m_vCameraFrom);
  773. const float sqDist = ((m_paModelTiles[refTile].boundingbox.maxCoords + m_paModelTiles[refTile].boundingbox.minCoords) * 0.5f - lodReferencePosition).lenSqr();
  774. unsigned int lod = (unsigned int)(m_paModelTiles[i].numLod - 1);
  775. for (unsigned int j=0; j < m_paModelTiles[refTile].numLod; j++)
  776. {
  777. if (sqDist < m_afSquaredLodDistances[j])
  778. {
  779. lod = j;
  780. break;
  781. }
  782. }
  783. const ModelTileLod *pLod = &m_paModelTiles[refTile].paLod[lod];
  784. if (!pLod->bLoaded)
  785. continue;
  786. // Ignore the tile if it is not visible
  787. if (m_bViewFrustumCulling && !BoundingBoxIntersectsFrustum(m_paModelTiles[refTile].boundingbox, planes))
  788. continue;
  789. glBindBuffer(GL_ARRAY_BUFFER, pLod->vbos[0]);
  790. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pLod->vbos[1]);
  791. for (unsigned int j=0; j < numRefObjects; j++)
  792. {
  793. const ModelTileObjectSet *pObjectSet = &pLod->paObjects[pRefObjects[j]];
  794. // Ignore the object if it is not visible
  795. if (m_bViewFrustumCulling && !BoundingBoxIntersectsFrustum(pObjectSet->boundingbox, planes))
  796. continue;
  797. for (unsigned int k=0; k < pObjectSet->numSubObjects; k++)
  798. {
  799. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, sizeof(PVRTModelVertex), 0);
  800. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, sizeof(PVRTModelVertex), (const void*)offsetof(PVRTModelVertex, normal));
  801. glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, sizeof(PVRTModelVertex), (const void*)offsetof(PVRTModelVertex, texcoord));
  802. if (pObjectSet->pauiTextures[k] != prevTexture)
  803. {
  804. glBindTexture(GL_TEXTURE_2D, pObjectSet->pauiTextures[k]);
  805. prevTexture = pObjectSet->pauiTextures[k];
  806. }
  807. glDrawElements(GL_TRIANGLES, (GLsizei)pObjectSet->paNumIndices[k], GL_UNSIGNED_SHORT, (void *)(pObjectSet->paIndexOffsets[k]*sizeof(GLushort)));
  808. }
  809. }
  810. }
  811. glDisableVertexAttribArray(VERTEX_ARRAY);
  812. glDisableVertexAttribArray(NORMAL_ARRAY);
  813. glDisableVertexAttribArray(TEXCOORD_ARRAY);
  814. glBindBuffer(GL_ARRAY_BUFFER, 0);
  815. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  816. }
  817. /*!****************************************************************************
  818. @Function RenderSkyBox
  819. @Description TBD
  820. ******************************************************************************/
  821. void OGLES2Navigation3D::RenderSkyBox()
  822. {
  823. PVRTMat4 mv_matrix = PVRTMat4::LookAtRH(PVRTVec3(0.0f, 0.0f, -2.5f), m_vCameraTo - m_vCameraFrom + PVRTVec3(0.0f, 0.0f, -2.5f), m_vCameraUp);
  824. PVRTMat4 mvp_matrix = m_mProjectionMatrix * mv_matrix;
  825. glUseProgram(m_SkyboxShader.uiId);
  826. glUniformMatrix4fv(m_SkyboxShader.uiModelViewProjMatrixLoc, 1, GL_FALSE, mvp_matrix.ptr());
  827. glBindBuffer(GL_ARRAY_BUFFER, m_uiSkyboxVBO);
  828. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  829. glBindTexture(GL_TEXTURE_2D, m_uiTextureIdSkybox);
  830. // Enable the vertex attribute arrays
  831. glEnableVertexAttribArray(VERTEX_ARRAY);
  832. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, sizeof(PVRTVec3), NULL);
  833. // Draw primitive
  834. for(int i = 0; i < 6; ++i)
  835. glDrawArrays(GL_TRIANGLE_STRIP, i*4, 4);
  836. glDisableVertexAttribArray(VERTEX_ARRAY);
  837. }
  838. /*!****************************************************************************
  839. @Function CreateModelVbo
  840. @Description Creates vertex buffer objects of
  841. ******************************************************************************/
  842. void OGLES2Navigation3D::CreateModelVbo(const unsigned int tile, const unsigned int lod)
  843. {
  844. ModelTileLod *pLod = &m_paModelTiles[tile].paLod[lod];
  845. CPVRTModelPOD model;
  846. if (PVR_FAIL == model.ReadFromFile(pLod->pszFilename))
  847. return;
  848. else
  849. pLod->bLoaded = true;
  850. unsigned int totalVertexCount = 0;
  851. unsigned int totalIndexCount = 0;
  852. for (unsigned int i=0; i < pLod->numObjects; i++)
  853. {
  854. const size_t numSubObjects = pLod->paObjects[i].numSubObjects;
  855. pLod->paObjects[i].paNumIndices = new unsigned int[numSubObjects];
  856. pLod->paObjects[i].paIndexOffsets = new unsigned int[numSubObjects];
  857. pLod->paObjects[i].pauiTextures = new GLuint[numSubObjects];
  858. for (unsigned int j=0; j < pLod->paObjects[i].numSubObjects; j++)
  859. {
  860. const int mesh_index = model.pNode[pLod->paObjects[i].pNodeIdx[j]].nIdx;
  861. const SPODMesh &mesh = model.pMesh[mesh_index];
  862. totalVertexCount += mesh.nNumVertex;
  863. totalIndexCount += PVRTModelPODCountIndices(mesh);
  864. pLod->paObjects[i].paNumIndices[j] = PVRTModelPODCountIndices(mesh);
  865. if (model.pMaterial)
  866. {
  867. const int material_index = model.pNode[pLod->paObjects[i].pNodeIdx[j]].nIdxMaterial;
  868. const SPODTexture &texture = model.pTexture[model.pMaterial[material_index].nIdxTexDiffuse];
  869. // Pre-init with invalid texture handle
  870. pLod->paObjects[i].pauiTextures[j] = 0;
  871. for (unsigned int k=0; k < m_uiNumTextures; k++)
  872. {
  873. if (strcmp(texture.pszName, c_paszTextures[k]) == 0)
  874. {
  875. pLod->paObjects[i].pauiTextures[j] = m_pauiTextureIds[k];
  876. break;
  877. }
  878. }
  879. }
  880. }
  881. }
  882. if (totalVertexCount > 65536)
  883. {
  884. PVRShellOutputDebug("Too many vertices to index with ushort in mesh %s!\n", pLod->pszFilename);
  885. pLod->bLoaded = false;
  886. return;
  887. }
  888. GLushort *pIndices = new GLushort[totalIndexCount];
  889. PVRTModelVertex *pVertices = new PVRTModelVertex[totalVertexCount];
  890. unsigned int indexOffset = 0;
  891. unsigned int vertexOffset = 0;
  892. for (unsigned int i=0; i < pLod->numObjects; i++)
  893. {
  894. for (unsigned int j=0; j < pLod->paObjects[i].numSubObjects; j++)
  895. {
  896. const int mesh_index = model.pNode[pLod->paObjects[i].pNodeIdx[j]].nIdx;
  897. const SPODMesh &mesh = model.pMesh[mesh_index];
  898. const unsigned int numIndices = PVRTModelPODCountIndices(mesh);
  899. PVRTModelVertex *pSrcVertices = (PVRTModelVertex *)mesh.pInterleaved;
  900. GLushort *pSrcIndices = (GLushort *)mesh.sFaces.pData;
  901. pLod->paObjects[i].paIndexOffsets[j] = indexOffset;
  902. for (unsigned int k=0; k < mesh.nNumVertex; k++)
  903. {
  904. const PVRTVec3 normal = pSrcVertices[k].normal;
  905. pVertices[vertexOffset + k].normal = PVRTVec3(normal.x, -normal.z, normal.y);
  906. const PVRTVec3 pos = pSrcVertices[k].position;
  907. pVertices[vertexOffset + k].position = PVRTVec3(pos.x, -pos.z, pos.y);
  908. pVertices[vertexOffset + k].texcoord = pSrcVertices[k].texcoord;
  909. }
  910. for (unsigned int k=0; k < numIndices; k++)
  911. pIndices[indexOffset + k] = (GLushort)(pSrcIndices[k] + vertexOffset);
  912. vertexOffset += mesh.nNumVertex;
  913. indexOffset += numIndices;
  914. }
  915. }
  916. glGenBuffers(2, pLod->vbos);
  917. glBindBuffer(GL_ARRAY_BUFFER, pLod->vbos[0]);
  918. glBufferData(GL_ARRAY_BUFFER, totalVertexCount * sizeof(PVRTModelVertex), pVertices, GL_STATIC_DRAW);
  919. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pLod->vbos[1]);
  920. glBufferData(GL_ELEMENT_ARRAY_BUFFER, totalIndexCount * sizeof(GLushort), pIndices, GL_STATIC_DRAW);
  921. delete [] pIndices;
  922. delete [] pVertices;
  923. }
  924. /*!****************************************************************************
  925. @Function ReleaseModelVbo
  926. @Description TODO
  927. ******************************************************************************/
  928. void OGLES2Navigation3D::ReleaseModelVbo(const unsigned int tile, const unsigned int lod)
  929. {
  930. ModelTileLod *pLod = &m_paModelTiles[tile].paLod[lod];
  931. for (unsigned int i=0; i < pLod->numObjects; i++)
  932. {
  933. delete [] pLod->paObjects[i].paNumIndices;
  934. delete [] pLod->paObjects[i].paIndexOffsets;
  935. delete [] pLod->paObjects[i].pauiTextures;
  936. pLod->paObjects[i].paNumIndices = 0;
  937. pLod->paObjects[i].paIndexOffsets = 0;
  938. pLod->paObjects[i].pauiTextures = 0;
  939. }
  940. }
  941. /*!****************************************************************************
  942. @Function Cache3dModelData
  943. @Description Loads all POD files and textures in advance.
  944. ******************************************************************************/
  945. void OGLES2Navigation3D::Cache3dModelData()
  946. {
  947. for (unsigned int i=0; i < m_uiNumModelTiles; i++)
  948. for (unsigned int j=0; j < m_paModelTiles[i].numLod; j++)
  949. CreateModelVbo(i, j);
  950. }
  951. /*!****************************************************************************
  952. @Function GetCameraFrame
  953. @Description TODO
  954. ******************************************************************************/
  955. void OGLES2Navigation3D::GetCameraFrame(PVRTVec3 &from, PVRTVec3 &to, PVRTVec3 &up, float time)
  956. {
  957. m_CameraPod.SetFrame(time);
  958. m_CameraPod.GetCamera(from, to, up, m_ActiveCameraTrack);
  959. from *= 0.0254f;
  960. to *= 0.0254f;
  961. from = PVRTVec3(from.x, -from.z, from.y);
  962. to = PVRTVec3(to.x, -to.z, to.y);
  963. up = PVRTVec3(up.x, -up.z, up.y);
  964. }
  965. /*!****************************************************************************
  966. @Function CalculateCameraMatrices
  967. @Description TODO
  968. ******************************************************************************/
  969. void OGLES2Navigation3D::CalculateCameraMatrices()
  970. {
  971. float clamped_delta = m_fCameraAnimation + 5.0f;
  972. if (clamped_delta > (m_CameraPod.nNumFrame - 1))
  973. clamped_delta -= (m_CameraPod.nNumFrame - 1);
  974. PVRTVec3 now_from, now_to, now_up;
  975. GetCameraFrame(now_from, now_to, now_up, m_fCameraAnimation);
  976. PVRTVec3 next_from, next_to, next_up;
  977. GetCameraFrame(next_from, next_to, next_up, clamped_delta);
  978. m_vCameraFrom = now_from;
  979. m_vCameraTo = now_from + (next_from - now_from).normalized();
  980. m_vCameraUp = now_up;
  981. m_mViewMatrix = PVRTMat4::LookAtRH(m_vCameraFrom, m_vCameraTo, m_vCameraUp);
  982. m_mProjectionMatrix = PVRTMat4::PerspectiveFovRH(m_fFOV, m_fAspectRatio, m_fNearClipPlane, m_fFarClipPlane, PVRTMat4::OGL, m_bRotate);
  983. m_mViewProjectionMatrix = m_mProjectionMatrix * m_mViewMatrix;
  984. }
  985. /*!****************************************************************************
  986. @Function ExtractViewFrustumPlanes
  987. @Description Extracts the (left, right, front and back) view frustum planes
  988. from the camera modelview-projection matrix.
  989. ******************************************************************************/
  990. void OGLES2Navigation3D::ExtractViewFrustumPlanes(PVRTVec4 &left, PVRTVec4 &right, PVRTVec4 &front, PVRTVec4 &back) const
  991. {
  992. const PVRTMat4 matrix = m_mViewProjectionMatrix;
  993. left.x = (matrix.f[3] + matrix.f[0]);
  994. left.y = (matrix.f[7] + matrix.f[4]);
  995. left.z = (matrix.f[11] + matrix.f[8]);
  996. left.w = (matrix.f[15] + matrix.f[12]);
  997. float inv_len = 1.0f / PVRTVec3(left).length();
  998. left *= inv_len;
  999. right.x = (matrix.f[3] - matrix.f[0]);
  1000. right.y = (matrix.f[7] - matrix.f[4]);
  1001. right.z = (matrix.f[11] - matrix.f[8]);
  1002. right.w = (matrix.f[15] - matrix.f[12]);
  1003. inv_len = 1.0f / PVRTVec3(right).length();
  1004. right *= inv_len;
  1005. front.x = (matrix.f[3] + matrix.f[2]);
  1006. front.y = (matrix.f[7] + matrix.f[6]);
  1007. front.z = (matrix.f[11] + matrix.f[10]);
  1008. front.w = (matrix.f[15] + matrix.f[14]);
  1009. inv_len = 1.0f / PVRTVec3(front).length();
  1010. front *= inv_len;
  1011. back.x = (matrix.f[3] - matrix.f[2]);
  1012. back.y = (matrix.f[7] - matrix.f[6]);
  1013. back.z = (matrix.f[11] - matrix.f[10]);
  1014. back.w = (matrix.f[15] - matrix.f[14]);
  1015. inv_len = 1.0f / PVRTVec3(back).length();
  1016. back *= inv_len;
  1017. }
  1018. /*!****************************************************************************
  1019. @Function Load3dModelIndex
  1020. @Description Loads the mesh data required for this training course into
  1021. vertex buffer objects
  1022. ******************************************************************************/
  1023. bool OGLES2Navigation3D::Load3dModelIndex(const char *pszFilename, CPVRTString* pErrorStr)
  1024. {
  1025. CPVRTResourceFile file(pszFilename);
  1026. if (!file.IsOpen())
  1027. {
  1028. *pErrorStr = "Error: Could not open 3d model hirarchy file!\n";
  1029. return false;
  1030. }
  1031. const char *pData = (const char *)file.DataPtr();
  1032. size_t numTiles;
  1033. memcpy((char *)&numTiles, pData, sizeof(numTiles));
  1034. pData += sizeof(numTiles);
  1035. m_uiNumModelTiles = (unsigned int)numTiles;
  1036. m_paModelTiles = new ModelTile[m_uiNumModelTiles];
  1037. for (unsigned int i=0; i < m_uiNumModelTiles; i++)
  1038. {
  1039. memcpy((char *)&m_paModelTiles[i].boundingbox, pData, sizeof(PVRTBoundingBox2D));
  1040. pData += sizeof(PVRTBoundingBox2D);
  1041. memcpy((char *)&m_paModelTiles[i].numLod, pData, sizeof(size_t));
  1042. pData += sizeof(size_t);
  1043. m_paModelTiles[i].paLod = new ModelTileLod[m_paModelTiles[i].numLod];
  1044. for (unsigned int j=0; j < m_paModelTiles[i].numLod; j++)
  1045. {
  1046. m_paModelTiles[i].paLod[j].bLoaded = false;
  1047. size_t namelength;
  1048. memcpy((char *)&namelength, pData, sizeof(size_t));
  1049. pData += sizeof(size_t);
  1050. m_paModelTiles[i].paLod[j].pszFilename = new char[namelength+1];
  1051. memcpy((char *)m_paModelTiles[i].paLod[j].pszFilename, pData, sizeof(char) * namelength);
  1052. pData += sizeof(char) * namelength;
  1053. m_paModelTiles[i].paLod[j].pszFilename[namelength] = '\0';
  1054. memcpy((char *)&m_paModelTiles[i].paLod[j].numObjects, pData, sizeof(size_t));
  1055. pData += sizeof(size_t);
  1056. m_paModelTiles[i].paLod[j].paObjects = new ModelTileObjectSet[m_paModelTiles[i].paLod[j].numObjects];
  1057. m_paModelTiles[i].paLod[j].paVisibleNodes = new unsigned int[m_paModelTiles[i].paLod[j].numObjects];
  1058. m_paModelTiles[i].paLod[j].numVisibleNodes = 0;
  1059. for (unsigned int k=0; k < m_paModelTiles[i].paLod[j].numObjects; k++)
  1060. {
  1061. memcpy((char *)&m_paModelTiles[i].paLod[j].paObjects[k].boundingbox, pData, sizeof(PVRTBoundingBox2D));
  1062. pData += sizeof(PVRTBoundingBox2D);
  1063. memcpy((char *)&m_paModelTiles[i].paLod[j].paObjects[k].numSubObjects, pData, sizeof(size_t));
  1064. pData += sizeof(size_t);
  1065. m_paModelTiles[i].paLod[j].paObjects[k].pNodeIdx = new unsigned int[m_paModelTiles[i].paLod[j].paObjects[k].numSubObjects];
  1066. memcpy((char *)m_paModelTiles[i].paLod[j].paObjects[k].pNodeIdx, pData, sizeof(unsigned int) * m_paModelTiles[i].paLod[j].paObjects[k].numSubObjects);
  1067. pData += sizeof(unsigned int) * m_paModelTiles[i].paLod[j].paObjects[k].numSubObjects;
  1068. m_paModelTiles[i].paLod[j].paObjects[k].pauiTextures = 0;
  1069. m_paModelTiles[i].paLod[j].paObjects[k].paNumIndices = 0;
  1070. m_paModelTiles[i].paLod[j].paObjects[k].paIndexOffsets = 0;
  1071. }
  1072. }
  1073. }
  1074. return true;
  1075. }
  1076. /*!****************************************************************************
  1077. @Function Release3dModelIndex
  1078. @Description Loads the mesh data required for this training course into
  1079. vertex buffer objects
  1080. ******************************************************************************/
  1081. void OGLES2Navigation3D::Release3dModelIndex()
  1082. {
  1083. for (unsigned int i=0; i < m_uiNumModelTiles; i++)
  1084. {
  1085. for (unsigned int j=0; j < m_paModelTiles[i].numLod; j++)
  1086. {
  1087. for (unsigned int k=0; k < m_paModelTiles[i].paLod[j].numObjects; k++)
  1088. {
  1089. delete [] m_paModelTiles[i].paLod[j].paObjects[k].pNodeIdx;
  1090. delete [] m_paModelTiles[i].paLod[j].paObjects[k].paNumIndices;
  1091. delete [] m_paModelTiles[i].paLod[j].paObjects[k].paIndexOffsets;
  1092. delete [] m_paModelTiles[i].paLod[j].paObjects[k].pauiTextures;
  1093. }
  1094. delete [] m_paModelTiles[i].paLod[j].paObjects;
  1095. delete [] m_paModelTiles[i].paLod[j].paVisibleNodes;
  1096. delete [] m_paModelTiles[i].paLod[j].pszFilename;
  1097. }
  1098. delete [] m_paModelTiles[i].paLod;
  1099. }
  1100. delete [] m_paModelTiles;
  1101. }
  1102. /*!****************************************************************************
  1103. @Function LoadOcclusionData
  1104. @Description TODO
  1105. ******************************************************************************/
  1106. bool OGLES2Navigation3D::LoadOcclusionData(const char *pszFilename, CPVRTString* pErrorStr)
  1107. {
  1108. CPVRTResourceFile file(pszFilename);
  1109. if (!file.IsOpen())
  1110. {
  1111. *pErrorStr = "Error: Could not open occlusion data!\n";
  1112. return false;
  1113. }
  1114. const char *pData = (const char *)file.DataPtr();
  1115. size_t namelen;
  1116. memcpy((char *)&namelen, pData, sizeof(namelen));
  1117. pData += sizeof(namelen);
  1118. // Skip the name
  1119. pData += namelen;
  1120. size_t numTiles;
  1121. memcpy((char *)&numTiles, pData, sizeof(numTiles));
  1122. pData += sizeof(numTiles);
  1123. for (unsigned int i=0; i < numTiles; i++)
  1124. {
  1125. memcpy((char *)&namelen, pData, sizeof(namelen));
  1126. pData += sizeof(namelen);
  1127. // Skip the name
  1128. pData += namelen;
  1129. }
  1130. size_t numpositions;
  1131. memcpy((char *)&numpositions, pData, sizeof(numpositions));
  1132. pData += sizeof(numpositions);
  1133. m_uiNumOcclusionData = (unsigned int)numpositions;
  1134. m_paPositionOcclusionData = new PositionOcclusionData[m_uiNumOcclusionData];
  1135. for (unsigned int i=0; i < m_uiNumOcclusionData; i++)
  1136. {
  1137. memcpy((char *)&m_paPositionOcclusionData[i].position, pData, sizeof(PVRTVec3));
  1138. pData += sizeof(PVRTVec3);
  1139. size_t reftiles;
  1140. memcpy((char *)&reftiles, pData, sizeof(reftiles));
  1141. pData += sizeof(reftiles);
  1142. m_paPositionOcclusionData[i].numRefObjects = (unsigned int)reftiles;
  1143. m_paPositionOcclusionData[i].pRefTile = new unsigned int[reftiles];
  1144. m_paPositionOcclusionData[i].pNumRefObject = new unsigned int[reftiles];
  1145. m_paPositionOcclusionData[i].ppRefObjects = new unsigned int*[reftiles];
  1146. for (unsigned int j=0; j < reftiles; j++)
  1147. {
  1148. size_t tilenum;
  1149. memcpy((char *)&tilenum, pData, sizeof(tilenum));
  1150. pData += sizeof(tilenum);
  1151. m_paPositionOcclusionData[i].pRefTile[j] = (unsigned int)tilenum;
  1152. size_t num_ref_models;
  1153. memcpy((char *)&num_ref_models, pData, sizeof(num_ref_models));
  1154. pData += sizeof(num_ref_models);
  1155. m_paPositionOcclusionData[i].pNumRefObject[j] = (unsigned int)num_ref_models;
  1156. m_paPositionOcclusionData[i].ppRefObjects[j] = new unsigned int[num_ref_models];
  1157. memcpy((char *)m_paPositionOcclusionData[i].ppRefObjects[j], pData, sizeof(unsigned int) * num_ref_models);
  1158. pData += sizeof(unsigned int) * num_ref_models;
  1159. }
  1160. }
  1161. return true;
  1162. }
  1163. /*!****************************************************************************
  1164. @Function ReleaseOcclusionData
  1165. @Description TODO
  1166. ******************************************************************************/
  1167. void OGLES2Navigation3D::ReleaseOcclusionData()
  1168. {
  1169. for (unsigned int i=0; i < m_uiNumOcclusionData; i++)
  1170. {
  1171. for (unsigned int j=0; j < m_paPositionOcclusionData[i].numRefObjects; j++)
  1172. delete [] m_paPositionOcclusionData[i].ppRefObjects[j];
  1173. delete [] m_paPositionOcclusionData[i].pNumRefObject;
  1174. delete [] m_paPositionOcclusionData[i].pRefTile;
  1175. delete [] m_paPositionOcclusionData[i].ppRefObjects;
  1176. }
  1177. delete [] m_paPositionOcclusionData;
  1178. }
  1179. /*!****************************************************************************
  1180. @Function BoundingBoxIntersectsFrustum
  1181. @Description TODO
  1182. ******************************************************************************/
  1183. bool OGLES2Navigation3D::BoundingBoxIntersectsFrustum(const PVRTBoundingBox2D &bbox, const PVRTVec4 planes[4]) const
  1184. {
  1185. PVRTVec3 points[4];
  1186. points[0] = PVRTVec3(bbox.minCoords.x, bbox.minCoords.y, 0.0f);
  1187. points[1] = PVRTVec3(bbox.maxCoords.x, bbox.minCoords.y, 0.0f);
  1188. points[2] = PVRTVec3(bbox.maxCoords.x, bbox.maxCoords.y, 0.0f);
  1189. points[3] = PVRTVec3(bbox.minCoords.x, bbox.maxCoords.y, 0.0f);
  1190. // Test the axis-aligned bounding box against each plane;
  1191. // only cull if all points are outside of one the view frustum planes
  1192. for (unsigned int p=0; p < 4; p++)
  1193. {
  1194. unsigned int pointsOut = 0;
  1195. // Test the points against the plane
  1196. for(unsigned int j=0; j < 4; j++)
  1197. if ((planes[p].x * points[j].x + planes[p].y * points[j].y + planes[p].z * points[j].z + planes[p].w) < 0.0f)
  1198. pointsOut++;
  1199. // if all points are outside of a plane we can cull it
  1200. if (pointsOut == 4)
  1201. return false;
  1202. }
  1203. return true;
  1204. }
  1205. /*!****************************************************************************
  1206. @Function NewDemo
  1207. @Return PVRShell* The demo supplied by the user
  1208. @Description This function must be implemented by the user of the shell.
  1209. The user should return its PVRShell object defining the
  1210. behaviour of the application.
  1211. ******************************************************************************/
  1212. PVRShell* NewDemo()
  1213. {
  1214. return new OGLES2Navigation3D();
  1215. }
  1216. /******************************************************************************
  1217. End of file (OGLES2Navigation3D.cpp)
  1218. ******************************************************************************/