void* crnlib_malloc(size_t size, size_t* pActual_size) { size = (size + sizeof(uint32) - 1U) & ~(sizeof(uint32) - 1U); if (!size) size = sizeof(uint32); if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE) { crnlib_mem_error("crnlib_malloc: size too big"); return NULL; } size_t actual_size = size; uint8* p_new = static_cast<uint8*>((*g_pRealloc)(NULL, size, &actual_size, true, g_pUser_data)); if (pActual_size) *pActual_size = actual_size; if ((!p_new) || (actual_size < size)) { crnlib_mem_error("crnlib_malloc: out of memory"); return NULL; } CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0); #if CRNLIB_MEM_STATS CRNLIB_ASSERT((*g_pMSize)(p_new, g_pUser_data) == actual_size); update_total_allocated(1, static_cast<mem_stat_t>(actual_size)); #endif return p_new; }
bool task_pool::init(uint num_threads) { CRNLIB_ASSERT(num_threads <= cMaxThreads); num_threads = math::minimum<uint>(num_threads, cMaxThreads); deinit(); m_task_condition_var.lock(); m_num_threads = num_threads; bool succeeded = true; for (uint i = 0; i < num_threads; i++) { m_threads[i] = (HANDLE)_beginthreadex(NULL, 32768, thread_func, this, 0, NULL); CRNLIB_ASSERT(m_threads[i] != 0); if (!m_threads[i]) { succeeded = false; break; } } m_task_condition_var.unlock(); if (!succeeded) { deinit(); return false; } return true; }
static mem_stat_t update_total_allocated(int block_delta, mem_stat_t byte_delta) { mem_stat_t cur_total_blocks; for ( ; ; ) { cur_total_blocks = (mem_stat_t)g_total_blocks; mem_stat_t new_total_blocks = static_cast<mem_stat_t>(cur_total_blocks + block_delta); CRNLIB_ASSERT(new_total_blocks >= 0); if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_total_blocks, new_total_blocks, cur_total_blocks) == cur_total_blocks) break; } mem_stat_t cur_total_allocated, new_total_allocated; for ( ; ; ) { cur_total_allocated = g_total_allocated; new_total_allocated = static_cast<mem_stat_t>(cur_total_allocated + byte_delta); CRNLIB_ASSERT(new_total_allocated >= 0); if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_total_allocated, new_total_allocated, cur_total_allocated) == cur_total_allocated) break; } for ( ; ; ) { mem_stat_t cur_max_allocated = g_max_allocated; mem_stat_t new_max_allocated = CRNLIB_MAX(new_total_allocated, cur_max_allocated); if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_max_allocated, new_max_allocated, cur_max_allocated) == cur_max_allocated) break; } return new_total_allocated; }
static void* crnlib_default_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data) { pUser_data; void* p_new; if (!p) { p_new = ::malloc(size); CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 ); if (pActual_size) *pActual_size = p_new ? ::_msize(p_new) : 0; } else if (!size) { ::free(p); p_new = NULL; if (pActual_size) *pActual_size = 0; } else { void* p_final_block = p; #ifdef WIN32 p_new = ::_expand(p, size); #else p_new = NULL; #endif if (p_new) { CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 ); p_final_block = p_new; } else if (movable) { p_new = ::realloc(p, size); if (p_new) { CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 ); p_final_block = p_new; } } if (pActual_size) *pActual_size = ::_msize(p_final_block); } return p_new; }
bool task_pool::init(uint num_threads) { CRNLIB_ASSERT(num_threads <= cMaxThreads); num_threads = math::minimum<uint>(num_threads, cMaxThreads); deinit(); bool succeeded = true; m_num_threads = 0; while (m_num_threads < num_threads) { int status = pthread_create(&m_threads[m_num_threads], NULL, thread_func, this); if (status) { succeeded = false; break; } m_num_threads++; } if (!succeeded) { deinit(); return false; } return true; }
void task_pool::join() { for ( ; ; ) { m_task_condition_var.lock(); if (!m_tasks.empty()) { task tsk(m_tasks.front()); m_tasks.pop_front(); m_task_condition_var.unlock(); process_task(tsk); } else { int result = m_task_condition_var.wait(join_condition_func, this); result; CRNLIB_ASSERT(result >= 0); m_task_condition_var.unlock(); break; } } }
const wchar_t* texture_file_types::get_extension(format fmt) { CRNLIB_ASSERT(fmt < cNumFileFormats); if (fmt >= cNumFileFormats) return NULL; static const wchar_t* extensions[cNumFileFormats] = { L"tga", L"png", L"jpg", L"jpeg", L"bmp", L"gif", L"tif", L"tiff", L"ppm", L"pgm", L"dds", L"psd", L"jp2", L"crn", L"<clipboard>", L"<dragdrop>" }; return extensions[fmt]; }
void semaphore::release(long releaseCount) { CRNLIB_ASSERT(releaseCount >= 1); int status = 0; #ifdef WIN32 if (1 == releaseCount) status = sem_post(&m_sem); else status = sem_post_multiple(&m_sem, releaseCount); #else while (releaseCount > 0) { status = sem_post(&m_sem); if (status) break; releaseCount--; } #endif if (status) { CRNLIB_FAIL("semaphore: sem_post() or sem_post_multiple() failed"); } }
void* crnlib_realloc(void* p, size_t size, size_t* pActual_size, bool movable) { if ((ptr_bits_t)p & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) { crnlib_mem_error("crnlib_realloc: bad ptr"); return NULL; } if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE) { crnlib_mem_error("crnlib_malloc: size too big"); return NULL; } #if CRNLIB_MEM_STATS size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0; CRNLIB_ASSERT(!p || (cur_size >= sizeof(uint32))); #endif if ((size) && (size < sizeof(uint32))) size = sizeof(uint32); size_t actual_size = size; void* p_new = (*g_pRealloc)(p, size, &actual_size, movable, g_pUser_data); if (pActual_size) *pActual_size = actual_size; CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0); #if CRNLIB_MEM_STATS CRNLIB_ASSERT(!p_new || ((*g_pMSize)(p_new, g_pUser_data) == actual_size)); int num_new_blocks = 0; if (p) { if (!p_new) num_new_blocks = -1; } else if (p_new) { num_new_blocks = 1; } update_total_allocated(num_new_blocks, static_cast<mem_stat_t>(actual_size) - static_cast<mem_stat_t>(cur_size)); #endif return p_new; }
void timer::stop() { CRNLIB_ASSERT(m_started); QueryPerformanceCounter((LARGE_INTEGER*)&m_stop_time); m_stopped = true; }
semaphore::semaphore(long initialCount, long maximumCount, const char* pName) { maximumCount, pName; CRNLIB_ASSERT(maximumCount >= initialCount); if (sem_init(&m_sem, 0, initialCount)) { CRNLIB_FAIL("semaphore: sem_init() failed"); } }
bool command_line_params::is_param(uint index) const { CRNLIB_ASSERT(index < m_params.size()); if (index >= m_params.size()) return false; const dynamic_wstring& w = m_params[index]; if (w.is_empty()) return false; return (w.get_len() >= 2) && ((w[0] == L'-') || (w[0] == L'/')); }
bool task_pool::queue_task(task_callback_func pFunc, uint64 data, void* pData_ptr) { CRNLIB_ASSERT(m_num_threads); CRNLIB_ASSERT(pFunc); task tsk; tsk.m_callback = pFunc; tsk.m_data = data; tsk.m_pData_ptr = pData_ptr; tsk.m_flags = 0; atomic_increment32(&m_total_submitted_tasks); if (!m_task_stack.try_push(tsk)) { atomic_increment32(&m_total_completed_tasks); return false; } m_tasks_available.release(1); return true; }
uint64 timer::get_elapsed_us() const { CRNLIB_ASSERT(m_started); if (!m_started) return 0; uint64 stop_time = m_stop_time; if (!m_stopped) QueryPerformanceCounter((LARGE_INTEGER*)&stop_time); uint64 delta = stop_time - m_start_time; return (delta * 1000000ULL + (g_freq >> 1U)) / g_freq; }
// It's the object's responsibility to delete pObj within the execute_task() method, if needed! bool task_pool::queue_task(executable_task* pObj, uint64 data, void* pData_ptr) { CRNLIB_ASSERT(m_num_threads); CRNLIB_ASSERT(pObj); task tsk; tsk.m_pObj = pObj; tsk.m_data = data; tsk.m_pData_ptr = pData_ptr; tsk.m_flags = cTaskFlagObject; atomic_increment32(&m_total_submitted_tasks); if (!m_task_stack.try_push(tsk)) { atomic_increment32(&m_total_completed_tasks); return false; } m_tasks_available.release(1); return true; }
double timer::get_elapsed_secs() const { CRNLIB_ASSERT(m_started); if (!m_started) return 0; uint64 stop_time = m_stop_time; if (!m_stopped) QueryPerformanceCounter((LARGE_INTEGER*)&stop_time); uint64 delta = stop_time - m_start_time; return delta * g_inv_freq; }
static bool create_dds_tex(const crn_comp_params ¶ms, dds_texture &dds_tex) { image_u8 images[cCRNMaxFaces][cCRNMaxLevels]; bool has_alpha = false; for (uint face_index = 0; face_index < params.m_faces; face_index++) { for (uint level_index = 0; level_index < params.m_levels; level_index++) { const uint width = math::maximum(1U, params.m_width >> level_index); const uint height = math::maximum(1U, params.m_height >> level_index); if (!params.m_pImages[face_index][level_index]) return false; images[face_index][level_index].alias((color_quad_u8*)params.m_pImages[face_index][level_index], width, height); if (!has_alpha) has_alpha = image_utils::has_alpha(images[face_index][level_index]); } } for (uint face_index = 0; face_index < params.m_faces; face_index++) for (uint level_index = 0; level_index < params.m_levels; level_index++) images[face_index][level_index].set_component_valid(3, has_alpha); face_vec faces(params.m_faces); for (uint face_index = 0; face_index < params.m_faces; face_index++) { for (uint level_index = 0; level_index < params.m_levels; level_index++) { mip_level *pMip = crnlib_new<mip_level>(); image_u8 *pImage = crnlib_new<image_u8>(); pImage->swap(images[face_index][level_index]); pMip->assign(pImage); faces[face_index].push_back(pMip); } } dds_tex.assign(faces); #ifdef CRNLIB_BUILD_DEBUG CRNLIB_ASSERT(dds_tex.check()); #endif return true; }
bool command_line_params::parse(const wchar_t* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param) { CRNLIB_ASSERT(n && pParam_desc); dynamic_wstring_array p; if (!split_params(pCmd_line, p)) return 0; if (p.empty()) return 0; if (skip_first_param) p.erase(0U); return parse(p, n, pParam_desc); }
bool command_line_params::is_param(uint index) const { CRNLIB_ASSERT(index < m_params.size()); if (index >= m_params.size()) return false; const dynamic_string& w = m_params[index]; if (w.is_empty()) return false; #if CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS return (w.get_len() >= 2) && ((w[0] == '-') || (w[0] == '/')); #else return (w.get_len() >= 2) && (w[0] == '-'); #endif }
const wchar_t* get_texture_type_desc(texture_type t) { switch (t) { case cTextureTypeUnknown: return L"Unknown"; case cTextureTypeRegularMap: return L"2D map"; case cTextureTypeNormalMap: return L"Normal map"; case cTextureTypeVerticalCrossCubemap: return L"Vertical Cross Cubemap"; case cTextureTypeCubemap: return L"Cubemap"; default: break; } CRNLIB_ASSERT(false); return L"?"; }
// It's the object's responsibility to crnlib_delete pObj within the execute_task() method, if needed! void task_pool::queue_task(executable_task* pObj, uint64 data, void* pData_ptr) { CRNLIB_ASSERT(pObj); m_task_condition_var.lock(); task tsk; tsk.m_pObj = pObj; tsk.m_data = data; tsk.m_pData_ptr = pData_ptr; tsk.m_flags = cTaskFlagObject; m_tasks.push_back(tsk); m_num_outstanding_tasks++; m_task_condition_var.unlock(); }
void semaphore::try_release(long releaseCount) { CRNLIB_ASSERT(releaseCount >= 1); #ifdef WIN32 if (1 == releaseCount) sem_post(&m_sem); else sem_post_multiple(&m_sem, releaseCount); #else while (releaseCount > 0) { sem_post(&m_sem); releaseCount--; } #endif }
void task_pool::queue_task(task_callback_func pFunc, uint64 data, void* pData_ptr) { CRNLIB_ASSERT(pFunc); m_task_condition_var.lock(); task tsk; tsk.m_callback = pFunc; tsk.m_data = data; tsk.m_pData_ptr = pData_ptr; tsk.m_flags = 0; m_tasks.push_back(tsk); m_num_outstanding_tasks++; m_task_condition_var.unlock(); }
void crnlib_free(void* p) { if (!p) return; if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) { crnlib_mem_error("crnlib_free: bad ptr"); return; } #if CRNLIB_MEM_STATS size_t cur_size = (*g_pMSize)(p, g_pUser_data); CRNLIB_ASSERT(cur_size >= sizeof(uint32)); update_total_allocated(-1, -static_cast<mem_stat_t>(cur_size)); #endif (*g_pRealloc)(p, 0, NULL, true, g_pUser_data); }
uint command_line_params::find(uint num_keys, const wchar_t** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const { CRNLIB_ASSERT(ppKeys); if (pUnmatched_indices) { pUnmatched_indices->resize(m_params.size()); for (uint i = 0; i < m_params.size(); i++) (*pUnmatched_indices)[i] = i; } uint n = 0; for (uint i = 0; i < num_keys; i++) { const wchar_t* pKey = ppKeys[i]; param_map_const_iterator begin, end; find(pKey, begin, end); while (begin != end) { if (pIterators) pIterators->push_back(begin); if (pUnmatched_indices) { int k = pUnmatched_indices->find(begin->second.m_index); if (k >= 0) pUnmatched_indices->erase_unordered(k); } n++; begin++; } } return n; }
unsigned __stdcall task_pool::thread_func(void* pContext) { //set_thread_name(GetCurrentThreadId(), "taskpoolhelper"); task_pool* pPool = static_cast<task_pool*>(pContext); for ( ; ; ) { pPool->m_task_condition_var.lock(); int result = pPool->m_task_condition_var.wait(wait_condition_func, pPool); CRNLIB_ASSERT(result >= 0); if ((result < 0) || (pPool->m_exit_flag)) { pPool->m_task_condition_var.unlock(); break; } if (pPool->m_tasks.empty()) pPool->m_task_condition_var.unlock(); else { task tsk(pPool->m_tasks.front()); pPool->m_tasks.pop_front(); pPool->m_task_condition_var.unlock(); pPool->process_task(tsk); } } _endthreadex(0); return 0; }
bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret) { if ((!num_syms) || (num_syms > cHuffmanMaxSupportedSyms)) return false; huffman_work_tables& state = *static_cast<huffman_work_tables*>(pContext);; uint max_freq = 0; uint total_freq = 0; uint num_used_syms = 0; for (uint i = 0; i < num_syms; i++) { uint freq = pFreq[i]; if (!freq) pCodesizes[i] = 0; else { total_freq += freq; max_freq = math::maximum(max_freq, freq); sym_freq& sf = state.syms0[num_used_syms]; sf.m_left = (uint16)i; sf.m_right = cUINT16_MAX; sf.m_freq = freq; num_used_syms++; } } total_freq_ret = total_freq; if (num_used_syms == 1) { pCodesizes[state.syms0[0].m_left] = 1; return true; } sym_freq* syms = radix_sort_syms(num_used_syms, state.syms0, state.syms1); #if USE_CALCULATE_MINIMUM_REDUNDANCY int x[cHuffmanMaxSupportedSyms]; for (uint i = 0; i < num_used_syms; i++) x[i] = state.syms0[i].m_freq; calculate_minimum_redundancy(x, num_used_syms); uint max_len = 0; for (uint i = 0; i < num_used_syms; i++) { uint len = x[i]; max_len = math::maximum(len, max_len); pCodesizes[state.syms0[i].m_left] = static_cast<uint8>(len); } return true; #else // Dummy node sym_freq& sf = state.syms0[num_used_syms]; sf.m_left = cUINT16_MAX; sf.m_right = cUINT16_MAX; sf.m_freq = UINT_MAX; uint next_internal_node = num_used_syms + 1; uint queue_front = 0; uint queue_end = 0; uint next_lowest_sym = 0; uint num_nodes_remaining = num_used_syms; do { uint left_freq = syms[next_lowest_sym].m_freq; uint left_child = next_lowest_sym; if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < left_freq)) { left_child = state.queue[queue_front]; left_freq = syms[left_child].m_freq; queue_front++; } else next_lowest_sym++; uint right_freq = syms[next_lowest_sym].m_freq; uint right_child = next_lowest_sym; if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < right_freq)) { right_child = state.queue[queue_front]; right_freq = syms[right_child].m_freq; queue_front++; } else next_lowest_sym++; const uint internal_node_index = next_internal_node; next_internal_node++; CRNLIB_ASSERT(next_internal_node < CRNLIB_ARRAYSIZE(state.syms0)); syms[internal_node_index].m_freq = left_freq + right_freq; syms[internal_node_index].m_left = static_cast<uint16>(left_child); syms[internal_node_index].m_right = static_cast<uint16>(right_child); CRNLIB_ASSERT(queue_end < huffman_work_tables::cMaxInternalNodes); state.queue[queue_end] = static_cast<uint16>(internal_node_index); queue_end++; num_nodes_remaining--; } while (num_nodes_remaining > 1); CRNLIB_ASSERT(next_lowest_sym == num_used_syms); CRNLIB_ASSERT((queue_end - queue_front) == 1); uint cur_node_index = state.queue[queue_front]; uint32* pStack = (syms == state.syms0) ? (uint32*)state.syms1 : (uint32*)state.syms0; uint32* pStack_top = pStack; uint max_level = 0; for ( ; ; ) { uint level = cur_node_index >> 16; uint node_index = cur_node_index & 0xFFFF; uint left_child = syms[node_index].m_left; uint right_child = syms[node_index].m_right; uint next_level = (cur_node_index + 0x10000) & 0xFFFF0000; if (left_child < num_used_syms) { max_level = math::maximum(max_level, level); pCodesizes[syms[left_child].m_left] = static_cast<uint8>(level + 1); if (right_child < num_used_syms) { pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1); if (pStack == pStack_top) break; cur_node_index = *--pStack; } else { cur_node_index = next_level | right_child; } } else { if (right_child < num_used_syms) { max_level = math::maximum(max_level, level); pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1); cur_node_index = next_level | left_child; } else { *pStack++ = next_level | left_child; cur_node_index = next_level | right_child; } } } max_code_size = max_level + 1; #endif return true; }
bool command_line_params::parse(const dynamic_wstring_array& params, uint n, const param_desc* pParam_desc) { CRNLIB_ASSERT(n && pParam_desc); m_params = params; uint arg_index = 0; while (arg_index < params.size()) { const uint cur_arg_index = arg_index; const dynamic_wstring& src_param = params[arg_index++]; if (src_param.is_empty()) continue; if ((src_param[0] == L'/') || (src_param[0] == L'-')) { if (src_param.get_len() < 2) { console::error(L"Invalid command line parameter: \"%s\"", src_param.get_ptr()); return false; } dynamic_wstring key_str(src_param); key_str.right(1); int modifier = 0; wchar_t c = key_str[key_str.get_len() - 1]; if (c == L'+') modifier = 1; else if (c == L'-') modifier = -1; if (modifier) key_str.left(key_str.get_len() - 1); uint param_index; for (param_index = 0; param_index < n; param_index++) if (key_str == pParam_desc[param_index].m_pName) break; if (param_index == n) { console::error(L"Unrecognized command line parameter: \"%s\"", src_param.get_ptr()); return false; } const param_desc& desc = pParam_desc[param_index]; const uint cMaxValues = 16; dynamic_wstring val_str[cMaxValues]; uint num_val_strs = 0; if (desc.m_num_values) { CRNLIB_ASSERT(desc.m_num_values <= cMaxValues); if ((arg_index + desc.m_num_values) > params.size()) { console::error(L"Expected %u value(s) after command line parameter: \"%s\"", desc.m_num_values, src_param.get_ptr()); return false; } for (uint v = 0; v < desc.m_num_values; v++) val_str[num_val_strs++] = params[arg_index++]; } dynamic_wstring_array strings; if ((desc.m_support_listing_file) && (val_str[0].get_len() >= 2) && (val_str[0][0] == L'@')) { dynamic_wstring filename(val_str[0]); filename.right(1); filename.unquote(); if (!load_string_file(filename.get_ptr(), strings)) { console::error(L"Failed loading listing file \"%s\"!", filename.get_ptr()); return false; } } else { for (uint v = 0; v < num_val_strs; v++) { val_str[v].unquote(); strings.push_back(val_str[v]); } } param_value pv; pv.m_values.swap(strings); pv.m_index = cur_arg_index; pv.m_modifier = (int8)modifier; m_param_map.insert(std::make_pair(key_str, pv)); } else { param_value pv; pv.m_values.push_back(src_param); pv.m_values.back().unquote(); pv.m_index = cur_arg_index; m_param_map.insert(std::make_pair(g_empty_dynamic_wstring, pv)); } } return true; }
bool elemental_vector::increase_capacity(uint min_new_capacity, bool grow_hint, uint element_size, object_mover pMover, bool nofail) { CRNLIB_ASSERT(m_size <= m_capacity); #ifdef CRNLIB_PLATFORM_PC_X64 CRNLIB_ASSERT(min_new_capacity < (0x400000000ULL / element_size)); #else CRNLIB_ASSERT(min_new_capacity < (0x7FFF0000U / element_size)); #endif if (m_capacity >= min_new_capacity) return true; size_t new_capacity = min_new_capacity; if ((grow_hint) && (!math::is_power_of_2(new_capacity))) new_capacity = math::next_pow2(new_capacity); CRNLIB_ASSERT(new_capacity && (new_capacity > m_capacity)); const size_t desired_size = element_size * new_capacity; size_t actual_size; if (!pMover) { void* new_p = crnlib_realloc(m_p, desired_size, &actual_size, true); if (!new_p) { if (nofail) return false; char buf[256]; #ifdef _MSC_VER sprintf_s(buf, sizeof(buf), "vector: crnlib_realloc() failed allocating %u bytes", (uint)desired_size); #else sprintf(buf, "vector: crnlib_realloc() failed allocating %u bytes", (uint)desired_size); #endif CRNLIB_FAIL(buf); } m_p = new_p; } else { void* new_p = crnlib_malloc(desired_size, &actual_size); if (!new_p) { if (nofail) return false; char buf[256]; #ifdef _MSC_VER sprintf_s(buf, sizeof(buf), "vector: crnlib_malloc() failed allocating %u bytes", (uint)desired_size); #else sprintf(buf, "vector: crnlib_malloc() failed allocating %u bytes", (uint)desired_size); #endif CRNLIB_FAIL(buf); } (*pMover)(new_p, m_p, m_size); if (m_p) crnlib_free(m_p); m_p = new_p; } if (actual_size > desired_size) m_capacity = static_cast<uint>(actual_size / element_size); else m_capacity = static_cast<uint>(new_capacity); return true; }
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; }