xenia/third_party/crunch/crnlib/crn_mipmapped_texture.h

340 lines
12 KiB
C++

// File: crn_mipmapped_texture.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_dxt_image.h"
#include "../inc/dds_defs.h"
#include "crn_pixel_format.h"
#include "crn_image.h"
#include "crn_resampler.h"
#include "crn_data_stream_serializer.h"
#include "crn_qdxt1.h"
#include "crn_qdxt5.h"
#include "crn_texture_file_types.h"
#include "crn_image_utils.h"
namespace crnlib
{
extern const vec2I g_vertical_cross_image_offsets[6];
enum orientation_flags_t
{
cOrientationFlagXFlipped = 1,
cOrientationFlagYFlipped = 2,
cDefaultOrientationFlags = 0
};
enum unpack_flags_t
{
cUnpackFlagUncook = 1,
cUnpackFlagUnflip = 2
};
class mip_level
{
friend class mipmapped_texture;
public:
mip_level();
~mip_level();
mip_level(const mip_level& other);
mip_level& operator= (const mip_level& rhs);
// Assumes ownership.
void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
void clear();
inline uint get_width() const { return m_width; }
inline uint get_height() const { return m_height; }
inline uint get_total_pixels() const { return m_width * m_height; }
orientation_flags_t get_orientation_flags() const { return m_orient_flags; }
void set_orientation_flags(orientation_flags_t flags) { m_orient_flags = flags; }
inline image_u8* get_image() const { return m_pImage; }
inline dxt_image* get_dxt_image() const { return m_pDXTImage; }
image_u8* get_unpacked_image(image_u8& tmp, uint unpack_flags) const;
inline bool is_packed() const { return m_pDXTImage != NULL; }
inline bool is_valid() const { return (m_pImage != NULL) || (m_pDXTImage != NULL); }
inline pixel_format_helpers::component_flags get_comp_flags() const { return m_comp_flags; }
inline void set_comp_flags(pixel_format_helpers::component_flags comp_flags) { m_comp_flags = comp_flags; }
inline pixel_format get_format() const { return m_format; }
inline void set_format(pixel_format fmt) { m_format = fmt; }
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool pack_to_dxt(const image_u8& img, pixel_format fmt, bool cook, const dxt_image::pack_params& p, orientation_flags_t orient_flags = cDefaultOrientationFlags);
bool pack_to_dxt(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool unpack_from_dxt(bool uncook = true);
// Returns true if flipped on either axis.
bool is_flipped() const;
bool is_x_flipped() const;
bool is_y_flipped() const;
bool can_unflip_without_unpacking() const;
// Returns true if unflipped on either axis.
// Will try to flip packed (DXT/ETC) data in-place, if this isn't possible it'll unpack/uncook the mip level then unflip.
bool unflip(bool allow_unpacking_to_flip, bool uncook_during_unpack);
bool set_alpha_to_luma();
bool convert(image_utils::conversion_type conv_type);
bool flip_x();
bool flip_y();
private:
uint m_width;
uint m_height;
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
image_u8* m_pImage;
dxt_image* m_pDXTImage;
orientation_flags_t m_orient_flags;
void cook_image(image_u8& img) const;
void uncook_image(image_u8& img) const;
};
// A face is an array of mip_level ptr's.
typedef crnlib::vector<mip_level*> mip_ptr_vec;
// And an array of one, six, or N faces make up a texture.
typedef crnlib::vector<mip_ptr_vec> face_vec;
class mipmapped_texture
{
public:
// Construction/destruction
mipmapped_texture();
~mipmapped_texture();
mipmapped_texture(const mipmapped_texture& other);
mipmapped_texture& operator= (const mipmapped_texture& rhs);
void clear();
void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const char* pName, orientation_flags_t orient_flags);
// Assumes ownership.
void assign(face_vec& faces);
void assign(mip_level* pLevel);
void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
void set(texture_file_types::format source_file_type, const mipmapped_texture& mipmapped_texture);
// Accessors
image_u8* get_level_image(uint face, uint level, image_u8& img, uint unpack_flags = cUnpackFlagUncook | cUnpackFlagUnflip) const;
inline bool is_valid() const { return m_faces.size() > 0; }
const dynamic_string& get_name() const { return m_name; }
void set_name(const dynamic_string& name) { m_name = name; }
const dynamic_string& get_source_filename() const { return get_name(); }
texture_file_types::format get_source_file_type() const { return m_source_file_type; }
inline uint get_width() const { return m_width; }
inline uint get_height() const { return m_height; }
inline uint get_total_pixels() const { return m_width * m_height; }
uint get_total_pixels_in_all_faces_and_mips() const;
inline uint get_num_faces() const { return m_faces.size(); }
inline uint get_num_levels() const { if (m_faces.empty()) return 0; else return m_faces[0].size(); }
inline pixel_format_helpers::component_flags get_comp_flags() const { return m_comp_flags; }
inline pixel_format get_format() const { return m_format; }
inline bool is_unpacked() const { if (get_num_faces()) { return get_level(0, 0)->get_image() != NULL; } return false; }
inline const mip_ptr_vec& get_face(uint face) const { return m_faces[face]; }
inline mip_ptr_vec& get_face(uint face) { return m_faces[face]; }
inline const mip_level* get_level(uint face, uint mip) const { return m_faces[face][mip]; }
inline mip_level* get_level(uint face, uint mip) { return m_faces[face][mip]; }
bool has_alpha() const;
bool is_normal_map() const;
bool is_vertical_cross() const;
bool is_packed() const;
texture_type determine_texture_type() const;
const dynamic_string& get_last_error() const { return m_last_error; }
void clear_last_error() { m_last_error.clear(); }
// Reading/writing
bool read_dds(data_stream_serializer& serializer);
bool write_dds(data_stream_serializer& serializer) const;
bool read_ktx(data_stream_serializer& serializer);
bool write_ktx(data_stream_serializer& serializer) const;
bool read_crn(data_stream_serializer& serializer);
bool read_crn_from_memory(const void *pData, uint data_size, const char* pFilename);
// If file_format is texture_file_types::cFormatInvalid, the format will be determined from the filename's extension.
bool read_from_file(const char* pFilename, texture_file_types::format file_format = texture_file_types::cFormatInvalid);
bool read_from_stream(data_stream_serializer& serializer, texture_file_types::format file_format = texture_file_types::cFormatInvalid);
bool write_to_file(
const char* pFilename,
texture_file_types::format file_format = texture_file_types::cFormatInvalid,
crn_comp_params* pComp_params = NULL,
uint32* pActual_quality_level = NULL, float* pActual_bitrate = NULL,
uint32 image_write_flags = 0);
// Conversion
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool convert(pixel_format fmt, const dxt_image::pack_params& p);
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p, int qdxt_quality, bool hierarchical = true);
bool convert(image_utils::conversion_type conv_type);
bool unpack_from_dxt(bool uncook = true);
bool set_alpha_to_luma();
void discard_mipmaps();
void discard_mips();
struct resample_params
{
resample_params() :
m_pFilter("kaiser"),
m_wrapping(false),
m_srgb(false),
m_renormalize(false),
m_filter_scale(.9f),
m_gamma(1.75f), // or 2.2f
m_multithreaded(true)
{
}
const char* m_pFilter;
bool m_wrapping;
bool m_srgb;
bool m_renormalize;
float m_filter_scale;
float m_gamma;
bool m_multithreaded;
};
bool resize(uint new_width, uint new_height, const resample_params& params);
struct generate_mipmap_params : public resample_params
{
generate_mipmap_params() :
resample_params(),
m_min_mip_size(1),
m_max_mips(0)
{
}
uint m_min_mip_size;
uint m_max_mips; // actually the max # of total levels
};
bool generate_mipmaps(const generate_mipmap_params& params, bool force);
bool crop(uint x, uint y, uint width, uint height);
bool vertical_cross_to_cubemap();
// Low-level clustered DXT (QDXT) compression
struct qdxt_state
{
qdxt_state(task_pool& tp) : m_fmt(PIXEL_FMT_INVALID), m_qdxt1(tp), m_qdxt5a(tp), m_qdxt5b(tp)
{
}
pixel_format m_fmt;
qdxt1 m_qdxt1;
qdxt5 m_qdxt5a;
qdxt5 m_qdxt5b;
crnlib::vector<dxt_pixel_block> m_pixel_blocks;
qdxt1_params m_qdxt1_params;
qdxt5_params m_qdxt5_params[2];
bool m_has_blocks[3];
void clear()
{
m_fmt = PIXEL_FMT_INVALID;
m_qdxt1.clear();
m_qdxt5a.clear();
m_qdxt5b.clear();
m_pixel_blocks.clear();
m_qdxt1_params.clear();
m_qdxt5_params[0].clear();
m_qdxt5_params[1].clear();
utils::zero_object(m_has_blocks);
}
};
bool qdxt_pack_init(qdxt_state& state, mipmapped_texture& dst_tex, const qdxt1_params& dxt1_params, const qdxt5_params& dxt5_params, pixel_format fmt, bool cook);
bool qdxt_pack(qdxt_state& state, mipmapped_texture& dst_tex, const qdxt1_params& dxt1_params, const qdxt5_params& dxt5_params);
void swap(mipmapped_texture& img);
bool check() const;
void set_orientation_flags(orientation_flags_t flags);
// Returns true if any face/miplevel is flipped.
bool is_flipped() const;
bool is_x_flipped() const;
bool is_y_flipped() const;
bool can_unflip_without_unpacking() const;
bool unflip(bool allow_unpacking_to_flip, bool uncook_if_necessary_to_unpack);
bool flip_y(bool update_orientation_flags);
private:
dynamic_string m_name;
uint m_width;
uint m_height;
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
face_vec m_faces;
texture_file_types::format m_source_file_type;
mutable dynamic_string m_last_error;
inline void clear_last_error() const { m_last_error.clear(); }
inline void set_last_error(const char* p) const { m_last_error = p; }
void free_all_mips();
bool read_regular_image(data_stream_serializer &serializer, texture_file_types::format file_format);
bool write_regular_image(const char* pFilename, uint32 image_write_flags);
bool read_dds_internal(data_stream_serializer& serializer);
void print_crn_comp_params(const crn_comp_params& p);
bool write_comp_texture(const char* pFilename, const crn_comp_params &comp_params, uint32 *pActual_quality_level, float *pActual_bitrate);
void change_dxt1_to_dxt1a();
bool flip_y_helper();
};
inline void swap(mipmapped_texture& a, mipmapped_texture& b)
{
a.swap(b);
}
} // namespace crnlib