Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

TextureManager.cpp 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*!
  2. * \file src/TextureManager.cpp
  3. * \brief Texture registry
  4. *
  5. * \author Mongoose
  6. * \author xythobuz
  7. */
  8. #include "imgui/imgui.h"
  9. #include "stb/stb_image.h"
  10. #include "global.h"
  11. #include "Game.h"
  12. #include "Log.h"
  13. #include "RunTime.h"
  14. #include "World.h"
  15. #include "utils/Folder.h"
  16. #include "utils/pcx.h"
  17. #include "utils/pixel.h"
  18. #include "utils/random.h"
  19. #include "utils/strings.h"
  20. #include "TextureManager.h"
  21. glm::vec2 TextureTile::getUV(unsigned int i) {
  22. glm::vec2 uv(vertices.at(i).xPixel,
  23. vertices.at(i).yPixel);
  24. /*! \fixme
  25. * This is my somewhat hacky approach to fixing
  26. * the bad texture-bleeding problems everywhere.
  27. * That's better, but makes the seams between
  28. * each sector much more visible!
  29. */
  30. if (vertices.at(i).xCoordinate == 1) {
  31. uv.x += 0.375f;
  32. }
  33. if (vertices.at(i).yCoordinate == 1) {
  34. uv.y += 0.375f;
  35. }
  36. return uv / 256.0f;
  37. }
  38. // ----------------------------------------------------------------------------
  39. std::vector<unsigned int> TextureManager::mTextureIdsGame;
  40. std::vector<unsigned int> TextureManager::mTextureIdsSystem;
  41. std::vector<TextureTile*> TextureManager::tiles;
  42. std::vector<std::vector<int>> TextureManager::animations;
  43. std::vector<int> TextureManager::gameUnits;
  44. std::vector<int> TextureManager::systemUnits;
  45. unsigned int TextureManager::nextFreeTextureUnit = 0;
  46. std::vector<BufferManager> TextureManager::gameBuffers;
  47. std::vector<BufferManager> TextureManager::systemBuffers;
  48. int TextureManager::initialize() {
  49. assertEqual(mTextureIdsGame.size(), 0);
  50. assertEqual(mTextureIdsSystem.size(), 0);
  51. while (mTextureIdsSystem.size() < 2) {
  52. unsigned int id;
  53. glGenTextures(1, &id);
  54. mTextureIdsSystem.push_back(id);
  55. }
  56. unsigned char* image = generateColorTexture(WHITE, 32, 32, 32);
  57. int res = loadBufferSlot(image, 32, 32, ColorMode::RGBA, 32, TextureStorage::SYSTEM, TEXTURE_WHITE,
  58. false);
  59. delete [] image;
  60. if (res < 0) {
  61. return -1;
  62. }
  63. return 0;
  64. }
  65. int TextureManager::initializeSplash() {
  66. Folder f(RunTime::getPakDir());
  67. std::vector<File> files;
  68. f.findRecursiveFilesEndingWith(files, ".pcx");
  69. if (files.size() == 0) {
  70. if (loadImage(RunTime::getDataDir() + "/splash.tga", TextureStorage::SYSTEM, TEXTURE_SPLASH) < 0) {
  71. return -2;
  72. }
  73. } else {
  74. int i = randomInteger(files.size() - 1);
  75. if (loadImage(files.at(i).getPath(), TextureStorage::SYSTEM, TEXTURE_SPLASH) < 0) {
  76. if (loadImage(RunTime::getDataDir() + "/splash.tga", TextureStorage::SYSTEM, TEXTURE_SPLASH) < 0) {
  77. return -3;
  78. }
  79. }
  80. }
  81. return 0;
  82. }
  83. void TextureManager::shutdown() {
  84. while (mTextureIdsSystem.size() > 0) {
  85. unsigned int id = mTextureIdsSystem.at(mTextureIdsSystem.size() - 1);
  86. glDeleteTextures(1, &id);
  87. mTextureIdsSystem.pop_back();
  88. }
  89. gameBuffers.clear();
  90. systemBuffers.clear();
  91. clear();
  92. }
  93. void TextureManager::clear() {
  94. while (mTextureIdsGame.size() > 0) {
  95. unsigned int id = mTextureIdsGame.at(mTextureIdsGame.size() - 1);
  96. glDeleteTextures(1, &id);
  97. mTextureIdsGame.pop_back();
  98. }
  99. while (!tiles.empty()) {
  100. delete tiles.at(tiles.size() - 1);
  101. tiles.pop_back();
  102. }
  103. animations.clear();
  104. gameUnits.clear();
  105. systemUnits.clear();
  106. nextFreeTextureUnit = 0;
  107. }
  108. int TextureManager::loadBufferSlot(unsigned char* image,
  109. unsigned int width, unsigned int height,
  110. ColorMode mode, unsigned int bpp,
  111. TextureStorage s, int slot, bool filter) {
  112. assertGreaterThan(width, 0);
  113. assertGreaterThan(height, 0);
  114. assert((mode == ColorMode::RGB)
  115. || (mode == ColorMode::BGR)
  116. || (mode == ColorMode::ARGB)
  117. || (mode == ColorMode::RGBA)
  118. || (mode == ColorMode::BGRA));
  119. assert((bpp == 8) || (bpp == 24) || (bpp == 32));
  120. if (slot < 0)
  121. slot = getIds(s).size();
  122. while (getIds(s).size() <= slot) {
  123. unsigned int id;
  124. glGenTextures(1, &id);
  125. getIds(s).push_back(id);
  126. }
  127. unsigned int glcMode;
  128. switch (mode) {
  129. case ColorMode::BGR:
  130. glcMode = GL_BGR;
  131. break;
  132. case ColorMode::RGB:
  133. glcMode = GL_RGB;
  134. break;
  135. case ColorMode::ARGB:
  136. if (image != nullptr)
  137. argb2rgba32(image, width, height);
  138. glcMode = GL_RGBA;
  139. break;
  140. case ColorMode::BGRA:
  141. glcMode = GL_BGRA;
  142. break;
  143. case ColorMode::RGBA:
  144. glcMode = GL_RGBA;
  145. break;
  146. }
  147. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  148. bindTexture(slot, s);
  149. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, glcMode, GL_UNSIGNED_BYTE, image);
  150. if (filter) {
  151. // Trilinear filtering
  152. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  153. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  154. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  155. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  156. glGenerateMipmap(GL_TEXTURE_2D);
  157. } else {
  158. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  159. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  160. }
  161. return slot;
  162. }
  163. int TextureManager::numTextures(TextureStorage s) {
  164. return getIds(s).size();
  165. }
  166. void TextureManager::bindTextureId(unsigned int n, TextureStorage s, unsigned int unit) {
  167. assertLessThan(n, getIds(s).size());
  168. assertLessThan(unit, 80); //! \todo Query GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
  169. glActiveTexture(GL_TEXTURE0 + unit);
  170. glBindTexture(GL_TEXTURE_2D, getIds(s).at(n));
  171. }
  172. int TextureManager::bindTexture(unsigned int n, TextureStorage s) {
  173. assertLessThan(n, getIds(s).size());
  174. if ((n < getUnits(s).size()) && (getUnits(s).at(n) >= 0)) {
  175. bindTextureId(n, s, getUnits(s).at(n));
  176. return getUnits(s).at(n);
  177. } else {
  178. while (getUnits(s).size() <= n)
  179. getUnits(s).push_back(-1);
  180. getUnits(s).at(n) = nextFreeTextureUnit;
  181. bindTextureId(n, s, nextFreeTextureUnit);
  182. nextFreeTextureUnit++;
  183. return nextFreeTextureUnit - 1;
  184. }
  185. }
  186. unsigned int TextureManager::getTextureID(int n, TextureStorage s) {
  187. assertLessThan(n, getIds(s).size());
  188. return getIds(s).at(n);
  189. }
  190. void TextureManager::addTile(TextureTile* t) {
  191. tiles.push_back(t);
  192. }
  193. int TextureManager::numTiles() {
  194. return tiles.size();
  195. }
  196. TextureTile& TextureManager::getTile(int index) {
  197. assertGreaterThanEqual(index, 0);
  198. assertLessThan(index, tiles.size());
  199. return *tiles.at(index);
  200. }
  201. void TextureManager::addAnimatedTile(int index, int tile) {
  202. while (index >= animations.size())
  203. animations.push_back(std::vector<int>());
  204. animations.at(index).push_back(tile);
  205. }
  206. int TextureManager::numAnimatedTiles() {
  207. return animations.size();
  208. }
  209. int TextureManager::getFirstTileAnimation(int index) {
  210. assertLessThan(index, animations.size());
  211. assertGreaterThan(animations.at(index).size(), 0);
  212. return animations.at(index).at(0);
  213. }
  214. int TextureManager::getNextTileAnimation(int index, int tile) {
  215. assertLessThan(index, animations.size());
  216. for (int i = 0; i < animations.at(index).size(); i++) {
  217. if (animations.at(index).at(i) == tile) {
  218. if (i < (animations.at(index).size() - 1))
  219. return animations.at(index).at(i + 1);
  220. else
  221. return animations.at(index).at(0);
  222. }
  223. }
  224. return -1;
  225. }
  226. BufferManager* TextureManager::getBufferManager(int tex, TextureStorage store) {
  227. auto& v = (store == TextureStorage::GAME) ? gameBuffers : systemBuffers;
  228. while (v.size() <= (tex + 1)) {
  229. v.emplace_back(v.size(), store);
  230. }
  231. return &(v.at(tex));
  232. }
  233. int TextureManager::loadImage(std::string filename, TextureStorage s, int slot) {
  234. if (stringEndsWith(filename, ".pcx")) {
  235. return loadPCX(filename, s, slot);
  236. } else {
  237. int x, y, n;
  238. unsigned char* data = stbi_load(filename.c_str(), &x, &y, &n, 0);
  239. if (data) {
  240. if ((n < 3) || (n > 4)) {
  241. Log::get(LOG_ERROR) << "Image \"" << filename << "\" has unsupported format ("
  242. << n << ")!" << Log::endl;
  243. stbi_image_free(data);
  244. return -2;
  245. }
  246. int id = loadBufferSlot(data, x, y, (n == 3) ? ColorMode::RGB : ColorMode::RGBA,
  247. (n == 3) ? 24 : 32, s, slot);
  248. stbi_image_free(data);
  249. return id;
  250. } else {
  251. Log::get(LOG_ERROR) << "Can't load image \"" << filename << "\"!" << Log::endl;
  252. return -1;
  253. }
  254. }
  255. }
  256. int TextureManager::loadPCX(std::string filename, TextureStorage s, int slot) {
  257. int error = pcxCheck(filename.c_str());
  258. if (!error) {
  259. unsigned char* image;
  260. unsigned int w, h, bpp;
  261. ColorMode c;
  262. error = pcxLoad(filename.c_str(), &image, &w, &h, &c, &bpp);
  263. if (!error) {
  264. unsigned char* image2 = scaleBuffer(image, &w, &h, bpp);
  265. if (image2) {
  266. delete [] image;
  267. image = image2;
  268. }
  269. int id = loadBufferSlot(image, w, h, c, bpp, s, slot);
  270. delete [] image;
  271. return id;
  272. }
  273. return -5;
  274. }
  275. return -4;
  276. }
  277. std::vector<unsigned int>& TextureManager::getIds(TextureStorage s) {
  278. if (s == TextureStorage::GAME)
  279. return mTextureIdsGame;
  280. else
  281. return mTextureIdsSystem;
  282. }
  283. std::vector<int>& TextureManager::getUnits(TextureStorage s) {
  284. if (s == TextureStorage::GAME)
  285. return gameUnits;
  286. else
  287. return systemUnits;
  288. }
  289. void TextureManager::display() {
  290. if (ImGui::CollapsingHeader("Texture Viewer")) {
  291. static bool game = Game::isLoaded();
  292. static int index = 0;
  293. ImGui::SliderInt("##texslide", &index, 0, TextureManager::numTextures(
  294. game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1);
  295. ImGui::SameLine();
  296. if (ImGui::Button("+##texplus", ImVec2(0, 0), true)) {
  297. if (index < (numTextures(
  298. game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1))
  299. index++;
  300. else
  301. index = 0;
  302. }
  303. ImGui::SameLine();
  304. if (ImGui::Button("-##texminus", ImVec2(0, 0), true)) {
  305. if (index > 0)
  306. index--;
  307. else
  308. index = numTextures(
  309. game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1;
  310. }
  311. if ((numTextures(TextureStorage::GAME) > 0)) {
  312. ImGui::SameLine();
  313. ImGui::Checkbox("Game##texgame", &game);
  314. } else {
  315. game = false;
  316. }
  317. if (index >= numTextures(game ? TextureStorage::GAME : TextureStorage::SYSTEM)) {
  318. index = numTextures(game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1;
  319. if (index < 0) {
  320. game = false;
  321. index = 0;
  322. }
  323. }
  324. auto bm = getBufferManager(index, game ? TextureStorage::GAME
  325. : TextureStorage::SYSTEM);
  326. ImGui::Image(bm, ImVec2(ImGui::GetColumnWidth() * 2 / 3, ImGui::GetColumnWidth() * 2 / 3));
  327. }
  328. if (ImGui::CollapsingHeader("Textile Viewer")) {
  329. if (numTiles() > 0) {
  330. static int index = 0;
  331. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  332. ImGui::SliderInt("##tileslide", &index, 0, numTiles() - 1);
  333. ImGui::PopItemWidth();
  334. ImGui::SameLine();
  335. if (ImGui::Button("+##tileplus", ImVec2(0, 0), true)) {
  336. if (index < (numTiles() - 1))
  337. index++;
  338. else
  339. index = 0;
  340. }
  341. ImGui::SameLine();
  342. if (ImGui::Button("-##tileminus", ImVec2(0, 0), true)) {
  343. if (index > 0)
  344. index--;
  345. else
  346. index = numTiles() - 1;
  347. }
  348. if (index >= numTiles())
  349. index = 0;
  350. auto& tile = getTile(index);
  351. auto bm = getBufferManager(tile.getTexture(), TextureStorage::GAME);
  352. ImVec2 size(ImGui::GetColumnWidth() * 2 / 3, ImGui::GetColumnWidth() * 2 / 3);
  353. auto uvA = tile.getUV(0);
  354. auto uvB = tile.getUV(2);
  355. ImVec2 uv1(uvA.x, uvA.y);
  356. ImVec2 uv2(uvB.x, uvB.y);
  357. ImGui::Image(bm, size, uv1, uv2);
  358. } else {
  359. ImGui::Text("No textiles are currently loaded...!");
  360. }
  361. }
  362. if (ImGui::CollapsingHeader("Animated Textile Viewer")) {
  363. if (numAnimatedTiles() > 0) {
  364. static int index = 0;
  365. static int tile = getFirstTileAnimation(index);
  366. if (ImGui::SliderInt("##animslide", &index, 0, numAnimatedTiles() - 1)) {
  367. tile = getFirstTileAnimation(index);
  368. }
  369. ImGui::SameLine();
  370. if (ImGui::Button("+##animplus", ImVec2(0, 0), true)) {
  371. if (index < (numAnimatedTiles() - 1))
  372. index++;
  373. else
  374. index = 0;
  375. tile = getFirstTileAnimation(index);
  376. }
  377. ImGui::SameLine();
  378. if (ImGui::Button("-##animminus", ImVec2(0, 0), true)) {
  379. if (index > 0)
  380. index--;
  381. else
  382. index = numAnimatedTiles() - 1;
  383. tile = getFirstTileAnimation(index);
  384. }
  385. if (index >= numAnimatedTiles()) {
  386. index = 0;
  387. tile = getFirstTileAnimation(index);
  388. }
  389. int next = getNextTileAnimation(index, tile);
  390. if (next == -1) {
  391. index = 0;
  392. tile = getFirstTileAnimation(index);
  393. }
  394. ImGui::SameLine();
  395. ImGui::Text("%d", tile);
  396. auto& t = getTile(tile);
  397. auto bm = getBufferManager(t.getTexture(), TextureStorage::GAME);
  398. ImVec2 size(ImGui::GetColumnWidth() * 2 / 3, ImGui::GetColumnWidth() * 2 / 3);
  399. auto uvA = t.getUV(0);
  400. auto uvB = t.getUV(2);
  401. ImVec2 uv1(uvA.x, uvA.y);
  402. ImVec2 uv2(uvB.x, uvB.y);
  403. ImGui::Image(bm, size, uv1, uv2);
  404. static int fr = 0;
  405. if (fr > 0) {
  406. fr--;
  407. } else {
  408. fr = RunTime::getFPS() / 5;
  409. tile = next;
  410. }
  411. } else {
  412. ImGui::Text("No animated textures are currently loaded...!");
  413. }
  414. }
  415. if (ImGui::CollapsingHeader("Sprite Sequence Viewer")) {
  416. if (getWorld().sizeSprite() <= 0) {
  417. ImGui::Text("Please load a level containing sprites!");
  418. } else {
  419. static int index = 0;
  420. static int sprite = 0;
  421. if (ImGui::SliderInt("##spriteslide", &index, 0, getWorld().sizeSpriteSequence() - 1)) {
  422. sprite = 0;
  423. }
  424. ImGui::SameLine();
  425. if (ImGui::Button("+##spriteplus", ImVec2(0, 0), true)) {
  426. if (index < (getWorld().sizeSpriteSequence() - 1))
  427. index++;
  428. else
  429. index = 0;
  430. sprite = 0;
  431. }
  432. ImGui::SameLine();
  433. if (ImGui::Button("-##spriteminus", ImVec2(0, 0), true)) {
  434. if (index > 0)
  435. index--;
  436. else
  437. index = getWorld().sizeSpriteSequence() - 1;
  438. sprite = 0;
  439. }
  440. if (index >= getWorld().sizeSpriteSequence()) {
  441. index = 0;
  442. sprite = 0;
  443. }
  444. if (sprite >= getWorld().getSpriteSequence(index).size()) {
  445. sprite = 0;
  446. }
  447. ImGui::SameLine();
  448. ImGui::Text("Sprite %d/%d", sprite + 1, getWorld().getSpriteSequence(index).size());
  449. auto& s = getWorld().getSprite(getWorld().getSpriteSequence(index).getStart() + sprite);
  450. auto bm = getBufferManager(s.getTexture(), TextureStorage::GAME);
  451. ImVec2 size(ImGui::GetColumnWidth() * 2 / 3, ImGui::GetColumnWidth() * 2 / 3);
  452. auto uv = s.getUVs();
  453. ImVec2 uv1(uv.x, uv.w);
  454. ImVec2 uv2(uv.z, uv.y);
  455. ImGui::Image(bm, size, uv1, uv2);
  456. static int fr = 0;
  457. if (fr > 0) {
  458. fr--;
  459. } else {
  460. fr = RunTime::getFPS() / 10;
  461. if (sprite < (getWorld().getSpriteSequence(index).size() - 1))
  462. sprite++;
  463. else
  464. sprite = 0;
  465. }
  466. }
  467. }
  468. }