Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 31 additions & 20 deletions .azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,60 +29,71 @@ strategy:
VM_IMAGE: 'ubuntu-20.04'
APT_PACKAGES: ninja-build g++-8
CXX_COMPILER: g++-8
RUN_TESTS: true
Linux i686 GCC:
VM_IMAGE: 'ubuntu-20.04'
APT_PACKAGES: ninja-build g++-i686-linux-gnu
CXX_COMPILER: i686-linux-gnu-g++
RUN_TESTS: true
Linux arm64 GCC:
VM_IMAGE: 'ubuntu-20.04'
APT_PACKAGES: ninja-build g++-aarch64-linux-gnu
APT_PACKAGES: ninja-build g++-aarch64-linux-gnu qemu-user
CXX_COMPILER: aarch64-linux-gnu-g++
CRUNCH_EXE_RUNNER: qemu-aarch64 -L /usr/aarch64-linux-gnu
Linux armhf GCC:
VM_IMAGE: 'ubuntu-20.04'
APT_PACKAGES: ninja-build g++-arm-linux-gnueabihf
APT_PACKAGES: ninja-build g++-arm-linux-gnueabihf qemu-user
CXX_COMPILER: arm-linux-gnueabihf-g++
CRUNCH_EXE_RUNNER: qemu-arm -L /usr/arm-linux-gnueabihf
# There is a qemu-arm IO bug in ubuntu-20.04 and ubuntu-22.04,
# remove when ubuntu-24.04 is available.
CRUNCH_SIMPLE_TEST: true
Linux amd64 Clang:
VM_IMAGE: 'ubuntu-20.04'
APT_PACKAGES: ninja-build
CXX_COMPILER: clang++
RUN_TESTS: true
Windows amd64 MinGW:
VM_IMAGE: 'ubuntu-20.04'
APT_PACKAGES: ninja-build g++-mingw-w64-x86-64 mingw-w64-x86-64-dev
VM_IMAGE: 'ubuntu-22.04'
APT_PACKAGES: ninja-build g++-mingw-w64-x86-64 mingw-w64-x86-64-dev gcc-mingw-w64-x86-64-posix-runtime wine
SETUP_COMMANDS: sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
TOOLCHAIN_FILE: cmake/cross-toolchain-mingw64.cmake
EXE_EXTENSIONS: .exe
CRUNCH_EXE_RUNNER: wine
CRUNCH_EXTENSION: .exe
RUNTIME_FILES: /usr/lib/gcc/x86_64-w64-mingw32/10-posix/libgcc_s_seh-1.dll /usr/lib/gcc/x86_64-w64-mingw32/10-posix/libstdc++-6.dll /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll
Windows i686 MinGW:
VM_IMAGE: 'ubuntu-20.04'
APT_PACKAGES: ninja-build g++-mingw-w64-i686 mingw-w64-i686-dev
VM_IMAGE: 'ubuntu-22.04'
APT_ARCHITECTURE: i386
APT_PACKAGES: ninja-build g++-mingw-w64-i686 mingw-w64-i686-dev gcc-mingw-w64-i686-posix-runtime wine wine32
SETUP_COMMANDS: sudo update-alternatives --set i686-w64-mingw32-g++ /usr/bin/i686-w64-mingw32-g++-posix
TOOLCHAIN_FILE: cmake/cross-toolchain-mingw32.cmake
EXE_EXTENSIONS: .exe
CRUNCH_EXE_RUNNER: wine
CRUNCH_EXTENSION: .exe
RUNTIME_FILES: /usr/lib/gcc/i686-w64-mingw32/10-posix/libgcc_s_dw2-1.dll /usr/lib/gcc/i686-w64-mingw32/10-posix/libstdc++-6.dll /usr/i686-w64-mingw32/lib/libwinpthread-1.dll
macOS amd64 AppleClang:
VM_IMAGE: 'macOS-12'
CMAKE_GENERATOR: Unix Makefiles
NPROC_COMMAND: sysctl -n hw.logicalcpu
RUN_TESTS: true
macOS arm64 AppleClang:
VM_IMAGE: 'macOS-12'
CMAKE_GENERATOR: Unix Makefiles
COMPILER_FLAGS: -target arm64-apple-macos11 -Wno-overriding-t-option
NPROC_COMMAND: sysctl -n hw.logicalcpu
RUN_TESTS: false
Web Asm.js Emscripten:
VM_IMAGE: 'ubuntu-22.04'
APT_PACKAGES: ninja-build emscripten
TOOLCHAIN_FILE: /usr/share/emscripten/cmake/Modules/Platform/Emscripten.cmake
SOURCE_DIR: emscripten
EXE_EXTENSIONS: .js .wasm
EXECUTABLES: crunch.js crunch.wasm
RUN_TESTS: false

