crn_dds_comp.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // File: crn_dds_comp.cpp
  2. // See Copyright Notice and license at the end of inc/crnlib.h
  3. #include "crn_core.h"
  4. #include "crn_dds_comp.h"
  5. #include "crn_dynamic_stream.h"
  6. #include "crn_lzma_codec.h"
  7. namespace crnlib
  8. {
  9. dds_comp::dds_comp() :
  10. m_pParams(NULL),
  11. m_pixel_fmt(PIXEL_FMT_INVALID),
  12. m_pQDXT_state(NULL)
  13. {
  14. }
  15. dds_comp::~dds_comp()
  16. {
  17. crnlib_delete(m_pQDXT_state);
  18. }
  19. void dds_comp::clear()
  20. {
  21. m_src_tex.clear();
  22. m_packed_tex.clear();
  23. m_comp_data.clear();
  24. m_pParams = NULL;
  25. m_pixel_fmt = PIXEL_FMT_INVALID;
  26. m_task_pool.deinit();
  27. if (m_pQDXT_state)
  28. {
  29. crnlib_delete(m_pQDXT_state);
  30. m_pQDXT_state = NULL;
  31. }
  32. }
  33. bool dds_comp::create_dds_tex(mipmapped_texture &dds_tex)
  34. {
  35. image_u8 images[cCRNMaxFaces][cCRNMaxLevels];
  36. bool has_alpha = false;
  37. for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
  38. {
  39. for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
  40. {
  41. const uint width = math::maximum(1U, m_pParams->m_width >> level_index);
  42. const uint height = math::maximum(1U, m_pParams->m_height >> level_index);
  43. if (!m_pParams->m_pImages[face_index][level_index])
  44. return false;
  45. images[face_index][level_index].alias((color_quad_u8*)m_pParams->m_pImages[face_index][level_index], width, height);
  46. if (!has_alpha)
  47. has_alpha = image_utils::has_alpha(images[face_index][level_index]);
  48. }
  49. }
  50. for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
  51. for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
  52. images[face_index][level_index].set_component_valid(3, has_alpha);
  53. image_utils::conversion_type conv_type = image_utils::get_image_conversion_type_from_crn_format((crn_format)m_pParams->m_format);
  54. if (conv_type != image_utils::cConversion_Invalid)
  55. {
  56. for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
  57. {
  58. for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
  59. {
  60. image_u8 cooked_image(images[face_index][level_index]);
  61. image_utils::convert_image(cooked_image, conv_type);
  62. images[face_index][level_index].swap(cooked_image);
  63. }
  64. }
  65. }
  66. face_vec faces(m_pParams->m_faces);
  67. for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
  68. {
  69. for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
  70. {
  71. mip_level *pMip = crnlib_new<mip_level>();
  72. image_u8 *pImage = crnlib_new<image_u8>();
  73. pImage->swap(images[face_index][level_index]);
  74. pMip->assign(pImage);
  75. faces[face_index].push_back(pMip);
  76. }
  77. }
  78. dds_tex.assign(faces);
  79. #ifdef CRNLIB_BUILD_DEBUG
  80. CRNLIB_ASSERT(dds_tex.check());
  81. #endif
  82. return true;
  83. }
  84. static bool progress_callback_func(uint percentage_complete, void* pUser_data_ptr)
  85. {
  86. const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
  87. return params.m_pProgress_func(0, 1, percentage_complete, 100, params.m_pProgress_func_data) != 0;
  88. }
  89. static bool progress_callback_func_phase_0(uint percentage_complete, void* pUser_data_ptr)
  90. {
  91. const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
  92. return params.m_pProgress_func(0, 2, percentage_complete, 100, params.m_pProgress_func_data) != 0;
  93. }
  94. static bool progress_callback_func_phase_1(uint percentage_complete, void* pUser_data_ptr)
  95. {
  96. const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
  97. return params.m_pProgress_func(1, 2, percentage_complete, 100, params.m_pProgress_func_data) != 0;
  98. }
  99. bool dds_comp::convert_to_dxt(const crn_comp_params& params)
  100. {
  101. if ((params.m_quality_level == cCRNMaxQualityLevel) || (params.m_format == cCRNFmtDXT3))
  102. {
  103. m_packed_tex = m_src_tex;
  104. if (!m_packed_tex.convert(m_pixel_fmt, false, m_pack_params))
  105. return false;
  106. }
  107. else
  108. {
  109. const bool hierarchical = (params.m_flags & cCRNCompFlagHierarchical) != 0;
  110. m_q1_params.m_quality_level = params.m_quality_level;
  111. m_q1_params.m_hierarchical = hierarchical;
  112. m_q5_params.m_quality_level = params.m_quality_level;
  113. m_q5_params.m_hierarchical = hierarchical;
  114. if (!m_pQDXT_state)
  115. {
  116. m_pQDXT_state = crnlib_new<mipmapped_texture::qdxt_state>(m_task_pool);
  117. if (params.m_pProgress_func)
  118. {
  119. m_q1_params.m_pProgress_func = progress_callback_func_phase_0;
  120. m_q1_params.m_pProgress_data = (void*)&params;
  121. m_q5_params.m_pProgress_func = progress_callback_func_phase_0;
  122. m_q5_params.m_pProgress_data = (void*)&params;
  123. }
  124. if (!m_src_tex.qdxt_pack_init(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params, m_pixel_fmt, false))
  125. return false;
  126. if (params.m_pProgress_func)
  127. {
  128. m_q1_params.m_pProgress_func = progress_callback_func_phase_1;
  129. m_q5_params.m_pProgress_func = progress_callback_func_phase_1;
  130. }
  131. }
  132. else
  133. {
  134. if (params.m_pProgress_func)
  135. {
  136. m_q1_params.m_pProgress_func = progress_callback_func;
  137. m_q1_params.m_pProgress_data = (void*)&params;
  138. m_q5_params.m_pProgress_func = progress_callback_func;
  139. m_q5_params.m_pProgress_data = (void*)&params;
  140. }
  141. }
  142. if (!m_src_tex.qdxt_pack(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params))
  143. return false;
  144. }
  145. return true;
  146. }
  147. bool dds_comp::compress_init(const crn_comp_params& params)
  148. {
  149. clear();
  150. m_pParams = &params;
  151. if ((math::minimum(m_pParams->m_width, m_pParams->m_height) < 1) || (math::maximum(m_pParams->m_width, m_pParams->m_height) > cCRNMaxLevelResolution))
  152. return false;
  153. if (math::minimum(m_pParams->m_faces, m_pParams->m_levels) < 1)
  154. return false;
  155. if (!create_dds_tex(m_src_tex))
  156. return false;
  157. m_pack_params.init(*m_pParams);
  158. if (params.m_pProgress_func)
  159. {
  160. m_pack_params.m_pProgress_callback = progress_callback_func;
  161. m_pack_params.m_pProgress_callback_user_data_ptr = (void*)&params;
  162. }
  163. m_pixel_fmt = pixel_format_helpers::convert_crn_format_to_pixel_format(static_cast<crn_format>(m_pParams->m_format));
  164. if (m_pixel_fmt == PIXEL_FMT_INVALID)
  165. return false;
  166. if ((m_pixel_fmt == PIXEL_FMT_DXT1) && (m_src_tex.has_alpha()) && (m_pack_params.m_use_both_block_types) && (m_pParams->m_flags & cCRNCompFlagDXT1AForTransparency))
  167. m_pixel_fmt = PIXEL_FMT_DXT1A;
  168. if (!m_task_pool.init(m_pParams->m_num_helper_threads))
  169. return false;
  170. m_pack_params.m_pTask_pool = &m_task_pool;
  171. const bool hierarchical = (params.m_flags & cCRNCompFlagHierarchical) != 0;
  172. m_q1_params.init(m_pack_params, params.m_quality_level, hierarchical);
  173. m_q5_params.init(m_pack_params, params.m_quality_level, hierarchical);
  174. return true;
  175. }
  176. bool dds_comp::compress_pass(const crn_comp_params& params, float *pEffective_bitrate)
  177. {
  178. if (pEffective_bitrate) *pEffective_bitrate = 0.0f;
  179. if (!m_pParams)
  180. return false;
  181. if (!convert_to_dxt(params))
  182. return false;
  183. dynamic_stream out_stream;
  184. out_stream.reserve(512*1024);
  185. data_stream_serializer serializer(out_stream);
  186. if (!m_packed_tex.write_dds(serializer))
  187. return false;
  188. out_stream.reserve(0);
  189. m_comp_data.swap(out_stream.get_buf());
  190. if (pEffective_bitrate)
  191. {
  192. lzma_codec lossless_codec;
  193. crnlib::vector<uint8> cmp_tex_bytes;
  194. if (lossless_codec.pack(m_comp_data.get_ptr(), m_comp_data.size(), cmp_tex_bytes))
  195. {
  196. uint comp_size = cmp_tex_bytes.size();
  197. if (comp_size)
  198. {
  199. *pEffective_bitrate = (comp_size * 8.0f) / m_src_tex.get_total_pixels_in_all_faces_and_mips();
  200. }
  201. }
  202. }
  203. return true;
  204. }
  205. void dds_comp::compress_deinit()
  206. {
  207. clear();
  208. }
  209. } // namespace crnlib