Commit ca241db6 authored by DolceTriade's avatar DolceTriade Committed by Thomas Debesse

image: add crn support to the image plugin.

This works by converting the crn file to dds in memory
and then using the dds load functions to convert the dds
file to RGBA. This is because crn also stores the file as
a compressed texture meant to be uploaded directly to the
GPU, however, radiant wants an RGBA array.
parent 92008157
add_subdirectory(cmdlib)
add_subdirectory(container)
add_subdirectory(crunch)
add_subdirectory(ddslib)
add_subdirectory(debugging)
add_subdirectory(etclib)
......
add_library(crnlib
crn_decomp.h
crnlib.h
crn_rgba.h
crn_rgba.cpp
)
set_target_properties(crnlib PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(crnlib PRIVATE ddslib)
target_compile_options(crnlib PRIVATE -fexceptions)
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
/*
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 "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
This diff is collapsed.
......@@ -6,8 +6,10 @@ radiant_plugin(image
ktx.cpp ktx.h
pcx.cpp pcx.h
tga.cpp tga.h
crn.cpp crn.h
)
find_package(JPEG REQUIRED)
target_include_directories(image PRIVATE ${JPEG_INCLUDE_DIR})
target_link_libraries(image PRIVATE ddslib etclib ${JPEG_LIBRARIES})
target_include_directories(image PRIVATE ${JPEG_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/libs/crunch)
target_link_libraries(image PRIVATE ddslib etclib crnlib ${JPEG_LIBRARIES})
target_compile_options(image 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.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
......@@ -28,6 +28,7 @@
#include "pcx.h"
#include "dds.h"
#include "ktx.h"
#include "crn.h"
#include "modulesystem/singletonmodule.h"
......@@ -173,6 +174,29 @@ typedef SingletonModule<ImageKTXAPI, ImageDependencies> ImageKTXModule;
ImageKTXModule g_ImageKTXModule;
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);
......@@ -183,4 +207,5 @@ extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer &server)
g_ImagePCXModule.selfRegister();
g_ImageDDSModule.selfRegister();
g_ImageKTXModule.selfRegister();
g_ImageCRNModule.selfRegister();
}
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