pool:
vmImage: $(VM_IMAGE)

steps:
- bash: |
set -xue
if [ -n "${APT_ARCHITECTURE:-}" ]; then
sudo dpkg --add-architecture "${APT_ARCHITECTURE}"
fi
if [ -n "${APT_PACKAGES:-}" ]; then
sudo apt-get update && sudo apt-get -y -q --no-install-recommends install ${APT_PACKAGES}
fi
Expand Down Expand Up @@ -112,14 +123,14 @@ steps:
displayName: 'Build'
- bash: |
set -xue
if [ -z "${EXE_EXTENSIONS:-}" ]; then
file 'build/crunch'
else
for ext in ${EXE_EXTENSIONS}; do
file "build/crunch${ext}"
done
EXECUTABLES="${EXECUTABLES:-crunch example1 example2 example3}"
for exe_file in ${EXECUTABLES}; do
file 'build/${exe_file}${CRUNCH_EXTENSION:-}'
done
if [ -n "${RUNTIME_FILES:-}" ]; then
cp -av ${RUNTIME_FILES} build/
fi
if "${RUN_TESTS:-false}"; then
if "${RUN_TESTS:-true}"; then
test/test.py
fi
displayName: 'Test'
2 changes: 1 addition & 1 deletion crnlib/crn_strutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ char* crn_strdup(const char* pStr) {
return p;
}

