Commit fdd8e69b authored by Mario's avatar Mario

Merge branch 'crunch-submodule' into 'master'

Add crunch support to radiant and q3map2, the submodule way

See merge request !104
parents 92008157 6acf8cb1
[submodule "libs/crunch"]
path = libs/crunch
url = https://github.com/DaemonEngine/crunch.git
......@@ -3,6 +3,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
project(NetRadiant C CXX)
option(BUILD_RADIANT "Build the GUI" ON)
option(BUILD_CRUNCH "Build Crunch image support" OFF)
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/install" CACHE PATH "..." FORCE)
......
......@@ -13,7 +13,7 @@ http://git-scm.org
To get a copy of the source using the commandline git client:
```
git clone https://gitlab.com/xonotic/netradiant.git
git clone --recursive https://gitlab.com/xonotic/netradiant.git
cd netradiant
```
......@@ -54,6 +54,17 @@ brew install Caskroom/cask/xquartz
brew link --force gettext
```
# Submodules
* Crunch
If you forgot to add `--recursive` option at `git clone` time, fetch it this way:
```
git submodule update --init --recursive
```
# Compiling
This project uses the usual CMake workflow:
......@@ -86,3 +97,7 @@ targets:
* `quake3` Compiles all the Quake3 tools
- `q3map2` Quake3 map compiler
- `q3data`
## Note about Crunch
The crnlib used to decode `.crn` files is the one from [Dæmon](http://github.com/DaemonEngine/Daemon) which is just the one by [Unity](https://github.com/Unity-Technologies/crunch/tree/unity) made cross-platform. Since Unity brokes compatibility with [BinomialLLC's legacy tree](https://github.com/BinomialLLC/crunch) it's required to use either crunch from Dæmon or the one from Unity to compress textures that have to be read by radiant or q3map2.
add_subdirectory(cmdlib)
add_subdirectory(container)
if (BUILD_CRUNCH)
add_subdirectory(crnrgba)
endif ()
add_subdirectory(ddslib)
add_subdirectory(debugging)
add_subdirectory(etclib)
......
add_library(crnrgba
crn_rgba.h
crn_rgba.cpp
../crunch/inc/crn_decomp.h
../crunch/inc/crnlib.h
)
set_target_properties(crnrgba PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(crnrgba PRIVATE ddslib)
target_compile_options(crnrgba PRIVATE -fexceptions)
/*
Copyright (C) 2018, Unvanquished Developers
All Rights Reserved.
This file is part of NetRadiant.
NetRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
NetRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NetRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "crn_rgba.h"
#include <string.h>
#include <memory>
#include "ddslib.h"
#include "../crunch/inc/crn_decomp.h"
int LittleLong(int l) {
#if GDEF_ARCH_ENDIAN_BIG
std::reverse(reinterpret_cast<unsigned char *>( &l ), reinterpret_cast<unsigned char *>( &l ) + sizeof(int));
#endif
return l;
}
// Sets `x` and `y` to the width and height of the input crn image. Returns false if there is an
// error reading the image.
extern "C" int GetCRNImageSize(const void *buffer, int length, int *x, int *y) {
crnd::crn_texture_info ti;
if(!crnd::crnd_get_texture_info(buffer, length, &ti) ||
// Ensure we are not trying to load a cubemap (which has 6 faces...)
(ti.m_faces != 1) ) {
return false;
}
if (x) *x = ti.m_width;
if (y) *y = ti.m_height;
return true;
}
// Converts a .crn file to RGBA. Stores the pixels in outBuf. Use GetCRNImageSize to get the image
// size to determine how big outBuf should be. The function will return false if the image does not
// fit inside outBuf.
extern "C" int ConvertCRNtoRGBA(const void *buffer, int length, int outBufLen, void* outBuf) {
crnd::crn_texture_info ti;
if(!crnd::crnd_get_texture_info(buffer, length, &ti) ||
// Ensure we are not trying to load a cubemap (which has 6 faces...)
(ti.m_faces != 1) ) {
return false;
}
// Sanity check mipmaps.
if (ti.m_levels <= 0) {
return false;
}
// The largest layer is always layer 0, so load that one.
crnd::crn_level_info li;
if (!crnd::crnd_get_level_info( buffer, length, 0, &li)) {
return false;
}
// Ensure we can fit the final image in outBuf.
if (outBufLen < ti.m_width * ti.m_height) {
return false;
}
crnd::crnd_unpack_context ctx = crnd::crnd_unpack_begin(buffer, length);
if (!ctx) {
return false;
}
// Since the texture is compressed and the crunch library doesn't provide the code to convert the code
// to RGBAImage, we'll need to convert it to DDS first and use the DDS decompression routines to get
// the raw pixels (theoretically, we could refactor the DDS functions to be generalized, but for now,
// this seems much more maintainable...). This code is cribbed from the example code in
// the crunch repo: https://github.com/DaemonEngine/crunch/blob/master/example2/example2.cpp
// Compute the face's width, height, number of DXT blocks per row/col, etc.
// This is not a proper DDS conversion; it's only enough to get the ddslib decompressor to be happy.
const crn_uint32 blocks_x = std::max(1U, (ti.m_width + 3) >> 2);
const crn_uint32 blocks_y = std::max(1U, (ti.m_height + 3) >> 2);
const crn_uint32 row_pitch = blocks_x * crnd::crnd_get_bytes_per_dxt_block(ti.m_format);
const crn_uint32 total_face_size = row_pitch * blocks_y;
const crn_uint32 ddsSize = sizeof(ddsBuffer_t) + total_face_size;
std::unique_ptr<char> ddsBuffer(new char[ddsSize]);
memset(ddsBuffer.get(), 0, ddsSize);
ddsBuffer_t* dds = reinterpret_cast<ddsBuffer_t*>(ddsBuffer.get());
memcpy(&dds->magic, "DDS ", sizeof(dds->magic));
dds->size = LittleLong(124); // Size of the DDS header.
dds->height = LittleLong(ti.m_height);
dds->width = LittleLong(ti.m_width);
dds->mipMapCount = LittleLong(1);
dds->pixelFormat.size = LittleLong(sizeof(ddsPixelFormat_t));
crn_format fundamental_fmt = crnd::crnd_get_fundamental_dxt_format(ti.m_format);
dds->pixelFormat.fourCC = LittleLong(crnd::crnd_crn_format_to_fourcc(fundamental_fmt));
if (fundamental_fmt != ti.m_format) {
// It's a funky swizzled DXTn format - write its FOURCC to RGBBitCount.
dds->pixelFormat.rgbBitCount = LittleLong(crnd::crnd_crn_format_to_fourcc(ti.m_format));
}
char* imageArray[1];
imageArray[0] = reinterpret_cast<char*>(&dds->data);
if (!crnd::crnd_unpack_level(ctx, reinterpret_cast<void**>(&imageArray), total_face_size, row_pitch, 0)) {
return false;
}
if (DDSDecompress(dds, reinterpret_cast<unsigned char*>(outBuf)) == -1) {
return false;
}
return true;
}
/*
Copyright (C) 2018, Unvanquished Developers
All Rights Reserved.
This file is part of NetRadiant.
NetRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
NetRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NetRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Sets `x` and `y` to the width and height of the input crn image. Returns false if there is an
// error reading the image.
int GetCRNImageSize(const void *buffer, int length, int *x, int *y);
// Converts a .crn file to RGBA. Stores the pixels in outBuf. Use GetCRNImageSize to get the image
// size to determine how big outBuf should be. The function will return false if the image does not
// fit inside outBuf.
int ConvertCRNtoRGBA(const void *buffer, int length, int outBufLen, void* outBuf);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
Subproject commit 85bab3d798a54abe32a22d5275e625ec06df6917
......@@ -17,6 +17,11 @@ add_subdirectory(archivewad)
add_subdirectory(archivezip)
add_subdirectory(entity)
add_subdirectory(image)
if(BUILD_CRUNCH)
add_subdirectory(imagecrn)
endif()
add_subdirectory(imagehl)
add_subdirectory(imagepng)
add_subdirectory(imageq2)
......
......@@ -11,3 +11,4 @@ radiant_plugin(image
find_package(JPEG REQUIRED)
target_include_directories(image PRIVATE ${JPEG_INCLUDE_DIR})
target_link_libraries(image PRIVATE ddslib etclib ${JPEG_LIBRARIES})
target_compile_options(image PRIVATE -fexceptions)
radiant_plugin(imagecrn
imagecrn.cpp
crn.cpp crn.h
)
target_include_directories(imagecrn PRIVATE ${CMAKE_SOURCE_DIR}/libs/crnrgba)
target_link_libraries(imagecrn PRIVATE crnrgba)
/*
Copyright (C) 2018, Unvanquished Developers
All Rights Reserved.
This file is part of NetRadiant.
NetRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
NetRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NetRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "crn.h"
#include <stdlib.h>
#include "ifilesystem.h"
#include "iarchive.h"
#include "idatastream.h"
#include "crn_rgba.h"
#include "ddslib.h"
#include "imagelib.h"
Image *LoadCRNBuff(const byte *buffer, int length)
{
int width, height;
if (!GetCRNImageSize(buffer, length, &width, &height)) {
globalErrorStream() << "ERROR: Error getting crn imag dimensions.\n";
return nullptr;
}
RGBAImage *image = new RGBAImage(width, height);
if (!ConvertCRNtoRGBA(buffer, length, width * height, image->getRGBAPixels())) {
globalErrorStream() << "ERROR: Error decoding crn image.\n";
image->release();
return nullptr;
}
return image;
}
Image *LoadCRN(ArchiveFile &file)
{
ScopedArchiveBuffer buffer(file);
return LoadCRNBuff(buffer.buffer, buffer.length);
}
/*
Copyright (C) 2018, Unvanquished Developers
All Rights Reserved.
This file is part of NetRadiant.
NetRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
NetRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NetRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_CRN_H )
#define INCLUDED_CRN_H
class Image;
class ArchiveFile;
Image *LoadCRN(ArchiveFile &file);
#endif
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "ifilesystem.h"
#include "iimage.h"
#include "crn.h"
#include "modulesystem/singletonmodule.h"
class ImageDependencies : public GlobalFileSystemModuleRef {
};
class ImageCRNAPI {
_QERPlugImageTable m_imagecrn;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "crn");
ImageCRNAPI()
{
m_imagecrn.loadImage = LoadCRN;
}
_QERPlugImageTable *getTable()
{
return &m_imagecrn;
}
};
typedef SingletonModule<ImageCRNAPI, ImageDependencies> ImageCRNModule;
ImageCRNModule g_ImageCRNModule;
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer &server)
{
initialiseModule(server);
g_ImageCRNModule.selfRegister();
}
; imagepng.def : Declares the module parameters for the DLL.
LIBRARY "IMAGECRN"
EXPORTS
; Explicit exports can go here
Radiant_RegisterModules @1
......@@ -31,6 +31,8 @@ include_directories(${ZLIB_INCLUDE_DIRS})
find_package(Minizip REQUIRED)
include_directories(${Minizip_INCLUDE_DIRS})
include_directories(${CMAKE_SOURCE_DIR}/libs/crnrgba)
set(q3map2_games
q3map2/game_darkplaces.h
q3map2/game_dq.h
......@@ -119,6 +121,16 @@ radiant_tool(q3map2
q3map2/writebsp.c
)
if (BUILD_CRUNCH)
set(OPTIONAL_IMAGE_LIBRARIES crnrgba)
set(OPTIONAL_IMAGE_DEFINES BUILD_CRUNCH=1)
endif ()
target_compile_definitions(q3map2
PRIVATE
${OPTIONAL_IMAGE_DEFINES}
)
target_link_libraries(q3map2
${GLIB_LIBRARIES}
${JPEG_LIBRARIES}
......@@ -126,6 +138,7 @@ target_link_libraries(q3map2
${LIBXML2_LIBRARIES}
${Minizip_LIBRARIES}
${ZLIB_LIBRARIES}
${OPTIONAL_IMAGE_LIBRARIES}
ddslib
etclib
filematch
......
......@@ -86,6 +86,28 @@ static void LoadDDSBuffer( byte *buffer, int size, byte **pixels, int *width, in
DDSDecompress( (ddsBuffer_t*) buffer, *pixels );
}
#ifdef BUILD_CRUNCH
/*
LoadCRNBuffer
loads a crn image into a valid rgba image
*/
void LoadCRNBuffer( byte *buffer, int size, byte **pixels, int *width, int *height) {
/* dummy check */
if ( buffer == NULL || size <= 0 || pixels == NULL || width == NULL || height == NULL ) {
return;
}
if ( !GetCRNImageSize( buffer, size, width, height ) ) {
Sys_FPrintf( SYS_WRN, "WARNING: Error getting crn imag dimensions.\n");;
return;
}
int outBufSize = *width * *height * 4;
*pixels = safe_malloc( outBufSize );
if ( !ConvertCRNtoRGBA( buffer, size, outBufSize, *pixels) ) {
Sys_FPrintf( SYS_WRN, "WARNING: Error decoding crn image.\n", 0 );
return;
}
}
#endif // BUILD_CRUNCH
/*
......@@ -437,6 +459,18 @@ image_t *ImageLoad( const char *filename ){
if ( size > 0 ) {
LoadKTXBufferFirstImage( buffer, size, &image->pixels, &image->width, &image->height );
}
#ifdef BUILD_CRUNCH
else
{
/* attempt to load crn */
StripExtension( name );
strcat( name, ".crn" );
size = vfsLoadFile( ( const char* ) name, ( void** ) &buffer, 0 );
if ( size > 0 ) {
LoadCRNBuffer( buffer, size, &image->pixels, &image->width, &image->height );
}
}
#endif // BUILD_CRUNCH
}
}
}
......@@ -473,7 +507,7 @@ image_t *ImageLoad( const char *filename ){
if (pixels) {
// On error, LoadJPGBuff might store a pointer to the error message in pixels
Sys_FPrintf( SYS_WRN, "WARNING: LoadJPGBuff %s %s\n", name, (unsigned char*) pixels );
}
}
} else {
if ( width == image->width && height == image->height ) {
int i;
......
......@@ -70,6 +70,7 @@
#include "mathlib.h"
#include "md5lib.h"
#include "ddslib.h"
#include "crn_rgba.h"
#include "picomodel.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment