bool create_compressed_texture(const crn_comp_params ¶ms, const crn_mipmap_params &mipmap_params, crnlib::vector<uint8> &comp_data, uint32 *pActual_quality_level, float *pActual_bitrate) { comp_data.resize(0); if (pActual_bitrate) *pActual_bitrate = 0.0f; if (pActual_quality_level) *pActual_quality_level = 0; dds_texture work_tex; if (!create_dds_tex(params, work_tex)) { console::error(L"Failed creating DDS texture from crn_comp_params!"); return false; } if (!create_texture_mipmaps(work_tex, params, mipmap_params, true)) return false; crn_comp_params new_params(params); new_params.m_levels = work_tex.get_num_levels(); memset(new_params.m_pImages, 0, sizeof(new_params.m_pImages)); for (uint f = 0; f < work_tex.get_num_faces(); f++) for (uint l = 0; l < work_tex.get_num_levels(); l++) new_params.m_pImages[f][l] = (uint32*)work_tex.get_level(f, l)->get_image()->get_ptr(); return create_compressed_texture(new_params, comp_data, pActual_quality_level, pActual_bitrate); }
static bool param_more(uint8_t seq, uint8_t limit, const uint8_t *payload) { switch (limit-seq) { default: hash_merge(payload, PAYLOAD); break; case 1: hash_end(); failed = !hash_eq(payload, PAYLOAD, 0); break; case 0: if (!hash_eq(payload, PAYLOAD, PAYLOAD)) failed = 1; if (failed) return 0; new_params(); break; } return 1; }
bool create_texture_mipmaps(dds_texture &work_tex, const crn_comp_params ¶ms, const crn_mipmap_params &mipmap_params, bool generate_mipmaps) { crn_comp_params new_params(params); bool generate_new_mips = false; switch (mipmap_params.m_mode) { case cCRNMipModeUseSourceOrGenerateMips: { if (work_tex.get_num_levels() == 1) generate_new_mips = true; break; } case cCRNMipModeUseSourceMips: { break; } case cCRNMipModeGenerateMips: { generate_new_mips = true; break; } case cCRNMipModeNoMips: { work_tex.discard_mipmaps(); break; } default: { CRNLIB_ASSERT(0); break; } } rect window_rect(mipmap_params.m_window_left, mipmap_params.m_window_top, mipmap_params.m_window_right, mipmap_params.m_window_bottom); if (!window_rect.is_empty()) { if (work_tex.get_num_faces() > 1) { console::warning(L"Can't crop cubemap textures"); } else { console::info(L"Cropping input texture from window (%ux%u)-(%ux%u)", window_rect.get_left(), window_rect.get_top(), window_rect.get_right(), window_rect.get_bottom()); if (!work_tex.crop(window_rect.get_left(), window_rect.get_top(), window_rect.get_width(), window_rect.get_height())) console::warning(L"Failed cropping window rect"); } } int new_width = work_tex.get_width(); int new_height = work_tex.get_height(); if ((mipmap_params.m_clamp_width) && (mipmap_params.m_clamp_height)) { if ((new_width > (int)mipmap_params.m_clamp_width) || (new_height > (int)mipmap_params.m_clamp_height)) { if (!mipmap_params.m_clamp_scale) { if (work_tex.get_num_faces() > 1) { console::warning(L"Can't crop cubemap textures"); } else { new_width = math::minimum<uint>(mipmap_params.m_clamp_width, new_width); new_height = math::minimum<uint>(mipmap_params.m_clamp_height, new_height); console::info(L"Clamping input texture to %ux%u", new_width, new_height); work_tex.crop(0, 0, new_width, new_height); } } } } if (mipmap_params.m_scale_mode != cCRNSMDisabled) { bool is_pow2 = math::is_power_of_2((uint32)new_width) && math::is_power_of_2((uint32)new_height); switch (mipmap_params.m_scale_mode) { case cCRNSMAbsolute: { new_width = (uint)mipmap_params.m_scale_x; new_height = (uint)mipmap_params.m_scale_y; break; } case cCRNSMRelative: { new_width = (uint)(mipmap_params.m_scale_x * new_width + .5f); new_height = (uint)(mipmap_params.m_scale_y * new_height + .5f); break; } case cCRNSMLowerPow2: { if (!is_pow2) math::compute_lower_pow2_dim(new_width, new_height); break; } case cCRNSMNearestPow2: { if (!is_pow2) { int lwidth = new_width; int lheight = new_height; math::compute_lower_pow2_dim(lwidth, lheight); int uwidth = new_width; int uheight = new_height; math::compute_upper_pow2_dim(uwidth, uheight); if (labs(new_width - lwidth) < labs(new_width - uwidth)) new_width = lwidth; else new_width = uwidth; if (labs(new_height - lheight) < labs(new_height - uheight)) new_height = lheight; else new_height = uheight; } break; } case cCRNSMNextPow2: { if (!is_pow2) math::compute_upper_pow2_dim(new_width, new_height); break; } default: break; } } if ((mipmap_params.m_clamp_width) && (mipmap_params.m_clamp_height)) { if ((new_width > (int)mipmap_params.m_clamp_width) || (new_height > (int)mipmap_params.m_clamp_height)) { if (mipmap_params.m_clamp_scale) { new_width = math::minimum<uint>(mipmap_params.m_clamp_width, new_width); new_height = math::minimum<uint>(mipmap_params.m_clamp_height, new_height); } } } new_width = math::clamp<int>(new_width, 1, cCRNMaxLevelResolution); new_height = math::clamp<int>(new_height, 1, cCRNMaxLevelResolution); if ((new_width != (int)work_tex.get_width()) || (new_height != (int)work_tex.get_height())) { console::info(L"Resampling input texture to %ux%u", new_width, new_height); const char* pFilter = crn_get_mip_filter_name(mipmap_params.m_filter); bool srgb = mipmap_params.m_gamma_filtering != 0; dds_texture::resample_params res_params; res_params.m_pFilter = pFilter; res_params.m_wrapping = mipmap_params.m_tiled != 0; if (work_tex.get_num_faces()) res_params.m_wrapping = false; res_params.m_renormalize = mipmap_params.m_renormalize != 0; res_params.m_filter_scale = 1.0f; res_params.m_gamma = mipmap_params.m_gamma; res_params.m_srgb = srgb; res_params.m_multithreaded = (params.m_num_helper_threads > 0); if (!work_tex.resize(new_width, new_height, res_params)) { console::error(L"Failed resizing texture!"); return false; } } if ((generate_new_mips) && (generate_mipmaps)) { bool srgb = mipmap_params.m_gamma_filtering != 0; const char* pFilter = crn_get_mip_filter_name(mipmap_params.m_filter); dds_texture::generate_mipmap_params gen_params; gen_params.m_pFilter = pFilter; gen_params.m_wrapping = mipmap_params.m_tiled != 0; gen_params.m_renormalize = mipmap_params.m_renormalize != 0; gen_params.m_filter_scale = mipmap_params.m_blurriness; gen_params.m_gamma = mipmap_params.m_gamma; gen_params.m_srgb = srgb; gen_params.m_multithreaded = params.m_num_helper_threads > 0; gen_params.m_max_mips = mipmap_params.m_max_levels; gen_params.m_min_mip_size = mipmap_params.m_min_mip_size; console::info(L"Generating mipmaps using filter \"%S\"", pFilter); timer tm; tm.start(); if (!work_tex.generate_mipmaps(gen_params, true)) { console::error(L"Failed generating mipmaps!"); return false; } double t = tm.get_elapsed_secs(); console::info(L"Generated %u mipmap levels in %3.3fs", work_tex.get_num_levels() - 1, t); } return true; }