char* strcpy_safe(char* pDst, uint dst_len, const char* pSrc) {
char* strcpy_safe(char* pDst, size_t dst_len, const char* pSrc) {
CRNLIB_ASSERT(pDst && pSrc && dst_len);
if (!dst_len)
return pDst;
Expand Down
2 changes: 1 addition & 1 deletion crnlib/crn_strutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
namespace crnlib {
char* crn_strdup(const char* pStr);

char* strcpy_safe(char* pDst, uint dst_len, const char* pSrc);
char* strcpy_safe(char* pDst, size_t dst_len, const char* pSrc);

bool int_to_string(int value, char* pDst, uint len);
bool uint_to_string(uint value, char* pDst, uint len);
Expand Down
111 changes: 33 additions & 78 deletions example1/example1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
// .DDS file format definitions.
#include "dds_defs.h"

#include "crn_platform.h"
#include "crn_core.h"
#include "crn_strutils.h"
#include "crn_file_utils.h"

// stb_image, for loading/saving image files.
#ifdef _MSC_VER
Expand Down Expand Up @@ -141,7 +143,7 @@ static bool print_crn_info(const crn_uint8* pData, crn_uint32 data_size) {
if (!crnd::crnd_get_texture_info(pData, data_size, &tex_info))
return false;

printf("Dimensions: %ux%u\nLevels: %u\nFaces: %u\nBytesPerBlock: %u\nUserData0: %u\nUserData1: %u\nCrnFormat: %S\n",
printf("Dimensions: %ux%u\nLevels: %u\nFaces: %u\nBytesPerBlock: %u\nUserData0: %u\nUserData1: %u\nCrnFormat: %s\n",
tex_info.m_width, tex_info.m_height, tex_info.m_levels, tex_info.m_faces, tex_info.m_bytes_per_block, tex_info.m_userdata0, tex_info.m_userdata1, crn_get_format_string(tex_info.m_format));

return true;
Expand Down Expand Up @@ -170,7 +172,7 @@ static bool print_dds_info(const void* pData, crn_uint32 data_size) {
"DDSD_TEXTURESTAGE", "DDSD_FVF", "DDSD_SRCVBHANDLE", "DDSD_DEPTH"};

printf("DDSD Flags: 0x%08X ", desc.dwFlags);
for (int i = 0; i < sizeof(pDDSDFlagNames) / sizeof(pDDSDFlagNames[0]); i++)
for (size_t i = 0; i < sizeof(pDDSDFlagNames) / sizeof(pDDSDFlagNames[0]); i++)
if ((pDDSDFlagNames[i]) && (desc.dwFlags & (1 << i)))
printf("%s ", pDDSDFlagNames[i]);
printf("\n\n");
Expand Down Expand Up @@ -227,7 +229,7 @@ static bool print_dds_info(const void* pData, crn_uint32 data_size) {
"DDSCAPS2_CUBEMAP_POSITIVEY", "DDSCAPS2_CUBEMAP_NEGATIVEY", "DDSCAPS2_CUBEMAP_POSITIVEZ", "DDSCAPS2_CUBEMAP_NEGATIVEZ",
NULL, NULL, NULL, NULL,
NULL, "DDSCAPS2_VOLUME"};
for (int i = 0; i < sizeof(pDDCAPS2FlagNames) / sizeof(pDDCAPS2FlagNames[0]); i++)
for (size_t i = 0; i < sizeof(pDDCAPS2FlagNames) / sizeof(pDDCAPS2FlagNames[0]); i++)
if ((pDDCAPS2FlagNames[i]) && (desc.ddsCaps.dwCaps2 & (1 << i)))
printf("%s ", pDDCAPS2FlagNames[i]);
printf("\n");
Expand Down Expand Up @@ -312,11 +314,7 @@ int main(int argc, char* argv[]) {
if (++i >= argc)
return error("Expected output filename!");

#if defined(_WIN32)
strcpy_s(out_filename, sizeof(out_filename), argv[i]);
#else
strncpy(out_filename, argv[i], sizeof(out_filename));
#endif
strcpy_safe(out_filename, sizeof(out_filename), argv[i]);
} else if (!crnlib_stricmp(argv[i], "-nonsrgb"))
srgb_colorspace = false;
else if (!crnlib_stricmp(argv[i], "-nomips"))
Expand All @@ -332,24 +330,10 @@ int main(int argc, char* argv[]) {
}

// Split the source filename into its various components.
#if defined(_WIN32)
char drive_buf[_MAX_DRIVE], dir_buf[_MAX_DIR], fname_buf[_MAX_FNAME], ext_buf[_MAX_EXT];
if (_splitpath_s(pSrc_filename, drive_buf, _MAX_DRIVE, dir_buf, _MAX_DIR, fname_buf, _MAX_FNAME, ext_buf, _MAX_EXT))
dynamic_string drive, dir, fname, ext;

if (!file_utils::split_path(pSrc_filename, &drive, &dir, &fname, &ext))
return error("Invalid source filename!\n");
#else
char in_filename[FILENAME_MAX];
strncpy(in_filename, pSrc_filename, FILENAME_MAX);
const char drive_buf[] = "";
char *dir_buf = dirname(in_filename);
char *fname_buf = basename(in_filename);
char *dot = strrchr(fname_buf, '.');
char ext_buf[FILENAME_MAX];
ext_buf[0] = '\0';
if (dot && dot != fname_buf) {
strncpy(ext_buf, dot, strlen(dot));
*dot = '\0';
}
#endif

// Load the source file into memory.
printf("Loading source file: %s\n", pSrc_filename);
Expand All @@ -360,12 +344,12 @@ int main(int argc, char* argv[]) {

if (mode == 'i') {
// Information
if (crnlib_stricmp(ext_buf, ".crn") == 0) {
if (crnlib_stricmp(ext.get_ptr(), ".crn") == 0) {
if (!print_crn_info(pSrc_file_data, src_file_size)) {
free(pSrc_file_data);
return error("Not a CRN file!\n");
}
} else if (crnlib_stricmp(ext_buf, ".dds") == 0) {
} else if (crnlib_stricmp(ext.get_ptr(), ".dds") == 0) {
if (!print_dds_info(pSrc_file_data, src_file_size)) {
free(pSrc_file_data);
return error("Not a DDS file!\n");
Expand All @@ -387,22 +371,13 @@ int main(int argc, char* argv[]) {

// If the user has explicitly specified an output file, check the output file's extension to ensure we write the expected format.
if (out_filename[0]) {
#if defined(_WIN32)
char out_fname_buf[_MAX_FNAME], out_ext_buf[_MAX_EXT];
_splitpath_s(out_filename, NULL, 0, NULL, 0, out_fname_buf, _MAX_FNAME, out_ext_buf, _MAX_EXT);
#else
char *out_fname_buf = basename( in_filename );
dot = strrchr(out_fname_buf, '.');
char out_ext_buf[FILENAME_MAX];
out_ext_buf[0] = '\0';
if (dot && dot != fname_buf) {
strncpy(out_ext_buf, dot, strlen(dot));
*dot = '\0';
}
#endif
if (!crnlib_stricmp(out_ext_buf, ".crn"))
dynamic_string out_fname, out_ext;

file_utils::split_path(out_filename, NULL, NULL, &out_fname, &out_ext);

if (!crnlib_stricmp(out_ext.get_ptr(), ".crn"))
output_crn = true;
else if (!crnlib_stricmp(out_ext_buf, ".dds"))
else if (!crnlib_stricmp(out_ext.get_ptr(), ".dds"))
output_crn = false;
}

Expand Down Expand Up @@ -463,17 +438,17 @@ int main(int argc, char* argv[]) {
}

// Determine the # of helper threads (in addition to the main thread) to use during compression. NumberOfCPU's-1 is reasonable.
int num_helper_threads = 1;
int number_of_processors = 1;
#if defined(_WIN32)
SYSTEM_INFO g_system_info;
GetSystemInfo(&g_system_info);
num_helper_threads = std::max<int>(0, (int)g_system_info.dwNumberOfProcessors - 1);
number_of_processors = std::max<int>(1, (int)g_system_info.dwNumberOfProcessors);
#elif defined(__FreeBSD__) || defined(__APPLE__)
num_helper_threads = std::max<int>(1, sysconf(_SC_NPROCESSORS_ONLN));
number_of_processors = std::max<int>(1, sysconf(_SC_NPROCESSORS_ONLN));
#elif defined(__GNUC__)
num_helper_threads = std::max<int>(1, get_nprocs());
number_of_processors = std::max<int>(1, get_nprocs());
#endif
comp_params.m_num_helper_threads = num_helper_threads;
comp_params.m_num_helper_threads = std::min(number_of_processors - 1, (int)cCRNMaxHelperThreads);

comp_params.m_pProgress_func = progress_callback_func;

Expand Down Expand Up @@ -502,17 +477,13 @@ int main(int argc, char* argv[]) {

// Write the output file.
char dst_filename[FILENAME_MAX];
crnlib_snprintf(dst_filename, sizeof(dst_filename), "%s%s%s%s", drive_buf, dir_buf, fname_buf, output_crn ? ".crn" : ".dds");
crnlib_snprintf(dst_filename, sizeof(dst_filename), "%s%s%s%s", drive.get_ptr(), dir.get_ptr(), fname.get_ptr(), output_crn ? ".crn" : ".dds");
if (out_filename[0])
#if defined(_WIN32)
strcpy_s(dst_filename, sizeof(dst_filename), out_filename);
#else
strncpy(dst_filename, out_filename, sizeof(dst_filename));
#endif
strcpy_safe(dst_filename, sizeof(dst_filename), out_filename);

printf("Writing %s file: %s\n", output_crn ? "CRN" : "DDS", dst_filename);
FILE* pFile = NULL;
crn_fopen(&pFile, dst_filename, "wb");
crn_fopen(&pFile, dst_filename, "wb");
if ((!pFile) || (fwrite(pOutput_file_data, output_file_size, 1, pFile) != 1) || (fclose(pFile) == EOF)) {
free(pSrc_file_data);
crn_free_block(pOutput_file_data);
Expand All @@ -522,7 +493,7 @@ int main(int argc, char* argv[]) {

crn_free_block(pOutput_file_data);
stbi_image_free(pSrc_image);
} else if (crnlib_stricmp(ext_buf, ".crn") == 0) {
} else if (crnlib_stricmp(ext.get_ptr(), ".crn") == 0) {
// Decompress/transcode CRN to DDS.
printf("Decompressing CRN to DDS\n");

Expand All @@ -536,17 +507,13 @@ int main(int argc, char* argv[]) {

// Now write the DDS file to disk.
char dst_filename[FILENAME_MAX];
crnlib_snprintf(dst_filename, sizeof(dst_filename), "%s%s%s.dds", drive_buf, dir_buf, fname_buf);
crnlib_snprintf(dst_filename, sizeof(dst_filename), "%s%s%s.dds", drive.get_ptr(), dir.get_ptr(), fname.get_ptr());
if (out_filename[0])
#if defined(_WIN32)
strcpy_s(dst_filename, sizeof(dst_filename), out_filename);
#else
strncpy(dst_filename, out_filename, sizeof(dst_filename));
#endif
strcpy_safe(dst_filename, sizeof(dst_filename), out_filename);

printf("Writing file: %s\n", dst_filename);
FILE* pFile = NULL;
crn_fopen(&pFile, dst_filename, "wb");
crn_fopen(&pFile, dst_filename, "wb");
if ((!pFile) || (fwrite(pDDS_file_data, dds_file_size, 1, pFile) != 1) || (fclose(pFile) == EOF)) {
crn_free_block(pDDS_file_data);
free(pSrc_file_data);
Expand All @@ -558,22 +525,10 @@ int main(int argc, char* argv[]) {
print_dds_info(pDDS_file_data, dds_file_size);

crn_free_block(pDDS_file_data);
} else if (crnlib_stricmp(ext_buf, ".dds") == 0) {
} else if (crnlib_stricmp(ext.get_ptr(), ".dds") == 0) {
// Unpack DDS to one or more TGA's.
if (out_filename[0]) {
#if defined(_WIN32)
_splitpath_s(out_filename, drive_buf, _MAX_DRIVE, dir_buf, _MAX_DIR, fname_buf, _MAX_FNAME, ext_buf, _MAX_EXT);
#else
dir_buf = dirname(out_filename);
fname_buf = basename(out_filename);
dot = strrchr(fname_buf, '.');
ext_buf[FILENAME_MAX];
ext_buf[0] = '\0';
if (dot && dot != fname_buf) {
strncpy(ext_buf, dot, strlen(dot));
*dot = '\0';
}
#endif
file_utils::split_path(out_filename, &drive, &dir, &fname, &ext);
}

crn_texture_desc tex_desc;
Expand All @@ -596,7 +551,7 @@ int main(int argc, char* argv[]) {
int height = std::max(1U, tex_desc.m_height >> level_index);

char dst_filename[FILENAME_MAX];
crnlib_snprintf(dst_filename, sizeof(dst_filename), "%s%s%s_face%u_mip%u.tga", drive_buf, dir_buf, fname_buf, face_index, level_index);
crnlib_snprintf(dst_filename, sizeof(dst_filename), "%s%s%s_face%u_mip%u.tga", drive.get_ptr(), dir.get_ptr(), fname.get_ptr(), face_index, level_index);

printf("Writing file: %s\n", dst_filename);
if (!stbi_write_tga(dst_filename, width, height, 4, pImages[level_index + face_index * tex_desc.m_levels])) {
Expand Down
14 changes: 8 additions & 6 deletions example2/example2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@

using namespace crnlib;

#if defined(_WIN32)
#define example2_strcpy_safe(d, l, s) strcpy_s(d, l, s)
#else
void example2_strcpy_safe(char *d, size_t l, const char* s) {l = strnlen(s, l - 1); memcpy(d, s, l); d[l] = '\0';}
#endif

static int print_usage() {
printf("Description: Transcodes .CRN to .DDS files using crn_decomp.h.\n");
printf("Copyright (c) 2010-2016 Richard Geldreich, Jr. and Binomial LLC\n");
Expand Down Expand Up @@ -90,11 +96,7 @@ int main(int argc, char* argv[]) {
if (++i >= argc)
return error("Expected output filename!");

#if defined(_WIN32)
strcpy_s(out_filename, sizeof(out_filename), argv[i]);
#else
strncpy(out_filename, argv[i], sizeof(out_filename));
#endif
example2_strcpy_safe(out_filename, sizeof(out_filename), argv[i]);
} else
return error("Invalid option: %s\n", argv[i]);
}
Expand Down Expand Up @@ -137,7 +139,7 @@ int main(int argc, char* argv[]) {
// Now create the DDS file.
char dst_filename[FILENAME_MAX];
if (out_filename[0]) {
strcpy(dst_filename, out_filename);
example2_strcpy_safe(dst_filename, sizeof(dst_filename), out_filename);
} else {
unsigned int stripped_length = UINT32_MAX;
const char* ext_begin = strrchr(pSrc_filename, '.');
Expand Down
Loading