2
0

LoadTGA.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <TestFramework.h>
  4. #include <Image/LoadTGA.h>
  5. #include <Image/Surface.h>
  6. #pragma pack (1)
  7. struct TGAHeader
  8. {
  9. uint8 mIDLength;
  10. uint8 mColorMapType;
  11. uint8 mImageType;
  12. uint16 mColorMapFirstEntryIndex;
  13. uint16 mColorMapLength;
  14. uint8 mColorMapEntrySize;
  15. uint16 mXOrigin;
  16. uint16 mYOrigin;
  17. uint16 mWidth;
  18. uint16 mHeight;
  19. uint8 mPixelDepth;
  20. uint8 mImageDescriptor;
  21. };
  22. #pragma pack ()
  23. Ref<Surface> LoadTGA(istream &inStream)
  24. {
  25. bool loaded = true;
  26. // Read header
  27. TGAHeader header;
  28. inStream.read((char *)&header, sizeof(header));
  29. if (inStream.fail())
  30. return nullptr;
  31. // Get properties
  32. int bytes_per_pixel = (header.mPixelDepth + 7) >> 3;
  33. int scan_width = bytes_per_pixel * header.mWidth;
  34. // Check type
  35. if (header.mImageType < 1 || header.mImageType > 2)
  36. {
  37. Trace("Not a readable TGA");
  38. return nullptr;
  39. }
  40. // Check compression
  41. if ((header.mImageType == 1 && header.mColorMapType != 1) || (header.mImageType == 2 && header.mColorMapType != 0))
  42. {
  43. Trace("Not an uncompressed TGA");
  44. return nullptr;
  45. }
  46. Ref<Surface> surface;
  47. if (header.mPixelDepth == 8)
  48. {
  49. // Determine pixel format
  50. ESurfaceFormat format;
  51. int pixel_size;
  52. switch (header.mColorMapEntrySize)
  53. {
  54. case 15: format = ESurfaceFormat::X1R5G5B5; pixel_size = 2; break;
  55. case 16: format = ESurfaceFormat::X1R5G5B5; pixel_size = 2; break;
  56. case 24: format = ESurfaceFormat::R8G8B8; pixel_size = 3; break;
  57. case 32: format = ESurfaceFormat::A8R8G8B8; pixel_size = 4; break;
  58. default: Trace("Has invalid format"); return nullptr;
  59. }
  60. // Seek to beginning of palette
  61. inStream.seekg(sizeof(TGAHeader) + header.mIDLength);
  62. // Load palette
  63. int pal_bytes = pixel_size * header.mColorMapLength;
  64. uint8 *palette = new uint8 [pal_bytes];
  65. inStream.read((char *)palette, pal_bytes);
  66. loaded = loaded && !inStream.fail();
  67. // Convert pixel data to a surface
  68. surface = new SoftwareSurface(header.mWidth, header.mHeight, format);
  69. surface->Lock(ESurfaceLockMode::Write);
  70. uint8 *scan_line = new uint8 [scan_width];
  71. for (int y = header.mHeight - 1; y >= 0; --y)
  72. {
  73. // Load one scan line
  74. inStream.read((char *)scan_line, scan_width);
  75. loaded = loaded && !inStream.fail();
  76. // Copy one scan line
  77. uint8 *in_pixel = scan_line;
  78. uint8 *out_pixel = (uint8 *)surface->GetScanLine(y);
  79. for (int x = 0; x < header.mWidth; ++x, ++in_pixel, out_pixel += pixel_size)
  80. memcpy(out_pixel, palette + (*in_pixel - header.mColorMapFirstEntryIndex) * pixel_size, pixel_size);
  81. }
  82. surface->UnLock();
  83. // Release temporaries
  84. delete [] palette;
  85. delete [] scan_line;
  86. }
  87. else
  88. {
  89. // Determine pixel format
  90. ESurfaceFormat format;
  91. switch (header.mPixelDepth)
  92. {
  93. case 15: format = ESurfaceFormat::X1R5G5B5; break;
  94. case 16: format = ESurfaceFormat::X1R5G5B5; break;
  95. case 24: format = ESurfaceFormat::R8G8B8; break;
  96. case 32: format = ESurfaceFormat::A8R8G8B8; break;
  97. default: Trace("Invalid format"); return nullptr;
  98. }
  99. // Convert pixel data to a surface
  100. surface = new SoftwareSurface(header.mWidth, header.mHeight, format, scan_width);
  101. surface->Lock(ESurfaceLockMode::Write);
  102. for (int y = header.mHeight - 1; y >= 0; --y)
  103. {
  104. inStream.read((char *)surface->GetScanLine(y), scan_width);
  105. loaded = loaded && !inStream.fail();
  106. }
  107. surface->UnLock();
  108. }
  109. return loaded? surface : Ref<Surface>(nullptr);
  110. }