feat: modules moved and engine moved to submodule
|
|
@ -1,3 +0,0 @@
|
|||
Import('env')
|
||||
|
||||
env.add_source_files(env.modules_sources, "*.cpp")
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
def can_build(env, platform):
|
||||
return True;
|
||||
|
||||
def configure(env):
|
||||
pass;
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef GODOT_EXTRA_MACROS_H
|
||||
#define GODOT_EXTRA_MACROS_H
|
||||
|
||||
#define BIND_GET_SET(m_property)\
|
||||
ClassDB::bind_method(D_METHOD("set_" #m_property, #m_property), &self_type::set_##m_property);\
|
||||
ClassDB::bind_method(D_METHOD("get_" #m_property), &self_type::get_##m_property)
|
||||
|
||||
#define BIND_HPROPERTY(m_type, m_property, ...)\
|
||||
BIND_GET_SET(m_property);\
|
||||
ADD_PROPERTY(PropertyInfo(m_type, #m_property, __VA_ARGS__), "set_" #m_property, "get_" #m_property)
|
||||
|
||||
#define BIND_PROPERTY(m_type, m_property)\
|
||||
BIND_GET_SET(m_property);\
|
||||
ADD_PROPERTY(PropertyInfo(m_type, #m_property), "set_" #m_property, "get_" #m_property)
|
||||
|
||||
#endif // !GODOT_EXTRA_MACROS_H
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#include "register_types.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
void initialize_PROJECT_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void uninitialize_PROJECT_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef PROJECT_REGISTER_TYPES_H
|
||||
#define PROJECT_REGISTER_TYPES_H
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_PROJECT_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_PROJECT_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // !PROJECT_REGISTER_TYPES_H
|
||||
|
|
@ -17,8 +17,9 @@ Export("env_modules")
|
|||
|
||||
# Header with MODULE_*_ENABLED defines.
|
||||
def modules_enabled_builder(target, source, env):
|
||||
with methods.generated_wrapper(target) as file:
|
||||
for module in source[0].read():
|
||||
modules = sorted(source[0].read())
|
||||
with methods.generated_wrapper(str(target[0])) as file:
|
||||
for module in modules:
|
||||
file.write(f"#define MODULE_{module.upper()}_ENABLED\n")
|
||||
|
||||
|
||||
|
|
@ -29,14 +30,26 @@ modules_enabled = env.CommandNoCache(
|
|||
|
||||
def register_module_types_builder(target, source, env):
|
||||
modules = source[0].read()
|
||||
mod_inc = "\n".join([f'#include "{p}/register_types.h"' for p in modules.values()])
|
||||
mod_inc = "\n".join([f'#include "{value}/register_types.h"' for value in modules.values()])
|
||||
mod_init = "\n".join(
|
||||
[f"#ifdef MODULE_{n.upper()}_ENABLED\n\tinitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
|
||||
[
|
||||
f"""\
|
||||
#ifdef MODULE_{key.upper()}_ENABLED
|
||||
initialize_{key}_module(p_level);
|
||||
#endif"""
|
||||
for key in modules.keys()
|
||||
]
|
||||
)
|
||||
mod_uninit = "\n".join(
|
||||
[f"#ifdef MODULE_{n.upper()}_ENABLED\n\tuninitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
|
||||
[
|
||||
f"""\
|
||||
#ifdef MODULE_{key.upper()}_ENABLED
|
||||
uninitialize_{key}_module(p_level);
|
||||
#endif"""
|
||||
for key in modules.keys()
|
||||
]
|
||||
)
|
||||
with methods.generated_wrapper(target) as file:
|
||||
with methods.generated_wrapper(str(target[0])) as file:
|
||||
file.write(
|
||||
f"""\
|
||||
#include "register_module_types.h"
|
||||
|
|
@ -88,9 +101,10 @@ for name, path in env.module_list.items():
|
|||
if env["tests"]:
|
||||
|
||||
def modules_tests_builder(target, source, env):
|
||||
with methods.generated_wrapper(target) as file:
|
||||
for header in source:
|
||||
file.write('#include "{}"\n'.format(os.path.normpath(header.path).replace("\\", "/")))
|
||||
headers = sorted([os.path.relpath(src.path, methods.base_folder).replace("\\", "/") for src in source])
|
||||
with methods.generated_wrapper(str(target[0])) as file:
|
||||
for header in headers:
|
||||
file.write(f'#include "{header}"\n')
|
||||
|
||||
env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_tests_builder))
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ thirdparty_sources = [
|
|||
]
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
env_astcenc.Prepend(CPPPATH=[thirdparty_dir])
|
||||
env_astcenc.Prepend(CPPEXTPATH=[thirdparty_dir])
|
||||
|
||||
env_thirdparty = env_astcenc.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef IMAGE_COMPRESS_ASTCENC_H
|
||||
#define IMAGE_COMPRESS_ASTCENC_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image.h"
|
||||
|
||||
|
|
@ -38,5 +37,3 @@ void _compress_astc(Image *r_img, Image::ASTCFormat p_format);
|
|||
#endif
|
||||
|
||||
void _decompress_astc(Image *r_img);
|
||||
|
||||
#endif // IMAGE_COMPRESS_ASTCENC_H
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ASTCENC_REGISTER_TYPES_H
|
||||
#define ASTCENC_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_astcenc_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_astcenc_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // ASTCENC_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -42,18 +42,14 @@ if basisu_encoder:
|
|||
|
||||
transcoder_sources = [thirdparty_dir + "transcoder/basisu_transcoder.cpp"]
|
||||
|
||||
# Treat Basis headers as system headers to avoid raising warnings. Not supported on MSVC.
|
||||
if not env.msvc:
|
||||
env_basisu.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path])
|
||||
else:
|
||||
env_basisu.Prepend(CPPPATH=[thirdparty_dir])
|
||||
env_basisu.Prepend(CPPEXTPATH=[thirdparty_dir])
|
||||
|
||||
if basisu_encoder:
|
||||
env_basisu.Prepend(CPPPATH=["#thirdparty/jpeg-compressor"])
|
||||
env_basisu.Prepend(CPPPATH=["#thirdparty/tinyexr"])
|
||||
env_basisu.Prepend(CPPEXTPATH=["#thirdparty/jpeg-compressor"])
|
||||
env_basisu.Prepend(CPPEXTPATH=["#thirdparty/tinyexr"])
|
||||
|
||||
if env["builtin_zstd"]:
|
||||
env_basisu.Prepend(CPPPATH=["#thirdparty/zstd"])
|
||||
env_basisu.Prepend(CPPEXTPATH=["#thirdparty/zstd"])
|
||||
|
||||
env_thirdparty = env_basisu.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
|
|||
bool rgtc_supported = RS::get_singleton()->has_os_feature("rgtc");
|
||||
bool s3tc_supported = RS::get_singleton()->has_os_feature("s3tc");
|
||||
bool etc2_supported = RS::get_singleton()->has_os_feature("etc2");
|
||||
bool astc_hdr_supported = RS::get_singleton()->has_os_feature("astc_hdr");
|
||||
|
||||
bool needs_ra_rg_swap = false;
|
||||
bool needs_rg_trim = false;
|
||||
|
|
@ -379,7 +380,7 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
|
|||
if (bptc_supported) {
|
||||
basisu_format = basist::transcoder_texture_format::cTFBC6H;
|
||||
image_format = Image::FORMAT_BPTC_RGBFU;
|
||||
} else if (astc_supported) {
|
||||
} else if (astc_hdr_supported) {
|
||||
basisu_format = basist::transcoder_texture_format::cTFASTC_HDR_4x4_RGBA;
|
||||
image_format = Image::FORMAT_ASTC_4x4_HDR;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef IMAGE_COMPRESS_BASISU_H
|
||||
#define IMAGE_COMPRESS_BASISU_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image.h"
|
||||
|
||||
|
|
@ -58,5 +57,3 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
|||
|
||||
Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size);
|
||||
Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer);
|
||||
|
||||
#endif // IMAGE_COMPRESS_BASISU_H
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef BASIS_UNIVERSAL_REGISTER_TYPES_H
|
||||
#define BASIS_UNIVERSAL_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_basis_universal_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_basis_universal_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // BASIS_UNIVERSAL_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -48,14 +48,14 @@ static void decompress_image(BCdecFormat format, const void *src, void *dst, con
|
|||
const uint8_t *src_blocks = reinterpret_cast<const uint8_t *>(src);
|
||||
uint8_t *dec_blocks = reinterpret_cast<uint8_t *>(dst);
|
||||
|
||||
#define DECOMPRESS_LOOP(func, block_size, color_bytesize, color_components) \
|
||||
for (uint64_t y = 0; y < height; y += 4) { \
|
||||
for (uint64_t x = 0; x < width; x += 4) { \
|
||||
func(&src_blocks[src_pos], &dec_blocks[dst_pos], width *color_components); \
|
||||
src_pos += block_size; \
|
||||
dst_pos += 4 * color_bytesize; \
|
||||
} \
|
||||
dst_pos += 3 * width * color_bytesize; \
|
||||
#define DECOMPRESS_LOOP(func, block_size, color_bytesize, color_components) \
|
||||
for (uint64_t y = 0; y < height; y += 4) { \
|
||||
for (uint64_t x = 0; x < width; x += 4) { \
|
||||
func(&src_blocks[src_pos], &dec_blocks[dst_pos], width * color_components); \
|
||||
src_pos += block_size; \
|
||||
dst_pos += 4 * color_bytesize; \
|
||||
} \
|
||||
dst_pos += 3 * width * color_bytesize; \
|
||||
}
|
||||
|
||||
#define DECOMPRESS_LOOP_SAFE(func, block_size, color_bytesize, color_components, output) \
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef IMAGE_DECOMPRESS_BCDEC_H
|
||||
#define IMAGE_DECOMPRESS_BCDEC_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image.h"
|
||||
|
||||
|
|
@ -45,5 +44,3 @@ enum BCdecFormat {
|
|||
};
|
||||
|
||||
void image_decompress_bcdec(Image *p_image);
|
||||
|
||||
#endif // IMAGE_DECOMPRESS_BCDEC_H
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef BCDEC_REGISTER_TYPES_H
|
||||
#define BCDEC_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_bcdec_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_bcdec_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // BCDEC_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -89,12 +89,36 @@ float CalcMSLE(float3 a, float3 b) {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Adapt the log function to make sense when a < 0
|
||||
float3 customLog2(float3 a) {
|
||||
return float3(
|
||||
a.x >= 0 ? log2(a.x + 1.0f) : -log2(-a.x + 1.0f),
|
||||
a.y >= 0 ? log2(a.y + 1.0f) : -log2(-a.y + 1.0f),
|
||||
a.z >= 0 ? log2(a.z + 1.0f) : -log2(-a.z + 1.0f));
|
||||
}
|
||||
|
||||
// Inverse of customLog2()
|
||||
float3 customExp2(float3 a) {
|
||||
return float3(
|
||||
a.x >= 0 ? exp2(a.x) - 1.0f : -(exp2(-a.x) - 1.0f),
|
||||
a.y >= 0 ? exp2(a.y) - 1.0f : -(exp2(-a.y) - 1.0f),
|
||||
a.z >= 0 ? exp2(a.z) - 1.0f : -(exp2(-a.z) - 1.0f));
|
||||
}
|
||||
#else
|
||||
float CalcMSLE(float3 a, float3 b) {
|
||||
float3 err = log2((b + 1.0f) / (a + 1.0f));
|
||||
err = err * err;
|
||||
return err.x + err.y + err.z;
|
||||
}
|
||||
|
||||
float3 customLog2(float3 a) {
|
||||
return log2(a + 1.0f);
|
||||
}
|
||||
|
||||
float3 customExp2(float3 a) {
|
||||
return exp2(a) - 1.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint PatternFixupID(uint i) {
|
||||
|
|
@ -272,15 +296,15 @@ void EncodeP1(inout uint4 block, inout float blockMSLE, float3 texels[16]) {
|
|||
refinedBlockMax = max(refinedBlockMax, texels[i] == blockMax ? refinedBlockMax : texels[i]);
|
||||
}
|
||||
|
||||
float3 logBlockMax = log2(blockMax + 1.0f);
|
||||
float3 logBlockMin = log2(blockMin + 1.0f);
|
||||
float3 logRefinedBlockMax = log2(refinedBlockMax + 1.0f);
|
||||
float3 logRefinedBlockMin = log2(refinedBlockMin + 1.0f);
|
||||
float3 logBlockMax = customLog2(blockMax);
|
||||
float3 logBlockMin = customLog2(blockMin);
|
||||
float3 logRefinedBlockMax = customLog2(refinedBlockMax);
|
||||
float3 logRefinedBlockMin = customLog2(refinedBlockMin);
|
||||
float3 logBlockMaxExt = (logBlockMax - logBlockMin) * (1.0f / 32.0f);
|
||||
logBlockMin += min(logRefinedBlockMin - logBlockMin, logBlockMaxExt);
|
||||
logBlockMax -= min(logBlockMax - logRefinedBlockMax, logBlockMaxExt);
|
||||
blockMin = exp2(logBlockMin) - 1.0f;
|
||||
blockMax = exp2(logBlockMax) - 1.0f;
|
||||
blockMin = customExp2(logBlockMin);
|
||||
blockMax = customExp2(logBlockMax);
|
||||
|
||||
float3 blockDir = blockMax - blockMin;
|
||||
blockDir = blockDir / (blockDir.x + blockDir.y + blockDir.z);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef BETSY_BC1_H
|
||||
#define BETSY_BC1_H
|
||||
#pragma once
|
||||
|
||||
constexpr const float dxt1_encoding_table[1024] = {
|
||||
0,
|
||||
|
|
@ -1057,5 +1056,3 @@ constexpr const float dxt1_encoding_table[1024] = {
|
|||
63,
|
||||
63,
|
||||
};
|
||||
|
||||
#endif // BETSY_BC1_H
|
||||
|
|
|
|||
|
|
@ -259,6 +259,14 @@ void BetsyCompressor::_thread_exit() {
|
|||
compress_rd->free(cached_shaders[i].compiled);
|
||||
}
|
||||
}
|
||||
|
||||
// Free the RD (and RCD if necessary).
|
||||
memdelete(compress_rd);
|
||||
compress_rd = nullptr;
|
||||
if (compress_rcd != nullptr) {
|
||||
memdelete(compress_rcd);
|
||||
compress_rcd = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -268,16 +276,6 @@ void BetsyCompressor::finish() {
|
|||
WorkerThreadPool::get_singleton()->wait_for_task_completion(task_id);
|
||||
task_id = WorkerThreadPool::INVALID_TASK_ID;
|
||||
}
|
||||
|
||||
if (compress_rd != nullptr) {
|
||||
// Free the RD (and RCD if necessary).
|
||||
memdelete(compress_rd);
|
||||
compress_rd = nullptr;
|
||||
if (compress_rcd != nullptr) {
|
||||
memdelete(compress_rcd);
|
||||
compress_rcd = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions.
|
||||
|
|
@ -373,6 +371,13 @@ Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
|
|||
return ERR_INVALID_DATA;
|
||||
}
|
||||
|
||||
int img_width = r_img->get_width();
|
||||
int img_height = r_img->get_height();
|
||||
if (img_width % 4 != 0 || img_height % 4 != 0) {
|
||||
img_width = img_width <= 2 ? img_width : (img_width + 3) & ~3;
|
||||
img_height = img_height <= 2 ? img_height : (img_height + 3) & ~3;
|
||||
}
|
||||
|
||||
Error err = OK;
|
||||
|
||||
// Destination format.
|
||||
|
|
@ -443,7 +448,7 @@ Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
|
|||
|
||||
// Container for the compressed data.
|
||||
Vector<uint8_t> dst_data;
|
||||
dst_data.resize(Image::get_image_data_size(r_img->get_width(), r_img->get_height(), dest_format, r_img->has_mipmaps()));
|
||||
dst_data.resize(Image::get_image_data_size(img_width, img_height, dest_format, r_img->has_mipmaps()));
|
||||
uint8_t *dst_data_ptr = dst_data.ptrw();
|
||||
|
||||
Vector<Vector<uint8_t>> src_images;
|
||||
|
|
@ -452,9 +457,12 @@ Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
|
|||
|
||||
// Compress each mipmap.
|
||||
for (int i = 0; i < mip_count; i++) {
|
||||
int64_t ofs, size;
|
||||
int width, height;
|
||||
r_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, width, height);
|
||||
Image::get_image_mipmap_offset_and_dimensions(img_width, img_height, dest_format, i, width, height);
|
||||
|
||||
int64_t src_mip_ofs, src_mip_size;
|
||||
int src_mip_w, src_mip_h;
|
||||
r_img->get_mipmap_offset_size_and_dimensions(i, src_mip_ofs, src_mip_size, src_mip_w, src_mip_h);
|
||||
|
||||
// Set the source texture width and size.
|
||||
src_texture_format.height = height;
|
||||
|
|
@ -464,9 +472,38 @@ Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
|
|||
dst_texture_format.height = (height + 3) >> 2;
|
||||
dst_texture_format.width = (width + 3) >> 2;
|
||||
|
||||
// Create a buffer filled with the source mip layer data.
|
||||
src_image_ptr[0].resize(size);
|
||||
memcpy(src_image_ptr[0].ptrw(), r_img->ptr() + ofs, size);
|
||||
// Pad textures to nearest block by smearing.
|
||||
if (width != src_mip_w || height != src_mip_h) {
|
||||
const uint8_t *src_mip_read = r_img->ptr() + src_mip_ofs;
|
||||
|
||||
// Reserve the buffer for padded image data.
|
||||
int px_size = Image::get_format_pixel_size(r_img->get_format());
|
||||
src_image_ptr[0].resize(width * height * px_size);
|
||||
uint8_t *ptrw = src_image_ptr[0].ptrw();
|
||||
|
||||
int x = 0, y = 0;
|
||||
for (y = 0; y < src_mip_h; y++) {
|
||||
for (x = 0; x < src_mip_w; x++) {
|
||||
memcpy(ptrw + (width * y + x) * px_size, src_mip_read + (src_mip_w * y + x) * px_size, px_size);
|
||||
}
|
||||
|
||||
// First, smear in x.
|
||||
for (; x < width; x++) {
|
||||
memcpy(ptrw + (width * y + x) * px_size, ptrw + (width * y + x - 1) * px_size, px_size);
|
||||
}
|
||||
}
|
||||
|
||||
// Then, smear in y.
|
||||
for (; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
memcpy(ptrw + (width * y + x) * px_size, ptrw + (width * y + x - width) * px_size, px_size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create a buffer filled with the source mip layer data.
|
||||
src_image_ptr[0].resize(src_mip_size);
|
||||
memcpy(src_image_ptr[0].ptrw(), r_img->ptr() + src_mip_ofs, src_mip_size);
|
||||
}
|
||||
|
||||
// Create the textures on the GPU.
|
||||
RID src_texture = compress_rd->texture_create(src_texture_format, RD::TextureView(), src_images);
|
||||
|
|
@ -646,7 +683,7 @@ Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
|
|||
|
||||
// Copy data from the GPU to the buffer.
|
||||
const Vector<uint8_t> texture_data = compress_rd->texture_get_data(dst_texture_rid, 0);
|
||||
int64_t dst_ofs = Image::get_image_mipmap_offset(r_img->get_width(), r_img->get_height(), dest_format, i);
|
||||
int64_t dst_ofs = Image::get_image_mipmap_offset(img_width, img_height, dest_format, i);
|
||||
|
||||
memcpy(dst_data_ptr + dst_ofs, texture_data.ptr(), texture_data.size());
|
||||
|
||||
|
|
@ -658,12 +695,12 @@ Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
|
|||
src_images.clear();
|
||||
|
||||
// Set the compressed data to the image.
|
||||
r_img->set_data(r_img->get_width(), r_img->get_height(), r_img->has_mipmaps(), dest_format, dst_data);
|
||||
r_img->set_data(img_width, img_height, r_img->has_mipmaps(), dest_format, dst_data);
|
||||
|
||||
print_verbose(
|
||||
vformat("Betsy: Encoding a %dx%d image with %d mipmaps as %s took %d ms.",
|
||||
r_img->get_width(),
|
||||
r_img->get_height(),
|
||||
img_width,
|
||||
img_height,
|
||||
r_img->get_mipmap_count(),
|
||||
Image::get_format_name(dest_format),
|
||||
OS::get_singleton()->get_ticks_msec() - start_time));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef IMAGE_COMPRESS_BETSY_H
|
||||
#define IMAGE_COMPRESS_BETSY_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image.h"
|
||||
#include "core/object/worker_thread_pool.h"
|
||||
|
|
@ -128,5 +127,3 @@ public:
|
|||
return err;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // IMAGE_COMPRESS_BETSY_H
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef BETSY_REGISTER_TYPES_H
|
||||
#define BETSY_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_betsy_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_betsy_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // BETSY_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef IMAGE_LOADER_BMP_H
|
||||
#define IMAGE_LOADER_BMP_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image_loader.h"
|
||||
|
||||
|
|
@ -106,5 +105,3 @@ public:
|
|||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||
ImageLoaderBMP();
|
||||
};
|
||||
|
||||
#endif // IMAGE_LOADER_BMP_H
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef BMP_REGISTER_TYPES_H
|
||||
#define BMP_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_bmp_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_bmp_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // BMP_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef BUFFER_DECODER_H
|
||||
#define BUFFER_DECODER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image.h"
|
||||
#include "core/templates/vector.h"
|
||||
|
|
@ -112,5 +111,3 @@ public:
|
|||
JpegBufferDecoder(CameraFeed *p_camera_feed);
|
||||
virtual void decode(StreamingBuffer p_buffer) override;
|
||||
};
|
||||
|
||||
#endif // BUFFER_DECODER_H
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ void CameraFeedLinux::_update_buffer() {
|
|||
}
|
||||
|
||||
void CameraFeedLinux::_query_device(const String &p_device_name) {
|
||||
file_descriptor = open(p_device_name.ascii(), O_RDWR | O_NONBLOCK, 0);
|
||||
file_descriptor = open(p_device_name.ascii().get_data(), O_RDWR | O_NONBLOCK, 0);
|
||||
ERR_FAIL_COND_MSG(file_descriptor == -1, vformat("Cannot open file descriptor for %s. Error: %d.", p_device_name, errno));
|
||||
|
||||
struct v4l2_capability capability;
|
||||
|
|
@ -235,7 +235,7 @@ String CameraFeedLinux::get_device_name() const {
|
|||
|
||||
bool CameraFeedLinux::activate_feed() {
|
||||
ERR_FAIL_COND_V_MSG(selected_format == -1, false, "CameraFeed format needs to be set before activating.");
|
||||
file_descriptor = open(device_name.ascii(), O_RDWR | O_NONBLOCK, 0);
|
||||
file_descriptor = open(device_name.ascii().get_data(), O_RDWR | O_NONBLOCK, 0);
|
||||
if (_request_buffers() && _start_capturing()) {
|
||||
buffer_decoder = _create_buffer_decoder();
|
||||
_start_thread();
|
||||
|
|
@ -315,7 +315,7 @@ bool CameraFeedLinux::set_format(int p_index, const Dictionary &p_parameters) {
|
|||
|
||||
FeedFormat feed_format = formats[p_index];
|
||||
|
||||
file_descriptor = open(device_name.ascii(), O_RDWR | O_NONBLOCK, 0);
|
||||
file_descriptor = open(device_name.ascii().get_data(), O_RDWR | O_NONBLOCK, 0);
|
||||
|
||||
struct v4l2_format format;
|
||||
memset(&format, 0, sizeof(format));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CAMERA_FEED_LINUX_H
|
||||
#define CAMERA_FEED_LINUX_H
|
||||
#pragma once
|
||||
|
||||
#include "buffer_decoder.h"
|
||||
|
||||
|
|
@ -41,6 +40,8 @@
|
|||
struct StreamingBuffer;
|
||||
|
||||
class CameraFeedLinux : public CameraFeed {
|
||||
GDSOFTCLASS(CameraFeedLinux, CameraFeed);
|
||||
|
||||
private:
|
||||
SafeFlag exit_flag;
|
||||
Thread *thread = nullptr;
|
||||
|
|
@ -65,14 +66,12 @@ private:
|
|||
|
||||
public:
|
||||
String get_device_name() const;
|
||||
bool activate_feed();
|
||||
void deactivate_feed();
|
||||
bool set_format(int p_index, const Dictionary &p_parameters);
|
||||
Array get_formats() const;
|
||||
FeedFormat get_format() const;
|
||||
bool activate_feed() override;
|
||||
void deactivate_feed() override;
|
||||
bool set_format(int p_index, const Dictionary &p_parameters) override;
|
||||
Array get_formats() const override;
|
||||
FeedFormat get_format() const override;
|
||||
|
||||
CameraFeedLinux(const String &p_device_name);
|
||||
virtual ~CameraFeedLinux();
|
||||
~CameraFeedLinux() override;
|
||||
};
|
||||
|
||||
#endif // CAMERA_FEED_LINUX_H
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ void CameraLinux::_add_device(const String &p_device_name) {
|
|||
int CameraLinux::_open_device(const String &p_device_name) {
|
||||
struct stat s;
|
||||
|
||||
if (stat(p_device_name.ascii(), &s) == -1) {
|
||||
if (stat(p_device_name.ascii().get_data(), &s) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ int CameraLinux::_open_device(const String &p_device_name) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
return open(p_device_name.ascii(), O_RDWR | O_NONBLOCK, 0);
|
||||
return open(p_device_name.ascii().get_data(), O_RDWR | O_NONBLOCK, 0);
|
||||
}
|
||||
|
||||
// TODO any cheaper/cleaner way to check if file descriptor is invalid?
|
||||
|
|
@ -162,11 +162,25 @@ bool CameraLinux::_can_query_format(int p_file_descriptor, int p_type) {
|
|||
return ioctl(p_file_descriptor, VIDIOC_G_FMT, &format) != -1;
|
||||
}
|
||||
|
||||
CameraLinux::CameraLinux() {
|
||||
camera_thread.start(CameraLinux::camera_thread_func, this);
|
||||
inline void CameraLinux::set_monitoring_feeds(bool p_monitoring_feeds) {
|
||||
if (p_monitoring_feeds == monitoring_feeds) {
|
||||
return;
|
||||
}
|
||||
|
||||
CameraServer::set_monitoring_feeds(p_monitoring_feeds);
|
||||
if (p_monitoring_feeds) {
|
||||
camera_thread.start(CameraLinux::camera_thread_func, this);
|
||||
} else {
|
||||
exit_flag.set();
|
||||
if (camera_thread.is_started()) {
|
||||
camera_thread.wait_to_finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CameraLinux::~CameraLinux() {
|
||||
exit_flag.set();
|
||||
camera_thread.wait_to_finish();
|
||||
if (camera_thread.is_started()) {
|
||||
camera_thread.wait_to_finish();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CAMERA_LINUX_H
|
||||
#define CAMERA_LINUX_H
|
||||
#pragma once
|
||||
|
||||
#include "core/os/mutex.h"
|
||||
#include "core/os/thread.h"
|
||||
|
|
@ -53,8 +52,8 @@ private:
|
|||
bool _can_query_format(int p_file_descriptor, int p_type);
|
||||
|
||||
public:
|
||||
CameraLinux();
|
||||
CameraLinux() = default;
|
||||
~CameraLinux();
|
||||
};
|
||||
|
||||
#endif // CAMERA_LINUX_H
|
||||
void set_monitoring_feeds(bool p_monitoring_feeds) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CAMERA_MACOS_H
|
||||
#define CAMERA_MACOS_H
|
||||
#pragma once
|
||||
|
||||
///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!!
|
||||
// If you fix something here, make sure you fix it there as well!
|
||||
|
|
@ -37,10 +36,11 @@
|
|||
#include "servers/camera_server.h"
|
||||
|
||||
class CameraMacOS : public CameraServer {
|
||||
GDSOFTCLASS(CameraMacOS, CameraServer);
|
||||
|
||||
public:
|
||||
CameraMacOS();
|
||||
CameraMacOS() = default;
|
||||
|
||||
void update_feeds();
|
||||
void set_monitoring_feeds(bool p_monitoring_feeds) override;
|
||||
};
|
||||
|
||||
#endif // CAMERA_MACOS_H
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!!
|
||||
// If you fix something here, make sure you fix it there as well!
|
||||
|
||||
#include "camera_macos.h"
|
||||
#import "camera_macos.h"
|
||||
|
||||
#include "servers/camera/camera_feed.h"
|
||||
|
||||
|
|
@ -195,6 +195,8 @@
|
|||
// CameraFeedMacOS - Subclass for camera feeds in macOS
|
||||
|
||||
class CameraFeedMacOS : public CameraFeed {
|
||||
GDSOFTCLASS(CameraFeedMacOS, CameraFeed);
|
||||
|
||||
private:
|
||||
AVCaptureDevice *device;
|
||||
MyCaptureSession *capture_session;
|
||||
|
|
@ -206,8 +208,8 @@ public:
|
|||
|
||||
void set_device(AVCaptureDevice *p_device);
|
||||
|
||||
bool activate_feed();
|
||||
void deactivate_feed();
|
||||
bool activate_feed() override;
|
||||
void deactivate_feed() override;
|
||||
};
|
||||
|
||||
AVCaptureDevice *CameraFeedMacOS::get_device() const {
|
||||
|
|
@ -359,10 +361,20 @@ void CameraMacOS::update_feeds() {
|
|||
};
|
||||
}
|
||||
|
||||
CameraMacOS::CameraMacOS() {
|
||||
// Find available cameras we have at this time
|
||||
update_feeds();
|
||||
void CameraMacOS::set_monitoring_feeds(bool p_monitoring_feeds) {
|
||||
if (p_monitoring_feeds == monitoring_feeds) {
|
||||
return;
|
||||
}
|
||||
|
||||
// should only have one of these....
|
||||
device_notifications = [[MyDeviceNotifications alloc] initForServer:this];
|
||||
CameraServer::set_monitoring_feeds(p_monitoring_feeds);
|
||||
if (p_monitoring_feeds) {
|
||||
// Find available cameras we have at this time.
|
||||
update_feeds();
|
||||
|
||||
// Get notified on feed changes.
|
||||
device_notifications = [[MyDeviceNotifications alloc] initForServer:this];
|
||||
} else {
|
||||
// Stop monitoring feed changes.
|
||||
device_notifications = nil;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CAMERA_WIN_H
|
||||
#define CAMERA_WIN_H
|
||||
#pragma once
|
||||
|
||||
#include "servers/camera/camera_feed.h"
|
||||
#include "servers/camera_server.h"
|
||||
|
|
@ -42,5 +41,3 @@ public:
|
|||
CameraWindows();
|
||||
~CameraWindows() {}
|
||||
};
|
||||
|
||||
#endif // CAMERA_WIN_H
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CAMERA_REGISTER_TYPES_H
|
||||
#define CAMERA_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_camera_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_camera_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // CAMERA_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ thirdparty_sources = [
|
|||
]
|
||||
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
env_csg.Prepend(CPPPATH=[thirdparty_dir + "include"])
|
||||
env_csg.Prepend(CPPEXTPATH=[thirdparty_dir + "include"])
|
||||
env_thirdparty = env_csg.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CSG_H
|
||||
#define CSG_H
|
||||
#pragma once
|
||||
|
||||
#include "core/math/aabb.h"
|
||||
#include "core/math/transform_3d.h"
|
||||
|
|
@ -65,5 +64,3 @@ struct CSGBrush {
|
|||
void build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_invert_faces);
|
||||
void copy_from(const CSGBrush &p_brush, const Transform3D &p_xform);
|
||||
};
|
||||
|
||||
#endif // CSG_H
|
||||
|
|
|
|||
|
|
@ -36,10 +36,13 @@
|
|||
#include "core/math/geometry_2d.h"
|
||||
#include "scene/resources/3d/navigation_mesh_source_geometry_data_3d.h"
|
||||
#include "scene/resources/navigation_mesh.h"
|
||||
#ifndef NAVIGATION_3D_DISABLED
|
||||
#include "servers/navigation_server_3d.h"
|
||||
#endif // NAVIGATION_3D_DISABLED
|
||||
|
||||
#include <manifold/manifold.h>
|
||||
|
||||
#ifndef NAVIGATION_3D_DISABLED
|
||||
Callable CSGShape3D::_navmesh_source_geometry_parsing_callback;
|
||||
RID CSGShape3D::_navmesh_source_geometry_parser;
|
||||
|
||||
|
|
@ -60,9 +63,13 @@ void CSGShape3D::navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navi
|
|||
}
|
||||
|
||||
NavigationMesh::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
|
||||
uint32_t parsed_collision_mask = p_navigation_mesh->get_collision_mask();
|
||||
|
||||
if (parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES || (parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS && csgshape3d->is_using_collision() && (csgshape3d->get_collision_layer() & parsed_collision_mask)) || parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_BOTH) {
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
bool nav_collision = (parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS && csgshape3d->is_using_collision() && (csgshape3d->get_collision_layer() & p_navigation_mesh->get_collision_mask()));
|
||||
#else
|
||||
bool nav_collision = false;
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
if (parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES || nav_collision || parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_BOTH) {
|
||||
Array meshes = csgshape3d->get_meshes();
|
||||
if (!meshes.is_empty()) {
|
||||
Ref<Mesh> mesh = meshes[1];
|
||||
|
|
@ -72,7 +79,9 @@ void CSGShape3D::navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navi
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // NAVIGATION_3D_DISABLED
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
void CSGShape3D::set_use_collision(bool p_enable) {
|
||||
if (use_collision == p_enable) {
|
||||
return;
|
||||
|
|
@ -186,6 +195,7 @@ void CSGShape3D::set_collision_priority(real_t p_priority) {
|
|||
real_t CSGShape3D::get_collision_priority() const {
|
||||
return collision_priority;
|
||||
}
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
bool CSGShape3D::is_root_shape() const {
|
||||
return !parent_shape;
|
||||
|
|
@ -207,15 +217,20 @@ float CSGShape3D::get_snap() const {
|
|||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
void CSGShape3D::_make_dirty(bool p_parent_removing) {
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
if ((p_parent_removing || is_root_shape()) && !dirty) {
|
||||
callable_mp(this, &CSGShape3D::_update_shape).call_deferred(); // Must be deferred; otherwise, is_root_shape() will use the previous parent.
|
||||
callable_mp(this, &CSGShape3D::update_shape).call_deferred(); // Must be deferred; otherwise, is_root_shape() will use the previous parent.
|
||||
}
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
if (!is_root_shape()) {
|
||||
parent_shape->_make_dirty();
|
||||
} else if (!dirty) {
|
||||
callable_mp(this, &CSGShape3D::_update_shape).call_deferred();
|
||||
}
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
else if (!dirty) {
|
||||
callable_mp(this, &CSGShape3D::update_shape).call_deferred();
|
||||
}
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
|
|
@ -550,7 +565,7 @@ void CSGShape3D::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const
|
|||
surface.tansw[i++] = d < 0 ? -1 : 1;
|
||||
}
|
||||
|
||||
void CSGShape3D::_update_shape() {
|
||||
void CSGShape3D::update_shape() {
|
||||
if (!is_root_shape()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -711,9 +726,20 @@ void CSGShape3D::_update_shape() {
|
|||
|
||||
set_base(root_mesh->get_rid());
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
_update_collision_faces();
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
}
|
||||
|
||||
Ref<ArrayMesh> CSGShape3D::bake_static_mesh() {
|
||||
Ref<ArrayMesh> baked_mesh;
|
||||
if (is_root_shape() && root_mesh.is_valid()) {
|
||||
baked_mesh = root_mesh;
|
||||
}
|
||||
return baked_mesh;
|
||||
}
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
Vector<Vector3> CSGShape3D::_get_brush_collision_faces() {
|
||||
Vector<Vector3> collision_faces;
|
||||
CSGBrush *n = _get_brush();
|
||||
|
|
@ -746,14 +772,6 @@ void CSGShape3D::_update_collision_faces() {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<ArrayMesh> CSGShape3D::bake_static_mesh() {
|
||||
Ref<ArrayMesh> baked_mesh;
|
||||
if (is_root_shape() && root_mesh.is_valid()) {
|
||||
baked_mesh = root_mesh;
|
||||
}
|
||||
return baked_mesh;
|
||||
}
|
||||
|
||||
Ref<ConcavePolygonShape3D> CSGShape3D::bake_collision_shape() {
|
||||
Ref<ConcavePolygonShape3D> baked_collision_shape;
|
||||
if (is_root_shape() && root_collision_shape.is_valid()) {
|
||||
|
|
@ -800,6 +818,7 @@ void CSGShape3D::_on_transform_changed() {
|
|||
RS::get_singleton()->instance_set_transform(root_collision_debug_instance, debug_shape_old_transform);
|
||||
}
|
||||
}
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
AABB CSGShape3D::get_aabb() const {
|
||||
return node_aabb;
|
||||
|
|
@ -872,6 +891,7 @@ void CSGShape3D::_notification(int p_what) {
|
|||
}
|
||||
} break;
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
if (use_collision && is_root_shape()) {
|
||||
root_collision_shape.instantiate();
|
||||
|
|
@ -904,6 +924,7 @@ void CSGShape3D::_notification(int p_what) {
|
|||
}
|
||||
_on_transform_changed();
|
||||
} break;
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -969,17 +990,18 @@ Ref<TriangleMesh> CSGShape3D::generate_triangle_mesh() const {
|
|||
}
|
||||
|
||||
void CSGShape3D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_update_shape"), &CSGShape3D::_update_shape);
|
||||
ClassDB::bind_method(D_METHOD("is_root_shape"), &CSGShape3D::is_root_shape);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_operation", "operation"), &CSGShape3D::set_operation);
|
||||
ClassDB::bind_method(D_METHOD("get_operation"), &CSGShape3D::get_operation);
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
ClassDB::bind_method(D_METHOD("_update_shape"), &CSGShape3D::update_shape);
|
||||
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape3D::set_snap);
|
||||
ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape3D::get_snap);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
ClassDB::bind_method(D_METHOD("set_use_collision", "operation"), &CSGShape3D::set_use_collision);
|
||||
ClassDB::bind_method(D_METHOD("is_using_collision"), &CSGShape3D::is_using_collision);
|
||||
|
||||
|
|
@ -1000,13 +1022,15 @@ void CSGShape3D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CSGShape3D::set_collision_priority);
|
||||
ClassDB::bind_method(D_METHOD("get_collision_priority"), &CSGShape3D::get_collision_priority);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("bake_collision_shape"), &CSGShape3D::bake_collision_shape);
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape3D::set_calculate_tangents);
|
||||
ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape3D::is_calculating_tangents);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_meshes"), &CSGShape3D::get_meshes);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("bake_static_mesh"), &CSGShape3D::bake_static_mesh);
|
||||
ClassDB::bind_method(D_METHOD("bake_collision_shape"), &CSGShape3D::bake_collision_shape);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
|
@ -1014,11 +1038,13 @@ void CSGShape3D::_bind_methods() {
|
|||
#endif // DISABLE_DEPRECATED
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_tangents"), "set_calculate_tangents", "is_calculating_tangents");
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
ADD_GROUP("Collision", "collision_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority");
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
BIND_ENUM_CONSTANT(OPERATION_UNION);
|
||||
BIND_ENUM_CONSTANT(OPERATION_INTERSECTION);
|
||||
|
|
@ -1109,13 +1135,13 @@ CSGBrush *CSGMesh3D::_build_brush() {
|
|||
|
||||
Array arrays = mesh->surface_get_arrays(i);
|
||||
|
||||
if (arrays.size() == 0) {
|
||||
if (arrays.is_empty()) {
|
||||
_make_dirty();
|
||||
ERR_FAIL_COND_V(arrays.is_empty(), memnew(CSGBrush));
|
||||
}
|
||||
|
||||
Vector<Vector3> avertices = arrays[Mesh::ARRAY_VERTEX];
|
||||
if (avertices.size() == 0) {
|
||||
if (avertices.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1231,7 +1257,7 @@ CSGBrush *CSGMesh3D::_build_brush() {
|
|||
}
|
||||
}
|
||||
|
||||
if (vertices.size() == 0) {
|
||||
if (vertices.is_empty()) {
|
||||
return memnew(CSGBrush);
|
||||
}
|
||||
|
||||
|
|
@ -1322,14 +1348,14 @@ CSGBrush *CSGSphere3D::_build_brush() {
|
|||
|
||||
// We want to follow an order that's convenient for UVs.
|
||||
// For latitude step we start at the top and move down like in an image.
|
||||
const double latitude_step = -Math_PI / rings;
|
||||
const double longitude_step = Math_TAU / radial_segments;
|
||||
const double latitude_step = -Math::PI / rings;
|
||||
const double longitude_step = Math::TAU / radial_segments;
|
||||
int face = 0;
|
||||
for (int i = 0; i < rings; i++) {
|
||||
double cos0 = 0;
|
||||
double sin0 = 1;
|
||||
if (i > 0) {
|
||||
double latitude0 = latitude_step * i + Math_TAU / 4;
|
||||
double latitude0 = latitude_step * i + Math::TAU / 4;
|
||||
cos0 = Math::cos(latitude0);
|
||||
sin0 = Math::sin(latitude0);
|
||||
}
|
||||
|
|
@ -1338,7 +1364,7 @@ CSGBrush *CSGSphere3D::_build_brush() {
|
|||
double cos1 = 0;
|
||||
double sin1 = -1;
|
||||
if (i < rings - 1) {
|
||||
double latitude1 = latitude_step * (i + 1) + Math_TAU / 4;
|
||||
double latitude1 = latitude_step * (i + 1) + Math::TAU / 4;
|
||||
cos1 = Math::cos(latitude1);
|
||||
sin1 = Math::sin(latitude1);
|
||||
}
|
||||
|
|
@ -1701,8 +1727,8 @@ CSGBrush *CSGCylinder3D::_build_brush() {
|
|||
inc_n = 0;
|
||||
}
|
||||
|
||||
float ang = inc * Math_TAU;
|
||||
float ang_n = inc_n * Math_TAU;
|
||||
float ang = inc * Math::TAU;
|
||||
float ang_n = inc_n * Math::TAU;
|
||||
|
||||
Vector3 face_base(Math::cos(ang), 0, Math::sin(ang));
|
||||
Vector3 face_base_n(Math::cos(ang_n), 0, Math::sin(ang_n));
|
||||
|
|
@ -1944,8 +1970,8 @@ CSGBrush *CSGTorus3D::_build_brush() {
|
|||
inci_n = 0;
|
||||
}
|
||||
|
||||
float angi = inci * Math_TAU;
|
||||
float angi_n = inci_n * Math_TAU;
|
||||
float angi = inci * Math::TAU;
|
||||
float angi_n = inci_n * Math::TAU;
|
||||
|
||||
Vector3 normali = Vector3(Math::cos(angi), 0, Math::sin(angi));
|
||||
Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n));
|
||||
|
|
@ -1957,8 +1983,8 @@ CSGBrush *CSGTorus3D::_build_brush() {
|
|||
incj_n = 0;
|
||||
}
|
||||
|
||||
float angj = incj * Math_TAU;
|
||||
float angj_n = incj_n * Math_TAU;
|
||||
float angj = incj * Math::TAU;
|
||||
float angj_n = incj_n * Math::TAU;
|
||||
|
||||
Vector2 normalj = Vector2(Math::cos(angj), Math::sin(angj)) * radius + Vector2(min_radius + radius, 0);
|
||||
Vector2 normalj_n = Vector2(Math::cos(angj_n), Math::sin(angj_n)) * radius + Vector2(min_radius + radius, 0);
|
||||
|
|
|
|||
|
|
@ -28,14 +28,16 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CSG_SHAPE_H
|
||||
#define CSG_SHAPE_H
|
||||
#pragma once
|
||||
|
||||
#include "csg.h"
|
||||
|
||||
#include "scene/3d/path_3d.h"
|
||||
#include "scene/3d/visual_instance_3d.h"
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
#include "scene/resources/3d/concave_polygon_shape_3d.h"
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
#include "thirdparty/misc/mikktspace.h"
|
||||
|
||||
|
|
@ -65,6 +67,7 @@ private:
|
|||
bool last_visible = false;
|
||||
float snap = 0.001;
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
bool use_collision = false;
|
||||
uint32_t collision_layer = 1;
|
||||
uint32_t collision_mask = 1;
|
||||
|
|
@ -73,6 +76,7 @@ private:
|
|||
RID root_collision_instance;
|
||||
RID root_collision_debug_instance;
|
||||
Transform3D debug_shape_old_transform;
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
bool calculate_tangents = true;
|
||||
|
||||
|
|
@ -110,13 +114,14 @@ private:
|
|||
static void mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
|
||||
const tbool bIsOrientationPreserving, const int iFace, const int iVert);
|
||||
|
||||
void _update_shape();
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
void _update_collision_faces();
|
||||
bool _is_debug_collision_shape_visible();
|
||||
void _update_debug_collision_shape();
|
||||
void _clear_debug_collision_shape();
|
||||
void _on_transform_changed();
|
||||
Vector<Vector3> _get_brush_collision_faces();
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
|
@ -133,6 +138,7 @@ protected:
|
|||
|
||||
public:
|
||||
Array get_meshes() const;
|
||||
void update_shape();
|
||||
|
||||
void set_operation(Operation p_operation);
|
||||
Operation get_operation() const;
|
||||
|
|
@ -172,10 +178,13 @@ public:
|
|||
bool is_root_shape() const;
|
||||
|
||||
Ref<ArrayMesh> bake_static_mesh();
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
Ref<ConcavePolygonShape3D> bake_collision_shape();
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
virtual Ref<TriangleMesh> generate_triangle_mesh() const override;
|
||||
|
||||
#ifndef NAVIGATION_3D_DISABLED
|
||||
private:
|
||||
static Callable _navmesh_source_geometry_parsing_callback;
|
||||
static RID _navmesh_source_geometry_parser;
|
||||
|
|
@ -183,6 +192,7 @@ private:
|
|||
public:
|
||||
static void navmesh_parse_init();
|
||||
static void navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_node);
|
||||
#endif // NAVIGATION_3D_DISABLED
|
||||
|
||||
CSGShape3D();
|
||||
~CSGShape3D();
|
||||
|
|
@ -482,5 +492,3 @@ public:
|
|||
VARIANT_ENUM_CAST(CSGPolygon3D::Mode)
|
||||
VARIANT_ENUM_CAST(CSGPolygon3D::PathRotation)
|
||||
VARIANT_ENUM_CAST(CSGPolygon3D::PathIntervalType)
|
||||
|
||||
#endif // CSG_SHAPE_H
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@
|
|||
</brief_description>
|
||||
<description>
|
||||
This is the CSG base class that provides CSG operation support to the various CSG nodes in Godot.
|
||||
[b]Performance:[/b] CSG nodes are only intended for prototyping as they have a significant CPU performance cost.
|
||||
Consider baking final CSG operation results into static geometry that replaces the CSG nodes.
|
||||
[b]Performance:[/b] CSG nodes are only intended for prototyping as they have a significant CPU performance cost. Consider baking final CSG operation results into static geometry that replaces the CSG nodes.
|
||||
Individual CSG root node results can be baked to nodes with static resources with the editor menu that appears when a CSG root node is selected.
|
||||
Individual CSG root nodes can also be baked to static resources with scripts by calling [method bake_static_mesh] for the visual mesh or [method bake_collision_shape] for the physics collision.
|
||||
Entire scenes of CSG nodes can be baked to static geometry and exported with the editor gltf scene exporter.
|
||||
Entire scenes of CSG nodes can be baked to static geometry and exported with the editor glTF scene exporter: [b]Scene > Export As... > glTF 2.0 Scene...[/b]
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
|
||||
|
|
@ -20,12 +19,14 @@
|
|||
<description>
|
||||
Returns a baked physics [ConcavePolygonShape3D] of this node's CSG operation result. Returns an empty shape if the node is not a CSG root node or has no valid geometry.
|
||||
[b]Performance:[/b] If the CSG operation results in a very detailed geometry with many faces physics performance will be very slow. Concave shapes should in general only be used for static level geometry and not with dynamic objects that are moving.
|
||||
[b]Note:[/b] CSG mesh data updates are deferred, which means they are updated with a delay of one rendered frame. To avoid getting an empty shape or outdated mesh data, make sure to call [code]await get_tree().process_frame[/code] before using [method bake_collision_shape] in [method Node._ready] or after changing properties on the [CSGShape3D].
|
||||
</description>
|
||||
</method>
|
||||
<method name="bake_static_mesh">
|
||||
<return type="ArrayMesh" />
|
||||
<description>
|
||||
Returns a baked static [ArrayMesh] of this node's CSG operation result. Materials from involved CSG nodes are added as extra mesh surfaces. Returns an empty mesh if the node is not a CSG root node or has no valid geometry.
|
||||
[b]Note:[/b] CSG mesh data updates are deferred, which means they are updated with a delay of one rendered frame. To avoid getting an empty mesh or outdated mesh data, make sure to call [code]await get_tree().process_frame[/code] before using [method bake_static_mesh] in [method Node._ready] or after changing properties on the [CSGShape3D].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_collision_layer_value" qualifiers="const">
|
||||
|
|
@ -46,6 +47,7 @@
|
|||
<return type="Array" />
|
||||
<description>
|
||||
Returns an [Array] with two elements, the first is the [Transform3D] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape.
|
||||
[b]Note:[/b] CSG mesh data updates are deferred, which means they are updated with a delay of one rendered frame. To avoid getting an empty shape or outdated mesh data, make sure to call [code]await get_tree().process_frame[/code] before using [method get_meshes] in [method Node._ready] or after changing properties on the [CSGShape3D].
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_root_shape" qualifiers="const">
|
||||
|
|
@ -73,7 +75,7 @@
|
|||
</methods>
|
||||
<members>
|
||||
<member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents" default="true">
|
||||
Calculate tangents for the CSG shape which allows the use of normal maps. This is only applied on the root shape, this setting is ignored on any child.
|
||||
Calculate tangents for the CSG shape which allows the use of normal and height maps. This is only applied on the root shape, this setting is ignored on any child. Setting this to [code]false[/code] can speed up shape generation slightly.
|
||||
</member>
|
||||
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
|
||||
The physics layers this area is in.
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include "csg_gizmos.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
|
|
@ -156,6 +154,8 @@ CSGShapeEditor::CSGShapeEditor() {
|
|||
options->hide();
|
||||
options->set_text(TTR("CSG"));
|
||||
options->set_switch_on_hover(true);
|
||||
options->set_flat(false);
|
||||
options->set_theme_type_variation("FlatMenuButton");
|
||||
Node3DEditor::get_singleton()->add_control_to_menu_panel(options);
|
||||
|
||||
options->get_popup()->add_item(TTR("Bake Mesh Instance"), MENU_OPTION_BAKE_MESH_INSTANCE);
|
||||
|
|
@ -187,9 +187,6 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() {
|
|||
create_handle_material("handles");
|
||||
}
|
||||
|
||||
CSGShape3DGizmoPlugin::~CSGShape3DGizmoPlugin() {
|
||||
}
|
||||
|
||||
String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
|
||||
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d());
|
||||
|
||||
|
|
@ -227,7 +224,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo
|
|||
|
||||
if (Object::cast_to<CSGCylinder3D>(cs)) {
|
||||
CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs);
|
||||
return p_id == 0 ? s->get_radius() : s->get_height();
|
||||
return Vector2(s->get_radius(), s->get_height());
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGTorus3D>(cs)) {
|
||||
|
|
@ -384,7 +381,7 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
|
|||
|
||||
Vector<Vector3> faces = cs->get_brush_faces();
|
||||
|
||||
if (faces.size() == 0) {
|
||||
if (faces.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -508,5 +505,3 @@ EditorPluginCSG::EditorPluginCSG() {
|
|||
csg_shape_editor = memnew(CSGShapeEditor);
|
||||
EditorNode::get_singleton()->get_gui_base()->add_child(csg_shape_editor);
|
||||
}
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CSG_GIZMOS_H
|
||||
#define CSG_GIZMOS_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#pragma once
|
||||
|
||||
#include "../csg_shape.h"
|
||||
|
||||
|
|
@ -62,7 +59,6 @@ public:
|
|||
virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) override;
|
||||
|
||||
CSGShape3DGizmoPlugin();
|
||||
~CSGShape3DGizmoPlugin();
|
||||
};
|
||||
|
||||
class CSGShapeEditor : public Control {
|
||||
|
|
@ -104,7 +100,3 @@ public:
|
|||
|
||||
EditorPluginCSG();
|
||||
};
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // CSG_GIZMOS_H
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="m8 2 6 3v6l-6 3-6-3V5zm0 12V8l6-3M8 8 2 5" mask="url(#a)"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="m8 2 6 3v6l-6 3-6-3V5zm0 12V8l6-3M8 8 2 5" mask="url(#a)"/></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 451 B |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="M4 6a4 4 0 0 1 8 0v4a4 4 0 0 1-8 0zm0 1.25a2.5 1 0 0 0 8 0m-4-5v12" mask="url(#a)"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="M4 6a4 4 0 0 1 8 0v4a4 4 0 0 1-8 0zm0 1.25a2.5 1 0 0 0 8 0m-4-5v12" mask="url(#a)"/></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 475 B After Width: | Height: | Size: 476 B |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="#fc7f7f" d="M3 1a2 2 0 0 0-2 2h2zm2 0v2h2V1zm4 0v2h2V1zm4 0v2h2a2 2 0 0 0-2-2zM1 5v2h2V5zm12 0v2h2V5zM1 9v2h2V9zm0 4a2 2 0 0 0 2 2v-2zm4 0v2h2v-2z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="#fc7f7f" d="M3 1a2 2 0 0 0-2 2h2zm2 0v2h2V1zm4 0v2h2V1zm4 0v2h2a2 2 0 0 0-2-2zM1 5v2h2V5zm12 0v2h2V5zM1 9v2h2V9zm0 4a2 2 0 0 0 2 2v-2zm4 0v2h2v-2z"/></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 377 B |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="M2 4v8a6 2 0 0 0 12 0V4A6 2 0 0 0 2 4a6 2 0 0 0 12 0" mask="url(#a)"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="M2 4v8a6 2 0 0 0 12 0V4A6 2 0 0 0 2 4a6 2 0 0 0 12 0" mask="url(#a)"/></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 461 B After Width: | Height: | Size: 462 B |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fc7f7f" d="M4.73 2A2 2 0 1 0 2 4.73v6.541A2 2 0 1 0 4.729 14H8v-2H4.729A2 2 0 0 0 4 11.271V5.415l4.914 4.916A2 2 0 0 1 9.998 10a2 2 0 0 1 .33-1.084L5.414 4h5.856a2 2 0 0 0 .73.729V8h2V4.729A2 2 0 1 0 11.27 2z"/><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fc7f7f" d="M4.73 2A2 2 0 1 0 2 4.73v6.541A2 2 0 1 0 4.729 14H8v-2H4.729A2 2 0 0 0 4 11.271V5.415l4.914 4.916A2 2 0 0 1 9.998 10a2 2 0 0 1 .33-1.084L5.414 4h5.856a2 2 0 0 0 .73.729V8h2V4.729A2 2 0 1 0 11.27 2z"/><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 440 B |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-width="2" d="m8 2 6 3.5v5L8 14l-6-3.5v-5h6zm6 3.5L8 9 2 5.5M8 9v5" mask="url(#a)"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-width="2" d="m8 2 6 3.5v5L8 14l-6-3.5v-5h6zm6 3.5L8 9 2 5.5M8 9v5" mask="url(#a)"/></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 485 B After Width: | Height: | Size: 486 B |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="M8 2a6 6 0 0 0 0 12A6 6 0 0 0 8 2v12M2.05 7.4a6 2 0 0 0 11.9 0" mask="url(#a)"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="M8 2a6 6 0 0 0 0 12A6 6 0 0 0 8 2v12M2.05 7.4a6 2 0 0 0 11.9 0" mask="url(#a)"/></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 471 B After Width: | Height: | Size: 472 B |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><g fill="none" stroke="#fc7f7f" mask="url(#a)"><path stroke-width="2" d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z"/><path stroke-linecap="round" stroke-width="1.75" d="M6.2 7.2a2 1 0 1 0 3.6 0"/></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><g fill="none" stroke="#fc7f7f" mask="url(#a)"><path stroke-width="2" d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z"/><path stroke-linecap="round" stroke-width="1.75" d="M6.2 7.2a2 1 0 1 0 3.6 0"/></g></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 561 B After Width: | Height: | Size: 562 B |
|
|
@ -47,7 +47,9 @@ void initialize_csg_module(ModuleInitializationLevel p_level) {
|
|||
GDREGISTER_CLASS(CSGTorus3D);
|
||||
GDREGISTER_CLASS(CSGPolygon3D);
|
||||
GDREGISTER_CLASS(CSGCombiner3D);
|
||||
#ifndef NAVIGATION_3D_DISABLED
|
||||
CSGShape3D::navmesh_parse_init();
|
||||
#endif // NAVIGATION_3D_DISABLED
|
||||
}
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CSG_REGISTER_TYPES_H
|
||||
#define CSG_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_csg_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_csg_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // CSG_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TEST_CSG_H
|
||||
#define TEST_CSG_H
|
||||
#pragma once
|
||||
|
||||
#include "../csg.h"
|
||||
#include "../csg_shape.h"
|
||||
|
|
@ -110,5 +109,3 @@ TEST_CASE("[SceneTree][CSG] CSGPolygon3D") {
|
|||
}
|
||||
|
||||
} // namespace TestCSG
|
||||
|
||||
#endif // TEST_CSG_H
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ thirdparty_sources = [
|
|||
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
env_cvtt.Prepend(CPPPATH=[thirdparty_dir])
|
||||
env_cvtt.Prepend(CPPEXTPATH=[thirdparty_dir])
|
||||
|
||||
env_thirdparty = env_cvtt.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ struct CVTTCompressionJobParams {
|
|||
};
|
||||
|
||||
struct CVTTCompressionRowTask {
|
||||
const uint8_t *in_mm_bytes = nullptr;
|
||||
Vector<uint8_t> in_mm;
|
||||
uint8_t *out_mm_bytes = nullptr;
|
||||
int y_start = 0;
|
||||
int width = 0;
|
||||
|
|
@ -61,7 +61,7 @@ struct CVTTCompressionJobQueue {
|
|||
};
|
||||
|
||||
static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const CVTTCompressionRowTask &p_row_task) {
|
||||
const uint8_t *in_bytes = p_row_task.in_mm_bytes;
|
||||
const uint8_t *in_bytes = p_row_task.in_mm.ptr();
|
||||
uint8_t *out_bytes = p_row_task.out_mm_bytes;
|
||||
int w = p_row_task.width;
|
||||
int h = p_row_task.height;
|
||||
|
|
@ -151,6 +151,11 @@ void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels) {
|
|||
int w = p_image->get_width();
|
||||
int h = p_image->get_height();
|
||||
|
||||
if (w % 4 != 0 || h % 4 != 0) {
|
||||
w = w <= 2 ? w : (w + 3) & ~3;
|
||||
h = h <= 2 ? h : (h + 3) & ~3;
|
||||
}
|
||||
|
||||
bool is_ldr = (p_image->get_format() <= Image::FORMAT_RGBA8);
|
||||
bool is_hdr = (p_image->get_format() >= Image::FORMAT_RF) && (p_image->get_format() <= Image::FORMAT_RGBE9995);
|
||||
|
||||
|
|
@ -180,8 +185,6 @@ void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels) {
|
|||
p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
|
||||
}
|
||||
|
||||
const uint8_t *rb = p_image->get_data().ptr();
|
||||
|
||||
Vector<uint8_t> data;
|
||||
int64_t target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
|
||||
int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
|
||||
|
|
@ -209,20 +212,59 @@ void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels) {
|
|||
Vector<CVTTCompressionRowTask> tasks;
|
||||
|
||||
for (int i = 0; i <= mm_count; i++) {
|
||||
int bw = w % 4 != 0 ? w + (4 - w % 4) : w;
|
||||
int bh = h % 4 != 0 ? h + (4 - h % 4) : h;
|
||||
Vector<uint8_t> in_data;
|
||||
int width, height;
|
||||
Image::get_image_mipmap_offset_and_dimensions(w, h, target_format, i, width, height);
|
||||
|
||||
int64_t src_ofs = p_image->get_mipmap_offset(i);
|
||||
int bw = width % 4 != 0 ? width + (4 - width % 4) : width;
|
||||
int bh = height % 4 != 0 ? height + (4 - height % 4) : height;
|
||||
|
||||
const uint8_t *in_bytes = &rb[src_ofs];
|
||||
int64_t src_mip_ofs, src_mip_size;
|
||||
int src_mip_w, src_mip_h;
|
||||
p_image->get_mipmap_offset_size_and_dimensions(i, src_mip_ofs, src_mip_size, src_mip_w, src_mip_h);
|
||||
|
||||
// Pad textures to nearest block by smearing.
|
||||
if (width != src_mip_w || height != src_mip_h) {
|
||||
const uint8_t *src_mip_read = p_image->ptr() + src_mip_ofs;
|
||||
|
||||
// Reserve the buffer for padded image data.
|
||||
int px_size = Image::get_format_pixel_size(p_image->get_format());
|
||||
in_data.resize(width * height * px_size);
|
||||
uint8_t *ptrw = in_data.ptrw();
|
||||
|
||||
int x = 0, y = 0;
|
||||
for (y = 0; y < src_mip_h; y++) {
|
||||
for (x = 0; x < src_mip_w; x++) {
|
||||
memcpy(ptrw + (width * y + x) * px_size, src_mip_read + (src_mip_w * y + x) * px_size, px_size);
|
||||
}
|
||||
|
||||
// First, smear in x.
|
||||
for (; x < width; x++) {
|
||||
memcpy(ptrw + (width * y + x) * px_size, ptrw + (width * y + x - 1) * px_size, px_size);
|
||||
}
|
||||
}
|
||||
|
||||
// Then, smear in y.
|
||||
for (; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
memcpy(ptrw + (width * y + x) * px_size, ptrw + (width * y + x - width) * px_size, px_size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create a buffer filled with the source mip layer data.
|
||||
in_data.resize(src_mip_size);
|
||||
memcpy(in_data.ptrw(), p_image->ptr() + src_mip_ofs, src_mip_size);
|
||||
}
|
||||
|
||||
//const uint8_t *in_bytes = &rb[src_ofs];
|
||||
uint8_t *out_bytes = &wb[dst_ofs];
|
||||
|
||||
for (int y_start = 0; y_start < h; y_start += 4) {
|
||||
for (int y_start = 0; y_start < height; y_start += 4) {
|
||||
CVTTCompressionRowTask row_task;
|
||||
row_task.width = w;
|
||||
row_task.height = h;
|
||||
row_task.width = width;
|
||||
row_task.height = height;
|
||||
row_task.y_start = y_start;
|
||||
row_task.in_mm_bytes = in_bytes;
|
||||
row_task.in_mm = in_data;
|
||||
row_task.out_mm_bytes = out_bytes;
|
||||
|
||||
tasks.push_back(row_task);
|
||||
|
|
@ -231,8 +273,6 @@ void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels) {
|
|||
}
|
||||
|
||||
dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift;
|
||||
w = MAX(w / 2, 1);
|
||||
h = MAX(h / 2, 1);
|
||||
}
|
||||
|
||||
const CVTTCompressionRowTask *tasks_rb = tasks.ptr();
|
||||
|
|
@ -242,7 +282,7 @@ void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels) {
|
|||
WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&_digest_job_queue, &job_queue, WorkerThreadPool::get_singleton()->get_thread_count(), -1, true, SNAME("CVTT Compress"));
|
||||
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
|
||||
|
||||
p_image->set_data(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
|
||||
p_image->set_data(w, h, p_image->has_mipmaps(), target_format, data);
|
||||
|
||||
print_verbose(vformat("CVTT: Encoding took %d ms.", OS::get_singleton()->get_ticks_msec() - start_time));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef IMAGE_COMPRESS_CVTT_H
|
||||
#define IMAGE_COMPRESS_CVTT_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image.h"
|
||||
|
||||
void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels);
|
||||
void image_decompress_cvtt(Image *p_image);
|
||||
|
||||
#endif // IMAGE_COMPRESS_CVTT_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CVTT_REGISTER_TYPES_H
|
||||
#define CVTT_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
|
|
@ -39,5 +38,3 @@ void initialize_cvtt_module(ModuleInitializationLevel p_level);
|
|||
void uninitialize_cvtt_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // CVTT_REGISTER_TYPES_H
|
||||
|
|
|
|||
203
engine/modules/dds/dds_enums.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/**************************************************************************/
|
||||
/* dds_enums.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image.h"
|
||||
|
||||
#define PF_FOURCC(m_s) ((uint32_t)(((m_s)[3] << 24U) | ((m_s)[2] << 16U) | ((m_s)[1] << 8U) | ((m_s)[0])))
|
||||
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dds-header
|
||||
|
||||
enum {
|
||||
DDS_MAGIC = 0x20534444,
|
||||
DDS_HEADER_SIZE = 124,
|
||||
DDS_PIXELFORMAT_SIZE = 32,
|
||||
|
||||
DDSD_PITCH = 0x00000008,
|
||||
DDSD_LINEARSIZE = 0x00080000,
|
||||
DDSD_MIPMAPCOUNT = 0x00020000,
|
||||
DDSD_CAPS = 0x1,
|
||||
DDSD_HEIGHT = 0x2,
|
||||
DDSD_WIDTH = 0x4,
|
||||
DDSD_PIXELFORMAT = 0x1000,
|
||||
DDPF_ALPHAPIXELS = 0x00000001,
|
||||
DDPF_ALPHAONLY = 0x00000002,
|
||||
DDPF_FOURCC = 0x00000004,
|
||||
DDPF_RGB = 0x00000040,
|
||||
DDPF_RG_SNORM = 0x00080000,
|
||||
|
||||
DDSC2_CUBEMAP = 0x200,
|
||||
DDSC2_VOLUME = 0x200000,
|
||||
|
||||
DX10D_1D = 2,
|
||||
DX10D_2D = 3,
|
||||
DX10D_3D = 4,
|
||||
};
|
||||
|
||||
enum DDSFourCC {
|
||||
DDFCC_DXT1 = PF_FOURCC("DXT1"),
|
||||
DDFCC_DXT2 = PF_FOURCC("DXT2"),
|
||||
DDFCC_DXT3 = PF_FOURCC("DXT3"),
|
||||
DDFCC_DXT4 = PF_FOURCC("DXT4"),
|
||||
DDFCC_DXT5 = PF_FOURCC("DXT5"),
|
||||
DDFCC_ATI1 = PF_FOURCC("ATI1"),
|
||||
DDFCC_BC4U = PF_FOURCC("BC4U"),
|
||||
DDFCC_ATI2 = PF_FOURCC("ATI2"),
|
||||
DDFCC_BC5U = PF_FOURCC("BC5U"),
|
||||
DDFCC_A2XY = PF_FOURCC("A2XY"),
|
||||
DDFCC_DX10 = PF_FOURCC("DX10"),
|
||||
DDFCC_R16F = 111,
|
||||
DDFCC_RG16F = 112,
|
||||
DDFCC_RGBA16F = 113,
|
||||
DDFCC_R32F = 114,
|
||||
DDFCC_RG32F = 115,
|
||||
DDFCC_RGBA32F = 116,
|
||||
};
|
||||
|
||||
// Reference: https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format
|
||||
enum DXGIFormat {
|
||||
DXGI_R32G32B32A32_FLOAT = 2,
|
||||
DXGI_R32G32B32_FLOAT = 6,
|
||||
DXGI_R16G16B16A16_FLOAT = 10,
|
||||
DXGI_R32G32_FLOAT = 16,
|
||||
DXGI_R10G10B10A2_UNORM = 24,
|
||||
DXGI_R8G8B8A8_UNORM = 28,
|
||||
DXGI_R8G8B8A8_UNORM_SRGB = 29,
|
||||
DXGI_R16G16_FLOAT = 34,
|
||||
DXGI_R32_FLOAT = 41,
|
||||
DXGI_R8G8_UNORM = 49,
|
||||
DXGI_R16_FLOAT = 54,
|
||||
DXGI_R8_UNORM = 61,
|
||||
DXGI_A8_UNORM = 65,
|
||||
DXGI_R9G9B9E5 = 67,
|
||||
DXGI_BC1_UNORM = 71,
|
||||
DXGI_BC1_UNORM_SRGB = 72,
|
||||
DXGI_BC2_UNORM = 74,
|
||||
DXGI_BC2_UNORM_SRGB = 75,
|
||||
DXGI_BC3_UNORM = 77,
|
||||
DXGI_BC3_UNORM_SRGB = 78,
|
||||
DXGI_BC4_UNORM = 80,
|
||||
DXGI_BC5_UNORM = 83,
|
||||
DXGI_B5G6R5_UNORM = 85,
|
||||
DXGI_B5G5R5A1_UNORM = 86,
|
||||
DXGI_B8G8R8A8_UNORM = 87,
|
||||
DXGI_BC6H_UF16 = 95,
|
||||
DXGI_BC6H_SF16 = 96,
|
||||
DXGI_BC7_UNORM = 98,
|
||||
DXGI_BC7_UNORM_SRGB = 99,
|
||||
DXGI_B4G4R4A4_UNORM = 115,
|
||||
};
|
||||
|
||||
// The legacy bitmasked format names here represent the actual data layout in the files,
|
||||
// while their official names are flipped (e.g. RGBA8 layout is officially called ABGR8).
|
||||
enum DDSFormat {
|
||||
DDS_DXT1,
|
||||
DDS_DXT3,
|
||||
DDS_DXT5,
|
||||
DDS_ATI1,
|
||||
DDS_ATI2,
|
||||
DDS_BC6U,
|
||||
DDS_BC6S,
|
||||
DDS_BC7,
|
||||
DDS_R16F,
|
||||
DDS_RG16F,
|
||||
DDS_RGBA16F,
|
||||
DDS_R32F,
|
||||
DDS_RG32F,
|
||||
DDS_RGB32F,
|
||||
DDS_RGBA32F,
|
||||
DDS_RGB9E5,
|
||||
DDS_RGB8,
|
||||
DDS_RGBA8,
|
||||
DDS_BGR8,
|
||||
DDS_BGRA8,
|
||||
DDS_BGR5A1,
|
||||
DDS_BGR565,
|
||||
DDS_B2GR3,
|
||||
DDS_B2GR3A8,
|
||||
DDS_BGR10A2,
|
||||
DDS_RGB10A2,
|
||||
DDS_BGRA4,
|
||||
DDS_LUMINANCE,
|
||||
DDS_LUMINANCE_ALPHA,
|
||||
DDS_LUMINANCE_ALPHA_4,
|
||||
DDS_MAX
|
||||
};
|
||||
|
||||
enum DDSType {
|
||||
DDST_2D = 1,
|
||||
DDST_CUBEMAP,
|
||||
DDST_3D,
|
||||
|
||||
DDST_TYPE_MASK = 0x7F,
|
||||
DDST_ARRAY = 0x80,
|
||||
};
|
||||
|
||||
struct DDSFormatInfo {
|
||||
const char *name = nullptr;
|
||||
bool compressed = false;
|
||||
uint32_t divisor = 0;
|
||||
uint32_t block_size = 0;
|
||||
Image::Format format = Image::Format::FORMAT_BPTC_RGBA;
|
||||
};
|
||||
|
||||
static const DDSFormatInfo dds_format_info[DDS_MAX] = {
|
||||
{ "DXT1/BC1", true, 4, 8, Image::FORMAT_DXT1 },
|
||||
{ "DXT2/DXT3/BC2", true, 4, 16, Image::FORMAT_DXT3 },
|
||||
{ "DXT4/DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 },
|
||||
{ "ATI1/BC4", true, 4, 8, Image::FORMAT_RGTC_R },
|
||||
{ "ATI2/A2XY/BC5", true, 4, 16, Image::FORMAT_RGTC_RG },
|
||||
{ "BC6UF", true, 4, 16, Image::FORMAT_BPTC_RGBFU },
|
||||
{ "BC6SF", true, 4, 16, Image::FORMAT_BPTC_RGBF },
|
||||
{ "BC7", true, 4, 16, Image::FORMAT_BPTC_RGBA },
|
||||
{ "R16F", false, 1, 2, Image::FORMAT_RH },
|
||||
{ "RG16F", false, 1, 4, Image::FORMAT_RGH },
|
||||
{ "RGBA16F", false, 1, 8, Image::FORMAT_RGBAH },
|
||||
{ "R32F", false, 1, 4, Image::FORMAT_RF },
|
||||
{ "RG32F", false, 1, 8, Image::FORMAT_RGF },
|
||||
{ "RGB32F", false, 1, 12, Image::FORMAT_RGBF },
|
||||
{ "RGBA32F", false, 1, 16, Image::FORMAT_RGBAF },
|
||||
{ "RGB9E5", false, 1, 4, Image::FORMAT_RGBE9995 },
|
||||
{ "RGB8", false, 1, 3, Image::FORMAT_RGB8 },
|
||||
{ "RGBA8", false, 1, 4, Image::FORMAT_RGBA8 },
|
||||
{ "BGR8", false, 1, 3, Image::FORMAT_RGB8 },
|
||||
{ "BGRA8", false, 1, 4, Image::FORMAT_RGBA8 },
|
||||
{ "BGR5A1", false, 1, 2, Image::FORMAT_RGBA8 },
|
||||
{ "BGR565", false, 1, 2, Image::FORMAT_RGB8 },
|
||||
{ "B2GR3", false, 1, 1, Image::FORMAT_RGB8 },
|
||||
{ "B2GR3A8", false, 1, 2, Image::FORMAT_RGBA8 },
|
||||
{ "BGR10A2", false, 1, 4, Image::FORMAT_RGBA8 },
|
||||
{ "RGB10A2", false, 1, 4, Image::FORMAT_RGBA8 },
|
||||
{ "BGRA4", false, 1, 2, Image::FORMAT_RGBA8 },
|
||||
{ "GRAYSCALE", false, 1, 1, Image::FORMAT_L8 },
|
||||
{ "GRAYSCALE_ALPHA", false, 1, 2, Image::FORMAT_LA8 },
|
||||
{ "GRAYSCALE_ALPHA_4", false, 1, 1, Image::FORMAT_LA8 },
|
||||
};
|
||||
487
engine/modules/dds/image_saver_dds.cpp
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
/**************************************************************************/
|
||||
/* image_saver_dds.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "image_saver_dds.h"
|
||||
|
||||
#include "dds_enums.h"
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/stream_peer.h"
|
||||
|
||||
Error save_dds(const String &p_path, const Ref<Image> &p_img) {
|
||||
Vector<uint8_t> buffer = save_dds_buffer(p_img);
|
||||
|
||||
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE);
|
||||
if (file.is_null()) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
file->store_buffer(buffer.ptr(), buffer.size());
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
enum DDSFormatType {
|
||||
DDFT_BITMASK,
|
||||
DDFT_FOURCC,
|
||||
DDFT_DXGI,
|
||||
};
|
||||
|
||||
DDSFormatType _dds_format_get_type(DDSFormat p_format) {
|
||||
switch (p_format) {
|
||||
case DDS_DXT1:
|
||||
case DDS_DXT3:
|
||||
case DDS_DXT5:
|
||||
case DDS_ATI1:
|
||||
case DDS_ATI2:
|
||||
case DDS_R16F:
|
||||
case DDS_RG16F:
|
||||
case DDS_RGBA16F:
|
||||
case DDS_R32F:
|
||||
case DDS_RG32F:
|
||||
case DDS_RGBA32F:
|
||||
return DDFT_FOURCC;
|
||||
|
||||
case DDS_BC6S:
|
||||
case DDS_BC6U:
|
||||
case DDS_BC7:
|
||||
case DDS_RGB9E5:
|
||||
case DDS_RGB32F:
|
||||
return DDFT_DXGI;
|
||||
|
||||
default:
|
||||
return DDFT_BITMASK;
|
||||
}
|
||||
}
|
||||
|
||||
DDSFormat _image_format_to_dds_format(Image::Format p_image_format) {
|
||||
switch (p_image_format) {
|
||||
case Image::FORMAT_RGBAF: {
|
||||
return DDS_RGBA32F;
|
||||
}
|
||||
case Image::FORMAT_RGBF: {
|
||||
return DDS_RGB32F;
|
||||
}
|
||||
case Image::FORMAT_RGBAH: {
|
||||
return DDS_RGBA16F;
|
||||
}
|
||||
case Image::FORMAT_RGF: {
|
||||
return DDS_RG32F;
|
||||
}
|
||||
case Image::FORMAT_RGBA8: {
|
||||
return DDS_RGBA8;
|
||||
}
|
||||
case Image::FORMAT_RGH: {
|
||||
return DDS_RG16F;
|
||||
}
|
||||
case Image::FORMAT_RF: {
|
||||
return DDS_R32F;
|
||||
}
|
||||
case Image::FORMAT_L8:
|
||||
case Image::FORMAT_R8: {
|
||||
return DDS_LUMINANCE;
|
||||
}
|
||||
case Image::FORMAT_RH: {
|
||||
return DDS_R16F;
|
||||
}
|
||||
case Image::FORMAT_LA8:
|
||||
case Image::FORMAT_RG8: {
|
||||
return DDS_LUMINANCE_ALPHA;
|
||||
}
|
||||
case Image::FORMAT_RGBA4444: {
|
||||
return DDS_BGRA4;
|
||||
}
|
||||
case Image::FORMAT_RGB565: {
|
||||
return DDS_BGR565;
|
||||
}
|
||||
case Image::FORMAT_RGBE9995: {
|
||||
return DDS_RGB9E5;
|
||||
}
|
||||
case Image::FORMAT_DXT1: {
|
||||
return DDS_DXT1;
|
||||
}
|
||||
case Image::FORMAT_DXT3: {
|
||||
return DDS_DXT3;
|
||||
}
|
||||
case Image::FORMAT_DXT5: {
|
||||
return DDS_DXT5;
|
||||
}
|
||||
case Image::FORMAT_RGTC_R: {
|
||||
return DDS_ATI1;
|
||||
}
|
||||
case Image::FORMAT_RGTC_RG: {
|
||||
return DDS_ATI2;
|
||||
}
|
||||
case Image::FORMAT_RGB8: {
|
||||
return DDS_RGB8;
|
||||
}
|
||||
case Image::FORMAT_BPTC_RGBFU: {
|
||||
return DDS_BC6U;
|
||||
}
|
||||
case Image::FORMAT_BPTC_RGBF: {
|
||||
return DDS_BC6S;
|
||||
}
|
||||
case Image::FORMAT_BPTC_RGBA: {
|
||||
return DDS_BC7;
|
||||
}
|
||||
default: {
|
||||
return DDS_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t _image_format_to_fourcc_format(Image::Format p_format) {
|
||||
switch (p_format) {
|
||||
case Image::FORMAT_DXT1:
|
||||
return DDFCC_DXT1;
|
||||
case Image::FORMAT_DXT3:
|
||||
return DDFCC_DXT3;
|
||||
case Image::FORMAT_DXT5:
|
||||
return DDFCC_DXT5;
|
||||
case Image::FORMAT_RGTC_R:
|
||||
return DDFCC_ATI1;
|
||||
case Image::FORMAT_RGTC_RG:
|
||||
return DDFCC_ATI2;
|
||||
case Image::FORMAT_RF:
|
||||
return DDFCC_R32F;
|
||||
case Image::FORMAT_RGF:
|
||||
return DDFCC_RG32F;
|
||||
case Image::FORMAT_RGBAF:
|
||||
return DDFCC_RGBA32F;
|
||||
case Image::FORMAT_RH:
|
||||
return DDFCC_R16F;
|
||||
case Image::FORMAT_RGH:
|
||||
return DDFCC_RG16F;
|
||||
case Image::FORMAT_RGBAH:
|
||||
return DDFCC_RGBA16F;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t _image_format_to_dxgi_format(Image::Format p_format) {
|
||||
switch (p_format) {
|
||||
case Image::FORMAT_DXT1:
|
||||
return DXGI_BC1_UNORM;
|
||||
case Image::FORMAT_DXT3:
|
||||
return DXGI_BC2_UNORM;
|
||||
case Image::FORMAT_DXT5:
|
||||
return DXGI_BC3_UNORM;
|
||||
case Image::FORMAT_RGTC_R:
|
||||
return DXGI_BC4_UNORM;
|
||||
case Image::FORMAT_RGTC_RG:
|
||||
return DXGI_BC5_UNORM;
|
||||
case Image::FORMAT_BPTC_RGBFU:
|
||||
return DXGI_BC6H_UF16;
|
||||
case Image::FORMAT_BPTC_RGBF:
|
||||
return DXGI_BC6H_SF16;
|
||||
case Image::FORMAT_BPTC_RGBA:
|
||||
return DXGI_BC7_UNORM;
|
||||
case Image::FORMAT_RF:
|
||||
return DXGI_R32_FLOAT;
|
||||
case Image::FORMAT_RGF:
|
||||
return DXGI_R32G32_FLOAT;
|
||||
case Image::FORMAT_RGBF:
|
||||
return DXGI_R32G32B32_FLOAT;
|
||||
case Image::FORMAT_RGBAF:
|
||||
return DXGI_R32G32B32A32_FLOAT;
|
||||
case Image::FORMAT_RH:
|
||||
return DXGI_R16_FLOAT;
|
||||
case Image::FORMAT_RGH:
|
||||
return DXGI_R16G16_FLOAT;
|
||||
case Image::FORMAT_RGBAH:
|
||||
return DXGI_R16G16B16A16_FLOAT;
|
||||
case Image::FORMAT_RGBE9995:
|
||||
return DXGI_R9G9B9E5;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void _get_dds_pixel_bitmask(Image::Format p_format, uint32_t &r_bit_count, uint32_t &r_red_mask, uint32_t &r_green_mask, uint32_t &r_blue_mask, uint32_t &r_alpha_mask) {
|
||||
switch (p_format) {
|
||||
case Image::FORMAT_R8:
|
||||
case Image::FORMAT_L8: {
|
||||
r_bit_count = 8;
|
||||
r_red_mask = 0xff;
|
||||
r_green_mask = 0;
|
||||
r_blue_mask = 0;
|
||||
r_alpha_mask = 0;
|
||||
} break;
|
||||
case Image::FORMAT_RG8:
|
||||
case Image::FORMAT_LA8: {
|
||||
r_bit_count = 16;
|
||||
r_red_mask = 0xff;
|
||||
r_green_mask = 0;
|
||||
r_blue_mask = 0;
|
||||
r_alpha_mask = 0xff00;
|
||||
} break;
|
||||
case Image::FORMAT_RGB8: {
|
||||
// BGR8
|
||||
r_bit_count = 24;
|
||||
r_red_mask = 0xff0000;
|
||||
r_green_mask = 0xff00;
|
||||
r_blue_mask = 0xff;
|
||||
r_alpha_mask = 0;
|
||||
} break;
|
||||
case Image::FORMAT_RGBA8: {
|
||||
r_bit_count = 32;
|
||||
r_red_mask = 0xff;
|
||||
r_green_mask = 0xff00;
|
||||
r_blue_mask = 0xff0000;
|
||||
r_alpha_mask = 0xff000000;
|
||||
} break;
|
||||
case Image::FORMAT_RGBA4444: {
|
||||
// BGRA4444
|
||||
r_bit_count = 16;
|
||||
r_red_mask = 0xf00;
|
||||
r_green_mask = 0xf0;
|
||||
r_blue_mask = 0xf;
|
||||
r_alpha_mask = 0xf000;
|
||||
} break;
|
||||
case Image::FORMAT_RGB565: {
|
||||
// BGR565
|
||||
r_bit_count = 16;
|
||||
r_red_mask = 0xf800;
|
||||
r_green_mask = 0x7e0;
|
||||
r_blue_mask = 0x1f;
|
||||
r_alpha_mask = 0;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
r_bit_count = 0;
|
||||
r_red_mask = 0;
|
||||
r_green_mask = 0;
|
||||
r_blue_mask = 0;
|
||||
r_alpha_mask = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<uint8_t> save_dds_buffer(const Ref<Image> &p_img) {
|
||||
Ref<StreamPeerBuffer> stream_buffer;
|
||||
stream_buffer.instantiate();
|
||||
|
||||
Ref<Image> image = p_img;
|
||||
|
||||
stream_buffer->put_32(DDS_MAGIC);
|
||||
stream_buffer->put_32(DDS_HEADER_SIZE);
|
||||
|
||||
uint32_t flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_LINEARSIZE;
|
||||
|
||||
if (image->has_mipmaps()) {
|
||||
flags |= DDSD_MIPMAPCOUNT;
|
||||
}
|
||||
|
||||
stream_buffer->put_32(flags);
|
||||
|
||||
uint32_t height = image->get_height();
|
||||
stream_buffer->put_32(height);
|
||||
|
||||
uint32_t width = image->get_width();
|
||||
stream_buffer->put_32(width);
|
||||
|
||||
DDSFormat dds_format = _image_format_to_dds_format(image->get_format());
|
||||
const DDSFormatInfo &info = dds_format_info[dds_format];
|
||||
|
||||
uint32_t depth = 1; // Default depth for 2D textures
|
||||
|
||||
uint32_t pitch;
|
||||
if (info.compressed) {
|
||||
pitch = ((MAX(info.divisor, width) + info.divisor - 1) / info.divisor) * ((MAX(info.divisor, height) + info.divisor - 1) / info.divisor) * info.block_size;
|
||||
} else {
|
||||
pitch = width * info.block_size;
|
||||
}
|
||||
|
||||
stream_buffer->put_32(pitch);
|
||||
stream_buffer->put_32(depth);
|
||||
|
||||
uint32_t mipmaps = image->get_mipmap_count() + 1;
|
||||
stream_buffer->put_32(mipmaps);
|
||||
|
||||
uint32_t reserved = 0;
|
||||
for (int i = 0; i < 11; i++) {
|
||||
stream_buffer->put_32(reserved);
|
||||
}
|
||||
|
||||
stream_buffer->put_32(DDS_PIXELFORMAT_SIZE);
|
||||
|
||||
uint32_t pf_flags = 0;
|
||||
|
||||
DDSFormatType format_type = _dds_format_get_type(dds_format);
|
||||
|
||||
if (format_type == DDFT_BITMASK) {
|
||||
pf_flags = DDPF_RGB;
|
||||
|
||||
if (image->get_format() == Image::FORMAT_LA8 || image->get_format() == Image::FORMAT_RG8 || image->get_format() == Image::FORMAT_RGBA8 || image->get_format() == Image::FORMAT_RGBA4444) {
|
||||
pf_flags |= DDPF_ALPHAPIXELS;
|
||||
}
|
||||
} else {
|
||||
pf_flags = DDPF_FOURCC;
|
||||
}
|
||||
|
||||
stream_buffer->put_32(pf_flags);
|
||||
|
||||
bool needs_pixeldata_swap = false;
|
||||
|
||||
if (format_type == DDFT_BITMASK) {
|
||||
// Uncompressed bitmasked.
|
||||
stream_buffer->put_32(0); // FourCC
|
||||
|
||||
uint32_t bit_count, r_mask, g_mask, b_mask, a_mask;
|
||||
_get_dds_pixel_bitmask(image->get_format(), bit_count, r_mask, g_mask, b_mask, a_mask);
|
||||
|
||||
stream_buffer->put_32(bit_count);
|
||||
stream_buffer->put_32(r_mask);
|
||||
stream_buffer->put_32(g_mask);
|
||||
stream_buffer->put_32(b_mask);
|
||||
stream_buffer->put_32(a_mask);
|
||||
|
||||
if (image->get_format() == Image::FORMAT_RGBA4444 || image->get_format() == Image::FORMAT_RGB565 || image->get_format() == Image::FORMAT_RGB8) {
|
||||
needs_pixeldata_swap = true;
|
||||
}
|
||||
} else if (format_type == DDFT_FOURCC) {
|
||||
// FourCC.
|
||||
uint32_t fourcc = _image_format_to_fourcc_format(image->get_format());
|
||||
stream_buffer->put_32(fourcc);
|
||||
|
||||
stream_buffer->put_32(0); // Bit count
|
||||
stream_buffer->put_32(0); // R Bitmask
|
||||
stream_buffer->put_32(0); // G Bitmask
|
||||
stream_buffer->put_32(0); // B Bitmask
|
||||
stream_buffer->put_32(0); // A Bitmask
|
||||
} else {
|
||||
// DXGI format and DX10 header.
|
||||
stream_buffer->put_32(DDFCC_DX10);
|
||||
|
||||
stream_buffer->put_32(0); // Bit count
|
||||
stream_buffer->put_32(0); // R Bitmask
|
||||
stream_buffer->put_32(0); // G Bitmask
|
||||
stream_buffer->put_32(0); // B Bitmask
|
||||
stream_buffer->put_32(0); // A Bitmask
|
||||
}
|
||||
|
||||
uint32_t caps1 = info.compressed ? DDSD_LINEARSIZE : DDSD_PITCH;
|
||||
stream_buffer->put_32(caps1);
|
||||
|
||||
stream_buffer->put_32(0); // Caps2
|
||||
stream_buffer->put_32(0); // Caps3
|
||||
stream_buffer->put_32(0); // Caps4
|
||||
stream_buffer->put_32(0); // Reserved 2
|
||||
|
||||
if (format_type == DDFT_DXGI) {
|
||||
// DX10 header.
|
||||
uint32_t dxgi_format = _image_format_to_dxgi_format(image->get_format());
|
||||
stream_buffer->put_32(dxgi_format);
|
||||
stream_buffer->put_32(DX10D_2D);
|
||||
stream_buffer->put_32(0); // Misc flags 1
|
||||
stream_buffer->put_32(1); // Array size
|
||||
stream_buffer->put_32(0); // Misc flags 2
|
||||
}
|
||||
|
||||
for (uint32_t mip_i = 0; mip_i < mipmaps; mip_i++) {
|
||||
uint32_t mip_width = MAX(1u, width >> mip_i);
|
||||
uint32_t mip_height = MAX(1u, height >> mip_i);
|
||||
|
||||
uint32_t expected_size = 0;
|
||||
if (info.compressed) {
|
||||
uint32_t blocks_x = (mip_width + info.divisor - 1) / info.divisor;
|
||||
uint32_t blocks_y = (mip_height + info.divisor - 1) / info.divisor;
|
||||
expected_size = blocks_x * blocks_y * info.block_size;
|
||||
} else {
|
||||
expected_size = mip_width * mip_height * info.block_size;
|
||||
}
|
||||
|
||||
if (needs_pixeldata_swap) {
|
||||
// The image's channels need to be swapped.
|
||||
Ref<Image> mip_image = image->get_image_from_mipmap(mip_i);
|
||||
Vector<uint8_t> data = mip_image->get_data();
|
||||
|
||||
ERR_FAIL_COND_V_MSG(data.size() != expected_size, Vector<uint8_t>(),
|
||||
"Image data size mismatch for mipmap level " + itos(mip_i) +
|
||||
". Expected size: " + itos(expected_size) + ", actual size: " + itos(data.size()) + ".");
|
||||
|
||||
if (mip_image->get_format() == Image::FORMAT_RGBA4444) {
|
||||
// RGBA4 to BGRA4
|
||||
const int64_t data_size = data.size();
|
||||
uint8_t *wb = data.ptrw();
|
||||
|
||||
for (int64_t data_i = 0; data_i < data_size; data_i += 2) {
|
||||
uint8_t ar = wb[data_i + 0];
|
||||
uint8_t gb = wb[data_i + 1];
|
||||
|
||||
wb[data_i + 1] = ((ar & 0x0F) << 4) | ((gb & 0xF0) >> 4);
|
||||
wb[data_i + 0] = ((ar & 0xF0) >> 4) | ((gb & 0x0F) << 4);
|
||||
}
|
||||
} else if (mip_image->get_format() == Image::FORMAT_RGB565) {
|
||||
// RGB565 to BGR565
|
||||
const int64_t data_size = data.size();
|
||||
uint8_t *wb = data.ptrw();
|
||||
|
||||
for (int64_t data_i = 0; data_i < data_size; data_i += 2) {
|
||||
uint16_t px = wb[data_i] | (wb[data_i + 1] << 8);
|
||||
|
||||
uint8_t r = (px >> 11) & 0x1F;
|
||||
uint8_t g = (px >> 5) & 0x3F;
|
||||
uint8_t b = px & 0x1F;
|
||||
|
||||
uint16_t out_px = (b << 11) | (g << 5) | r;
|
||||
|
||||
wb[data_i + 0] = out_px & 0xFF;
|
||||
wb[data_i + 1] = (out_px >> 8) & 0xFF;
|
||||
}
|
||||
} else if (mip_image->get_format() == Image::FORMAT_RGB8) {
|
||||
// RGB8 to BGR8
|
||||
const int64_t data_size = data.size();
|
||||
uint8_t *wb = data.ptrw();
|
||||
|
||||
for (int64_t data_i = 0; data_i < data_size; data_i += 3) {
|
||||
SWAP(wb[data_i], wb[data_i + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
stream_buffer->put_data(data.ptr(), data.size());
|
||||
} else {
|
||||
int64_t ofs, size;
|
||||
|
||||
image->get_mipmap_offset_and_size(mip_i, ofs, size);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(size != expected_size, Vector<uint8_t>(),
|
||||
"Image data size mismatch for mipmap level " + itos(mip_i) +
|
||||
". Expected size: " + itos(expected_size) + ", actual size: " + itos(size) + ".");
|
||||
|
||||
stream_buffer->put_data(image->ptr() + ofs, size);
|
||||
}
|
||||
}
|
||||
|
||||
return stream_buffer->get_data_array();
|
||||
}
|
||||
36
engine/modules/dds/image_saver_dds.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/**************************************************************************/
|
||||
/* image_saver_dds.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image.h"
|
||||
|
||||
Error save_dds(const String &p_path, const Ref<Image> &p_img);
|
||||
Vector<uint8_t> save_dds_buffer(const Ref<Image> &p_img);
|
||||
|
|
@ -30,8 +30,11 @@
|
|||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "image_saver_dds.h"
|
||||
#include "texture_loader_dds.h"
|
||||
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
static Ref<ResourceFormatDDS> resource_loader_dds;
|
||||
|
||||
void initialize_dds_module(ModuleInitializationLevel p_level) {
|
||||
|
|
@ -39,8 +42,13 @@ void initialize_dds_module(ModuleInitializationLevel p_level) {
|
|||
return;
|
||||
}
|
||||
|
||||
resource_loader_dds.instantiate();
|
||||
ResourceLoader::add_resource_format_loader(resource_loader_dds);
|
||||
Image::save_dds_func = save_dds;
|
||||
Image::save_dds_buffer_func = save_dds_buffer;
|
||||
|
||||
if (GD_IS_CLASS_ENABLED(Texture)) {
|
||||
resource_loader_dds.instantiate();
|
||||
ResourceLoader::add_resource_format_loader(resource_loader_dds);
|
||||
}
|
||||
}
|
||||
|
||||
void uninitialize_dds_module(ModuleInitializationLevel p_level) {
|
||||
|
|
@ -48,6 +56,11 @@ void uninitialize_dds_module(ModuleInitializationLevel p_level) {
|
|||
return;
|
||||
}
|
||||
|
||||
ResourceLoader::remove_resource_format_loader(resource_loader_dds);
|
||||
resource_loader_dds.unref();
|
||||
if (GD_IS_CLASS_ENABLED(Texture)) {
|
||||
ResourceLoader::remove_resource_format_loader(resource_loader_dds);
|
||||
resource_loader_dds.unref();
|
||||
}
|
||||
|
||||
Image::save_dds_func = nullptr;
|
||||
Image::save_dds_buffer_func = nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DDS_REGISTER_TYPES_H
|
||||
#define DDS_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_dds_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_dds_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // DDS_REGISTER_TYPES_H
|
||||
|
|
|
|||
161
engine/modules/dds/tests/test_dds.h
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/**************************************************************************/
|
||||
/* test_dds.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../image_saver_dds.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/image.h"
|
||||
#include "tests/core/config/test_project_settings.h"
|
||||
#include "tests/test_macros.h"
|
||||
#include "tests/test_utils.h"
|
||||
|
||||
namespace TestDDS {
|
||||
String init(const String &p_test, const String &p_copy_target = String()) {
|
||||
String old_resource_path = TestProjectSettingsInternalsAccessor::resource_path();
|
||||
Error err;
|
||||
// Setup project settings since it's needed for the import process.
|
||||
String project_folder = TestUtils::get_temp_path(p_test.get_file().get_basename());
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
da->make_dir_recursive(project_folder.path_join(".godot").path_join("imported"));
|
||||
// Initialize res:// to `project_folder`.
|
||||
TestProjectSettingsInternalsAccessor::resource_path() = project_folder;
|
||||
err = ProjectSettings::get_singleton()->setup(project_folder, String(), true);
|
||||
|
||||
if (p_copy_target.is_empty()) {
|
||||
return old_resource_path;
|
||||
}
|
||||
|
||||
// Copy all the necessary test data files to the res:// directory.
|
||||
da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
String test_data = String("tests/data").path_join(p_test);
|
||||
da = DirAccess::open(test_data);
|
||||
CHECK_MESSAGE(da.is_valid(), "Unable to open folder.");
|
||||
da->list_dir_begin();
|
||||
for (String item = da->get_next(); !item.is_empty(); item = da->get_next()) {
|
||||
if (!FileAccess::exists(test_data.path_join(item))) {
|
||||
continue;
|
||||
}
|
||||
Ref<FileAccess> output = FileAccess::open(p_copy_target.path_join(item), FileAccess::WRITE, &err);
|
||||
CHECK_MESSAGE(err == OK, "Unable to open output file.");
|
||||
output->store_buffer(FileAccess::get_file_as_bytes(test_data.path_join(item)));
|
||||
output->close();
|
||||
}
|
||||
da->list_dir_end();
|
||||
return old_resource_path;
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][DDSSaver] Save DDS - Save valid image with mipmap" * doctest::skip(true)) {
|
||||
String old_resource_path = init("save_dds_valid_image_with_mipmap");
|
||||
Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
|
||||
image->fill(Color(1, 0, 0)); // Fill with red color
|
||||
image->generate_mipmaps();
|
||||
image->compress_from_channels(Image::COMPRESS_S3TC, Image::USED_CHANNELS_RGBA);
|
||||
Error err = save_dds("res://valid_image_with_mipmap.dds", image);
|
||||
CHECK(err == OK);
|
||||
|
||||
Ref<Image> loaded_image;
|
||||
loaded_image.instantiate();
|
||||
Vector<uint8_t> buffer = FileAccess::get_file_as_bytes("res://valid_image_with_mipmap.dds", &err);
|
||||
CHECK(err == OK);
|
||||
err = loaded_image->load_dds_from_buffer(buffer);
|
||||
CHECK(err == OK);
|
||||
Dictionary metrics = image->compute_image_metrics(loaded_image, false);
|
||||
CHECK(metrics.size() > 0);
|
||||
CHECK_MESSAGE(metrics.has("root_mean_squared"), "Metrics dictionary contains 'root_mean_squared'.");
|
||||
float rms = metrics["root_mean_squared"];
|
||||
CHECK(rms == 0.0f);
|
||||
TestProjectSettingsInternalsAccessor::resource_path() = old_resource_path;
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][DDSSaver] Save DDS - Save valid image with BPTC and S3TC compression" * doctest::skip(true)) {
|
||||
String old_resource_path = init("save_dds_valid_image_bptc_s3tc");
|
||||
Ref<Image> image_bptc = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
|
||||
image_bptc->fill(Color(0, 0, 1)); // Fill with blue color
|
||||
image_bptc->compress_from_channels(Image::COMPRESS_BPTC, Image::USED_CHANNELS_RGBA);
|
||||
Error err_bptc = image_bptc->save_dds("res://valid_image_bptc.dds");
|
||||
CHECK(err_bptc == OK);
|
||||
|
||||
Ref<Image> image_s3tc = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
|
||||
image_s3tc->fill(Color(1, 1, 1)); // Fill with white color
|
||||
image_s3tc->compress_from_channels(Image::COMPRESS_S3TC, Image::USED_CHANNELS_RGBA);
|
||||
Error err_s3tc = image_s3tc->save_dds("res://valid_image_s3tc_combined.dds");
|
||||
CHECK(err_s3tc == OK);
|
||||
|
||||
// Validate BPTC image
|
||||
Ref<Image> loaded_image_bptc;
|
||||
loaded_image_bptc.instantiate();
|
||||
Vector<uint8_t> buffer_bptc = FileAccess::get_file_as_bytes("res://valid_image_bptc.dds", &err_bptc);
|
||||
CHECK(err_bptc == OK);
|
||||
err_bptc = loaded_image_bptc->load_dds_from_buffer(buffer_bptc);
|
||||
CHECK(err_bptc == OK);
|
||||
Dictionary metrics_bptc = image_bptc->compute_image_metrics(loaded_image_bptc, false);
|
||||
CHECK(metrics_bptc.size() > 0);
|
||||
CHECK_MESSAGE(metrics_bptc.has("root_mean_squared"), "Metrics dictionary contains 'root_mean_squared' for BPTC.");
|
||||
float rms_bptc = metrics_bptc["root_mean_squared"];
|
||||
CHECK(rms_bptc == 0.0f);
|
||||
|
||||
// Validate S3TC image
|
||||
Ref<Image> loaded_image_s3tc;
|
||||
loaded_image_s3tc.instantiate();
|
||||
Vector<uint8_t> buffer_s3tc = FileAccess::get_file_as_bytes("res://valid_image_s3tc_combined.dds", &err_s3tc);
|
||||
CHECK(err_s3tc == OK);
|
||||
err_s3tc = loaded_image_s3tc->load_dds_from_buffer(buffer_s3tc);
|
||||
CHECK(err_s3tc == OK);
|
||||
Dictionary metrics_s3tc = image_s3tc->compute_image_metrics(loaded_image_s3tc, false);
|
||||
CHECK(metrics_s3tc.size() > 0);
|
||||
CHECK_MESSAGE(metrics_s3tc.has("root_mean_squared"), "Metrics dictionary contains 'root_mean_squared' for S3TC.");
|
||||
float rms_s3tc = metrics_s3tc["root_mean_squared"];
|
||||
CHECK(rms_s3tc == 0.0f);
|
||||
TestProjectSettingsInternalsAccessor::resource_path() = old_resource_path;
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][DDSSaver] Save DDS - Save valid uncompressed image") {
|
||||
String old_resource_path = init("save_dds_valid_uncompressed");
|
||||
Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
|
||||
image->fill(Color(0, 0, 1)); // Fill with blue color
|
||||
Error err = image->save_dds("res://valid_image_uncompressed.dds");
|
||||
CHECK(err == OK);
|
||||
Vector<uint8_t> buffer = FileAccess::get_file_as_bytes("res://valid_image_uncompressed.dds", &err);
|
||||
CHECK(err == OK);
|
||||
Ref<Image> loaded_image;
|
||||
loaded_image.instantiate();
|
||||
err = loaded_image->load_dds_from_buffer(buffer);
|
||||
CHECK(err == OK);
|
||||
Dictionary metrics = image->compute_image_metrics(loaded_image, false);
|
||||
CHECK(metrics.size() > 0);
|
||||
CHECK_MESSAGE(metrics.has("root_mean_squared"), "Metrics dictionary contains 'root_mean_squared' for uncompressed.");
|
||||
float rms = metrics["root_mean_squared"];
|
||||
CHECK(rms == 0.0f);
|
||||
TestProjectSettingsInternalsAccessor::resource_path() = old_resource_path;
|
||||
}
|
||||
} //namespace TestDDS
|
||||
|
|
@ -30,171 +30,13 @@
|
|||
|
||||
#include "texture_loader_dds.h"
|
||||
|
||||
#include "dds_enums.h"
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/file_access_memory.h"
|
||||
#include "scene/resources/image_texture.h"
|
||||
|
||||
#define PF_FOURCC(s) ((uint32_t)(((s)[3] << 24U) | ((s)[2] << 16U) | ((s)[1] << 8U) | ((s)[0])))
|
||||
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dds-header
|
||||
|
||||
enum {
|
||||
DDS_MAGIC = 0x20534444,
|
||||
DDSD_PITCH = 0x00000008,
|
||||
DDSD_LINEARSIZE = 0x00080000,
|
||||
DDSD_MIPMAPCOUNT = 0x00020000,
|
||||
DDPF_ALPHAPIXELS = 0x00000001,
|
||||
DDPF_ALPHAONLY = 0x00000002,
|
||||
DDPF_FOURCC = 0x00000004,
|
||||
DDPF_RGB = 0x00000040,
|
||||
DDPF_RG_SNORM = 0x00080000,
|
||||
DDSC2_CUBEMAP = 0x200,
|
||||
DDSC2_VOLUME = 0x200000,
|
||||
DX10D_1D = 2,
|
||||
DX10D_2D = 3,
|
||||
DX10D_3D = 4,
|
||||
};
|
||||
|
||||
enum DDSFourCC {
|
||||
DDFCC_DXT1 = PF_FOURCC("DXT1"),
|
||||
DDFCC_DXT2 = PF_FOURCC("DXT2"),
|
||||
DDFCC_DXT3 = PF_FOURCC("DXT3"),
|
||||
DDFCC_DXT4 = PF_FOURCC("DXT4"),
|
||||
DDFCC_DXT5 = PF_FOURCC("DXT5"),
|
||||
DDFCC_ATI1 = PF_FOURCC("ATI1"),
|
||||
DDFCC_BC4U = PF_FOURCC("BC4U"),
|
||||
DDFCC_ATI2 = PF_FOURCC("ATI2"),
|
||||
DDFCC_BC5U = PF_FOURCC("BC5U"),
|
||||
DDFCC_A2XY = PF_FOURCC("A2XY"),
|
||||
DDFCC_DX10 = PF_FOURCC("DX10"),
|
||||
DDFCC_R16F = 111,
|
||||
DDFCC_RG16F = 112,
|
||||
DDFCC_RGBA16F = 113,
|
||||
DDFCC_R32F = 114,
|
||||
DDFCC_RG32F = 115,
|
||||
DDFCC_RGBA32F = 116
|
||||
};
|
||||
|
||||
// Reference: https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format
|
||||
enum DXGIFormat {
|
||||
DXGI_R32G32B32A32_FLOAT = 2,
|
||||
DXGI_R32G32B32_FLOAT = 6,
|
||||
DXGI_R16G16B16A16_FLOAT = 10,
|
||||
DXGI_R32G32_FLOAT = 16,
|
||||
DXGI_R10G10B10A2_UNORM = 24,
|
||||
DXGI_R8G8B8A8_UNORM = 28,
|
||||
DXGI_R8G8B8A8_UNORM_SRGB = 29,
|
||||
DXGI_R16G16_FLOAT = 34,
|
||||
DXGI_R32_FLOAT = 41,
|
||||
DXGI_R8G8_UNORM = 49,
|
||||
DXGI_R16_FLOAT = 54,
|
||||
DXGI_R8_UNORM = 61,
|
||||
DXGI_A8_UNORM = 65,
|
||||
DXGI_R9G9B9E5 = 67,
|
||||
DXGI_BC1_UNORM = 71,
|
||||
DXGI_BC1_UNORM_SRGB = 72,
|
||||
DXGI_BC2_UNORM = 74,
|
||||
DXGI_BC2_UNORM_SRGB = 75,
|
||||
DXGI_BC3_UNORM = 77,
|
||||
DXGI_BC3_UNORM_SRGB = 78,
|
||||
DXGI_BC4_UNORM = 80,
|
||||
DXGI_BC5_UNORM = 83,
|
||||
DXGI_B5G6R5_UNORM = 85,
|
||||
DXGI_B5G5R5A1_UNORM = 86,
|
||||
DXGI_B8G8R8A8_UNORM = 87,
|
||||
DXGI_BC6H_UF16 = 95,
|
||||
DXGI_BC6H_SF16 = 96,
|
||||
DXGI_BC7_UNORM = 98,
|
||||
DXGI_BC7_UNORM_SRGB = 99,
|
||||
DXGI_B4G4R4A4_UNORM = 115
|
||||
};
|
||||
|
||||
// The legacy bitmasked format names here represent the actual data layout in the files,
|
||||
// while their official names are flipped (e.g. RGBA8 layout is officially called ABGR8).
|
||||
enum DDSFormat {
|
||||
DDS_DXT1,
|
||||
DDS_DXT3,
|
||||
DDS_DXT5,
|
||||
DDS_ATI1,
|
||||
DDS_ATI2,
|
||||
DDS_BC6U,
|
||||
DDS_BC6S,
|
||||
DDS_BC7,
|
||||
DDS_R16F,
|
||||
DDS_RG16F,
|
||||
DDS_RGBA16F,
|
||||
DDS_R32F,
|
||||
DDS_RG32F,
|
||||
DDS_RGB32F,
|
||||
DDS_RGBA32F,
|
||||
DDS_RGB9E5,
|
||||
DDS_RGB8,
|
||||
DDS_RGBA8,
|
||||
DDS_BGR8,
|
||||
DDS_BGRA8,
|
||||
DDS_BGR5A1,
|
||||
DDS_BGR565,
|
||||
DDS_B2GR3,
|
||||
DDS_B2GR3A8,
|
||||
DDS_BGR10A2,
|
||||
DDS_RGB10A2,
|
||||
DDS_BGRA4,
|
||||
DDS_LUMINANCE,
|
||||
DDS_LUMINANCE_ALPHA,
|
||||
DDS_LUMINANCE_ALPHA_4,
|
||||
DDS_MAX
|
||||
};
|
||||
|
||||
enum DDSType {
|
||||
DDST_2D = 1,
|
||||
DDST_CUBEMAP,
|
||||
DDST_3D,
|
||||
|
||||
DDST_TYPE_MASK = 0x7F,
|
||||
DDST_ARRAY = 0x80,
|
||||
};
|
||||
|
||||
struct DDSFormatInfo {
|
||||
const char *name = nullptr;
|
||||
bool compressed = false;
|
||||
uint32_t divisor = 0;
|
||||
uint32_t block_size = 0;
|
||||
Image::Format format = Image::Format::FORMAT_BPTC_RGBA;
|
||||
};
|
||||
|
||||
static const DDSFormatInfo dds_format_info[DDS_MAX] = {
|
||||
{ "DXT1/BC1", true, 4, 8, Image::FORMAT_DXT1 },
|
||||
{ "DXT2/DXT3/BC2", true, 4, 16, Image::FORMAT_DXT3 },
|
||||
{ "DXT4/DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 },
|
||||
{ "ATI1/BC4", true, 4, 8, Image::FORMAT_RGTC_R },
|
||||
{ "ATI2/A2XY/BC5", true, 4, 16, Image::FORMAT_RGTC_RG },
|
||||
{ "BC6UF", true, 4, 16, Image::FORMAT_BPTC_RGBFU },
|
||||
{ "BC6SF", true, 4, 16, Image::FORMAT_BPTC_RGBF },
|
||||
{ "BC7", true, 4, 16, Image::FORMAT_BPTC_RGBA },
|
||||
{ "R16F", false, 1, 2, Image::FORMAT_RH },
|
||||
{ "RG16F", false, 1, 4, Image::FORMAT_RGH },
|
||||
{ "RGBA16F", false, 1, 8, Image::FORMAT_RGBAH },
|
||||
{ "R32F", false, 1, 4, Image::FORMAT_RF },
|
||||
{ "RG32F", false, 1, 8, Image::FORMAT_RGF },
|
||||
{ "RGB32F", false, 1, 12, Image::FORMAT_RGBF },
|
||||
{ "RGBA32F", false, 1, 16, Image::FORMAT_RGBAF },
|
||||
{ "RGB9E5", false, 1, 4, Image::FORMAT_RGBE9995 },
|
||||
{ "RGB8", false, 1, 3, Image::FORMAT_RGB8 },
|
||||
{ "RGBA8", false, 1, 4, Image::FORMAT_RGBA8 },
|
||||
{ "BGR8", false, 1, 3, Image::FORMAT_RGB8 },
|
||||
{ "BGRA8", false, 1, 4, Image::FORMAT_RGBA8 },
|
||||
{ "BGR5A1", false, 1, 2, Image::FORMAT_RGBA8 },
|
||||
{ "BGR565", false, 1, 2, Image::FORMAT_RGB8 },
|
||||
{ "B2GR3", false, 1, 1, Image::FORMAT_RGB8 },
|
||||
{ "B2GR3A8", false, 1, 2, Image::FORMAT_RGBA8 },
|
||||
{ "BGR10A2", false, 1, 4, Image::FORMAT_RGBA8 },
|
||||
{ "RGB10A2", false, 1, 4, Image::FORMAT_RGBA8 },
|
||||
{ "BGRA4", false, 1, 2, Image::FORMAT_RGBA8 },
|
||||
{ "GRAYSCALE", false, 1, 1, Image::FORMAT_L8 },
|
||||
{ "GRAYSCALE_ALPHA", false, 1, 2, Image::FORMAT_LA8 },
|
||||
{ "GRAYSCALE_ALPHA_4", false, 1, 1, Image::FORMAT_LA8 }
|
||||
};
|
||||
|
||||
inline DDSFormat _dxgi_to_dds_format(uint32_t p_dxgi_format) {
|
||||
DDSFormat _dxgi_to_dds_format(uint32_t p_dxgi_format) {
|
||||
switch (p_dxgi_format) {
|
||||
case DXGI_R32G32B32A32_FLOAT: {
|
||||
return DDS_RGBA32F;
|
||||
|
|
@ -323,8 +165,8 @@ static Ref<Image> _dds_load_layer(Ref<FileAccess> p_file, DDSFormat p_dds_format
|
|||
uint32_t size = p_width * p_height * info.block_size;
|
||||
|
||||
for (uint32_t i = 1; i < p_mipmaps; i++) {
|
||||
w = (w + 1) >> 1;
|
||||
h = (h + 1) >> 1;
|
||||
w = MAX(1u, w >> 1);
|
||||
h = MAX(1u, h >> 1);
|
||||
size += w * h * info.block_size;
|
||||
}
|
||||
|
||||
|
|
@ -543,7 +385,295 @@ static Ref<Image> _dds_load_layer(Ref<FileAccess> p_file, DDSFormat p_dds_format
|
|||
return memnew(Image(p_width, p_height, p_mipmaps > 1, info.format, r_src_data));
|
||||
}
|
||||
|
||||
Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
static Vector<Ref<Image>> _dds_load_images(Ref<FileAccess> p_f, DDSFormat p_dds_format, uint32_t p_width, uint32_t p_height, uint32_t p_mipmaps, uint32_t p_pitch, uint32_t p_flags, uint32_t p_layer_count) {
|
||||
Vector<uint8_t> src_data;
|
||||
Vector<Ref<Image>> images;
|
||||
images.resize(p_layer_count);
|
||||
|
||||
for (uint32_t i = 0; i < p_layer_count; i++) {
|
||||
images.write[i] = _dds_load_layer(p_f, p_dds_format, p_width, p_height, p_mipmaps, p_pitch, p_flags, src_data);
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
static Ref<Resource> _dds_create_texture(const Vector<Ref<Image>> &p_images, uint32_t p_dds_type, uint32_t p_width, uint32_t p_height, uint32_t p_layer_count, uint32_t p_mipmaps, Error *r_error) {
|
||||
if ((p_dds_type & DDST_TYPE_MASK) == DDST_2D) {
|
||||
if (p_dds_type & DDST_ARRAY) {
|
||||
Ref<Texture2DArray> texture;
|
||||
texture.instantiate();
|
||||
texture->create_from_images(p_images);
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return texture;
|
||||
|
||||
} else {
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return ImageTexture::create_from_image(p_images[0]);
|
||||
}
|
||||
|
||||
} else if ((p_layer_count & DDST_TYPE_MASK) == DDST_CUBEMAP) {
|
||||
ERR_FAIL_COND_V(p_layer_count % 6 != 0, Ref<Resource>());
|
||||
|
||||
if (p_dds_type & DDST_ARRAY) {
|
||||
Ref<CubemapArray> texture;
|
||||
texture.instantiate();
|
||||
texture->create_from_images(p_images);
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return texture;
|
||||
|
||||
} else {
|
||||
Ref<Cubemap> texture;
|
||||
texture.instantiate();
|
||||
texture->create_from_images(p_images);
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
} else if ((p_dds_type & DDST_TYPE_MASK) == DDST_3D) {
|
||||
Ref<ImageTexture3D> texture;
|
||||
texture.instantiate();
|
||||
texture->create(p_images[0]->get_format(), p_width, p_height, p_layer_count, p_mipmaps > 1, p_images);
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
return Ref<Resource>();
|
||||
}
|
||||
|
||||
static Ref<Resource> _dds_create_texture_from_images(const Vector<Ref<Image>> &p_images, DDSFormat p_dds_format, uint32_t p_width, uint32_t p_height, uint32_t p_mipmaps, uint32_t p_pitch, uint32_t p_flags, uint32_t p_layer_count, uint32_t p_dds_type, Error *r_error) {
|
||||
return _dds_create_texture(p_images, p_dds_type, p_width, p_height, p_layer_count, p_mipmaps, r_error);
|
||||
}
|
||||
|
||||
static Vector<Ref<Image>> _dds_load_images_from_buffer(Ref<FileAccess> p_f, DDSFormat &r_dds_format, uint32_t &r_width, uint32_t &r_height, uint32_t &r_mipmaps, uint32_t &r_pitch, uint32_t &r_flags, uint32_t &r_layer_count, uint32_t &r_dds_type, const String &p_path = "") {
|
||||
ERR_FAIL_COND_V_MSG(p_f.is_null(), Vector<Ref<Image>>(), vformat("Empty DDS texture file."));
|
||||
ERR_FAIL_COND_V_MSG(!p_f->get_length(), Vector<Ref<Image>>(), vformat("Empty DDS texture file."));
|
||||
|
||||
uint32_t magic = p_f->get_32();
|
||||
uint32_t hsize = p_f->get_32();
|
||||
r_flags = p_f->get_32();
|
||||
r_height = p_f->get_32();
|
||||
r_width = p_f->get_32();
|
||||
r_pitch = p_f->get_32();
|
||||
uint32_t depth = p_f->get_32();
|
||||
r_mipmaps = p_f->get_32();
|
||||
|
||||
// Skip reserved.
|
||||
for (int i = 0; i < 11; i++) {
|
||||
p_f->get_32();
|
||||
}
|
||||
|
||||
// Validate.
|
||||
// We don't check DDSD_CAPS or DDSD_PIXELFORMAT, as they're mandatory when writing,
|
||||
// but non-mandatory when reading (as some writers don't set them).
|
||||
if (magic != DDS_MAGIC || hsize != 124) {
|
||||
ERR_FAIL_V_MSG(Vector<Ref<Image>>(), vformat("Invalid or unsupported DDS texture file '%s'.", p_path));
|
||||
}
|
||||
|
||||
/* uint32_t format_size = */ p_f->get_32();
|
||||
uint32_t format_flags = p_f->get_32();
|
||||
uint32_t format_fourcc = p_f->get_32();
|
||||
uint32_t format_rgb_bits = p_f->get_32();
|
||||
uint32_t format_red_mask = p_f->get_32();
|
||||
uint32_t format_green_mask = p_f->get_32();
|
||||
uint32_t format_blue_mask = p_f->get_32();
|
||||
uint32_t format_alpha_mask = p_f->get_32();
|
||||
|
||||
/* uint32_t caps_1 = */ p_f->get_32();
|
||||
uint32_t caps_2 = p_f->get_32();
|
||||
/* uint32_t caps_3 = */ p_f->get_32();
|
||||
/* uint32_t caps_4 = */ p_f->get_32();
|
||||
|
||||
// Skip reserved.
|
||||
p_f->get_32();
|
||||
|
||||
if (p_f->get_position() < 128) {
|
||||
p_f->seek(128);
|
||||
}
|
||||
|
||||
r_layer_count = 1;
|
||||
r_dds_type = DDST_2D;
|
||||
|
||||
if (caps_2 & DDSC2_CUBEMAP) {
|
||||
r_dds_type = DDST_CUBEMAP;
|
||||
r_layer_count *= 6;
|
||||
|
||||
} else if (caps_2 & DDSC2_VOLUME) {
|
||||
r_dds_type = DDST_3D;
|
||||
r_layer_count = depth;
|
||||
}
|
||||
|
||||
r_dds_format = DDS_MAX;
|
||||
|
||||
if (format_flags & DDPF_FOURCC) {
|
||||
// FourCC formats.
|
||||
switch (format_fourcc) {
|
||||
case DDFCC_DXT1: {
|
||||
r_dds_format = DDS_DXT1;
|
||||
} break;
|
||||
case DDFCC_DXT2:
|
||||
case DDFCC_DXT3: {
|
||||
r_dds_format = DDS_DXT3;
|
||||
} break;
|
||||
case DDFCC_DXT4:
|
||||
case DDFCC_DXT5: {
|
||||
r_dds_format = DDS_DXT5;
|
||||
} break;
|
||||
case DDFCC_ATI1:
|
||||
case DDFCC_BC4U: {
|
||||
r_dds_format = DDS_ATI1;
|
||||
} break;
|
||||
case DDFCC_ATI2:
|
||||
case DDFCC_BC5U:
|
||||
case DDFCC_A2XY: {
|
||||
r_dds_format = DDS_ATI2;
|
||||
} break;
|
||||
case DDFCC_R16F: {
|
||||
r_dds_format = DDS_R16F;
|
||||
} break;
|
||||
case DDFCC_RG16F: {
|
||||
r_dds_format = DDS_RG16F;
|
||||
} break;
|
||||
case DDFCC_RGBA16F: {
|
||||
r_dds_format = DDS_RGBA16F;
|
||||
} break;
|
||||
case DDFCC_R32F: {
|
||||
r_dds_format = DDS_R32F;
|
||||
} break;
|
||||
case DDFCC_RG32F: {
|
||||
r_dds_format = DDS_RG32F;
|
||||
} break;
|
||||
case DDFCC_RGBA32F: {
|
||||
r_dds_format = DDS_RGBA32F;
|
||||
} break;
|
||||
case DDFCC_DX10: {
|
||||
uint32_t dxgi_format = p_f->get_32();
|
||||
uint32_t dimension = p_f->get_32();
|
||||
/* uint32_t misc_flags_1 = */ p_f->get_32();
|
||||
uint32_t array_size = p_f->get_32();
|
||||
/* uint32_t misc_flags_2 = */ p_f->get_32();
|
||||
|
||||
if (dimension == DX10D_3D) {
|
||||
r_dds_type = DDST_3D;
|
||||
r_layer_count = depth;
|
||||
}
|
||||
|
||||
if (array_size > 1) {
|
||||
r_layer_count *= array_size;
|
||||
r_dds_type |= DDST_ARRAY;
|
||||
}
|
||||
|
||||
r_dds_format = _dxgi_to_dds_format(dxgi_format);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
ERR_FAIL_V_MSG(Vector<Ref<Image>>(), vformat("Unrecognized or unsupported FourCC in DDS '%s'.", p_path));
|
||||
}
|
||||
}
|
||||
|
||||
} else if (format_flags & DDPF_RGB) {
|
||||
// Channel-bitmasked formats.
|
||||
if (format_flags & DDPF_ALPHAPIXELS) {
|
||||
// With alpha.
|
||||
if (format_rgb_bits == 32 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff && format_alpha_mask == 0xff000000) {
|
||||
r_dds_format = DDS_BGRA8;
|
||||
} else if (format_rgb_bits == 32 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000 && format_alpha_mask == 0xff000000) {
|
||||
r_dds_format = DDS_RGBA8;
|
||||
} else if (format_rgb_bits == 16 && format_red_mask == 0x00007c00 && format_green_mask == 0x000003e0 && format_blue_mask == 0x0000001f && format_alpha_mask == 0x00008000) {
|
||||
r_dds_format = DDS_BGR5A1;
|
||||
} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff00000 && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff && format_alpha_mask == 0xc0000000) {
|
||||
r_dds_format = DDS_BGR10A2;
|
||||
} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff00000 && format_alpha_mask == 0xc0000000) {
|
||||
r_dds_format = DDS_RGB10A2;
|
||||
} else if (format_rgb_bits == 16 && format_red_mask == 0xf00 && format_green_mask == 0xf0 && format_blue_mask == 0xf && format_alpha_mask == 0xf000) {
|
||||
r_dds_format = DDS_BGRA4;
|
||||
} else if (format_rgb_bits == 16 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3 && format_alpha_mask == 0xff00) {
|
||||
r_dds_format = DDS_B2GR3A8;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Without alpha.
|
||||
if (format_rgb_bits == 24 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff) {
|
||||
r_dds_format = DDS_BGR8;
|
||||
} else if (format_rgb_bits == 24 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000) {
|
||||
r_dds_format = DDS_RGB8;
|
||||
} else if (format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) {
|
||||
r_dds_format = DDS_BGR565;
|
||||
} else if (format_rgb_bits == 8 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3) {
|
||||
r_dds_format = DDS_B2GR3;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Other formats.
|
||||
if (format_flags & DDPF_ALPHAONLY && format_rgb_bits == 8 && format_alpha_mask == 0xff) {
|
||||
// Alpha only.
|
||||
r_dds_format = DDS_LUMINANCE;
|
||||
}
|
||||
}
|
||||
|
||||
// Depending on the writer, luminance formats may or may not have the DDPF_RGB or DDPF_LUMINANCE flags defined,
|
||||
// so we check for these formats after everything else failed.
|
||||
if (r_dds_format == DDS_MAX) {
|
||||
if (format_flags & DDPF_ALPHAPIXELS) {
|
||||
// With alpha.
|
||||
if (format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) {
|
||||
r_dds_format = DDS_LUMINANCE_ALPHA;
|
||||
} else if (format_rgb_bits == 8 && format_red_mask == 0xf && format_alpha_mask == 0xf0) {
|
||||
r_dds_format = DDS_LUMINANCE_ALPHA_4;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Without alpha.
|
||||
if (format_rgb_bits == 8 && format_red_mask == 0xff) {
|
||||
r_dds_format = DDS_LUMINANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No format detected, error.
|
||||
if (r_dds_format == DDS_MAX) {
|
||||
ERR_FAIL_V_MSG(Vector<Ref<Image>>(), vformat("Unrecognized or unsupported color layout in DDS '%s'.", p_path));
|
||||
}
|
||||
|
||||
if (!(r_flags & DDSD_MIPMAPCOUNT)) {
|
||||
r_mipmaps = 1;
|
||||
}
|
||||
|
||||
return _dds_load_images(p_f, r_dds_format, r_width, r_height, r_mipmaps, r_pitch, r_flags, r_layer_count);
|
||||
}
|
||||
|
||||
static Ref<Resource> _dds_load_from_buffer(Ref<FileAccess> p_f, Error *r_error, const String &p_path = "") {
|
||||
if (r_error) {
|
||||
*r_error = ERR_FILE_CORRUPT;
|
||||
}
|
||||
|
||||
DDSFormat dds_format;
|
||||
uint32_t width = 0, height = 0, mipmaps = 0, pitch = 0, flags = 0, layer_count = 0, dds_type = 0;
|
||||
|
||||
Vector<Ref<Image>> images = _dds_load_images_from_buffer(p_f, dds_format, width, height, mipmaps, pitch, flags, layer_count, dds_type, p_path);
|
||||
return _dds_create_texture_from_images(images, dds_format, width, height, mipmaps, pitch, flags, layer_count, dds_type, r_error);
|
||||
}
|
||||
|
||||
static Ref<Resource> _dds_load_from_file(const String &p_path, Error *r_error) {
|
||||
if (r_error) {
|
||||
*r_error = ERR_CANT_OPEN;
|
||||
}
|
||||
|
|
@ -554,268 +684,11 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
|
|||
return Ref<Resource>();
|
||||
}
|
||||
|
||||
Ref<FileAccess> fref(f);
|
||||
if (r_error) {
|
||||
*r_error = ERR_FILE_CORRUPT;
|
||||
}
|
||||
return _dds_load_from_buffer(f, r_error, p_path);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), vformat("Unable to open DDS texture file '%s'.", p_path));
|
||||
|
||||
uint32_t magic = f->get_32();
|
||||
uint32_t hsize = f->get_32();
|
||||
uint32_t flags = f->get_32();
|
||||
uint32_t height = f->get_32();
|
||||
uint32_t width = f->get_32();
|
||||
uint32_t pitch = f->get_32();
|
||||
uint32_t depth = f->get_32();
|
||||
uint32_t mipmaps = f->get_32();
|
||||
|
||||
// Skip reserved.
|
||||
for (int i = 0; i < 11; i++) {
|
||||
f->get_32();
|
||||
}
|
||||
|
||||
// Validate.
|
||||
// We don't check DDSD_CAPS or DDSD_PIXELFORMAT, as they're mandatory when writing,
|
||||
// but non-mandatory when reading (as some writers don't set them).
|
||||
if (magic != DDS_MAGIC || hsize != 124) {
|
||||
ERR_FAIL_V_MSG(Ref<Resource>(), vformat("Invalid or unsupported DDS texture file '%s'.", p_path));
|
||||
}
|
||||
|
||||
/* uint32_t format_size = */ f->get_32();
|
||||
uint32_t format_flags = f->get_32();
|
||||
uint32_t format_fourcc = f->get_32();
|
||||
uint32_t format_rgb_bits = f->get_32();
|
||||
uint32_t format_red_mask = f->get_32();
|
||||
uint32_t format_green_mask = f->get_32();
|
||||
uint32_t format_blue_mask = f->get_32();
|
||||
uint32_t format_alpha_mask = f->get_32();
|
||||
|
||||
/* uint32_t caps_1 = */ f->get_32();
|
||||
uint32_t caps_2 = f->get_32();
|
||||
/* uint32_t caps_3 = */ f->get_32();
|
||||
/* uint32_t caps_4 = */ f->get_32();
|
||||
|
||||
// Skip reserved.
|
||||
f->get_32();
|
||||
|
||||
if (f->get_position() < 128) {
|
||||
f->seek(128);
|
||||
}
|
||||
|
||||
uint32_t layer_count = 1;
|
||||
uint32_t dds_type = DDST_2D;
|
||||
|
||||
if (caps_2 & DDSC2_CUBEMAP) {
|
||||
dds_type = DDST_CUBEMAP;
|
||||
layer_count *= 6;
|
||||
|
||||
} else if (caps_2 & DDSC2_VOLUME) {
|
||||
dds_type = DDST_3D;
|
||||
layer_count = depth;
|
||||
}
|
||||
|
||||
DDSFormat dds_format = DDS_MAX;
|
||||
|
||||
if (format_flags & DDPF_FOURCC) {
|
||||
// FourCC formats.
|
||||
switch (format_fourcc) {
|
||||
case DDFCC_DXT1: {
|
||||
dds_format = DDS_DXT1;
|
||||
} break;
|
||||
case DDFCC_DXT2:
|
||||
case DDFCC_DXT3: {
|
||||
dds_format = DDS_DXT3;
|
||||
} break;
|
||||
case DDFCC_DXT4:
|
||||
case DDFCC_DXT5: {
|
||||
dds_format = DDS_DXT5;
|
||||
} break;
|
||||
case DDFCC_ATI1:
|
||||
case DDFCC_BC4U: {
|
||||
dds_format = DDS_ATI1;
|
||||
} break;
|
||||
case DDFCC_ATI2:
|
||||
case DDFCC_BC5U:
|
||||
case DDFCC_A2XY: {
|
||||
dds_format = DDS_ATI2;
|
||||
} break;
|
||||
case DDFCC_R16F: {
|
||||
dds_format = DDS_R16F;
|
||||
} break;
|
||||
case DDFCC_RG16F: {
|
||||
dds_format = DDS_RG16F;
|
||||
} break;
|
||||
case DDFCC_RGBA16F: {
|
||||
dds_format = DDS_RGBA16F;
|
||||
} break;
|
||||
case DDFCC_R32F: {
|
||||
dds_format = DDS_R32F;
|
||||
} break;
|
||||
case DDFCC_RG32F: {
|
||||
dds_format = DDS_RG32F;
|
||||
} break;
|
||||
case DDFCC_RGBA32F: {
|
||||
dds_format = DDS_RGBA32F;
|
||||
} break;
|
||||
case DDFCC_DX10: {
|
||||
uint32_t dxgi_format = f->get_32();
|
||||
uint32_t dimension = f->get_32();
|
||||
/* uint32_t misc_flags_1 = */ f->get_32();
|
||||
uint32_t array_size = f->get_32();
|
||||
/* uint32_t misc_flags_2 = */ f->get_32();
|
||||
|
||||
if (dimension == DX10D_3D) {
|
||||
dds_type = DDST_3D;
|
||||
layer_count = depth;
|
||||
}
|
||||
|
||||
if (array_size > 1) {
|
||||
layer_count *= array_size;
|
||||
dds_type |= DDST_ARRAY;
|
||||
}
|
||||
|
||||
dds_format = _dxgi_to_dds_format(dxgi_format);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
ERR_FAIL_V_MSG(Ref<Resource>(), vformat("Unrecognized or unsupported FourCC in DDS '%s'.", p_path));
|
||||
}
|
||||
}
|
||||
|
||||
} else if (format_flags & DDPF_RGB) {
|
||||
// Channel-bitmasked formats.
|
||||
if (format_flags & DDPF_ALPHAPIXELS) {
|
||||
// With alpha.
|
||||
if (format_rgb_bits == 32 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff && format_alpha_mask == 0xff000000) {
|
||||
dds_format = DDS_BGRA8;
|
||||
} else if (format_rgb_bits == 32 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000 && format_alpha_mask == 0xff000000) {
|
||||
dds_format = DDS_RGBA8;
|
||||
} else if (format_rgb_bits == 16 && format_red_mask == 0x00007c00 && format_green_mask == 0x000003e0 && format_blue_mask == 0x0000001f && format_alpha_mask == 0x00008000) {
|
||||
dds_format = DDS_BGR5A1;
|
||||
} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff00000 && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff && format_alpha_mask == 0xc0000000) {
|
||||
dds_format = DDS_BGR10A2;
|
||||
} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff00000 && format_alpha_mask == 0xc0000000) {
|
||||
dds_format = DDS_RGB10A2;
|
||||
} else if (format_rgb_bits == 16 && format_red_mask == 0xf00 && format_green_mask == 0xf0 && format_blue_mask == 0xf && format_alpha_mask == 0xf000) {
|
||||
dds_format = DDS_BGRA4;
|
||||
} else if (format_rgb_bits == 16 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3 && format_alpha_mask == 0xff00) {
|
||||
dds_format = DDS_B2GR3A8;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Without alpha.
|
||||
if (format_rgb_bits == 24 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff) {
|
||||
dds_format = DDS_BGR8;
|
||||
} else if (format_rgb_bits == 24 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000) {
|
||||
dds_format = DDS_RGB8;
|
||||
} else if (format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) {
|
||||
dds_format = DDS_BGR565;
|
||||
} else if (format_rgb_bits == 8 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3) {
|
||||
dds_format = DDS_B2GR3;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Other formats.
|
||||
if (format_flags & DDPF_ALPHAONLY && format_rgb_bits == 8 && format_alpha_mask == 0xff) {
|
||||
// Alpha only.
|
||||
dds_format = DDS_LUMINANCE;
|
||||
}
|
||||
}
|
||||
|
||||
// Depending on the writer, luminance formats may or may not have the DDPF_RGB or DDPF_LUMINANCE flags defined,
|
||||
// so we check for these formats after everything else failed.
|
||||
if (dds_format == DDS_MAX) {
|
||||
if (format_flags & DDPF_ALPHAPIXELS) {
|
||||
// With alpha.
|
||||
if (format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) {
|
||||
dds_format = DDS_LUMINANCE_ALPHA;
|
||||
} else if (format_rgb_bits == 8 && format_red_mask == 0xf && format_alpha_mask == 0xf0) {
|
||||
dds_format = DDS_LUMINANCE_ALPHA_4;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Without alpha.
|
||||
if (format_rgb_bits == 8 && format_red_mask == 0xff) {
|
||||
dds_format = DDS_LUMINANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No format detected, error.
|
||||
if (dds_format == DDS_MAX) {
|
||||
ERR_FAIL_V_MSG(Ref<Resource>(), vformat("Unrecognized or unsupported color layout in DDS '%s'.", p_path));
|
||||
}
|
||||
|
||||
if (!(flags & DDSD_MIPMAPCOUNT)) {
|
||||
mipmaps = 1;
|
||||
}
|
||||
|
||||
Vector<uint8_t> src_data;
|
||||
|
||||
Vector<Ref<Image>> images;
|
||||
images.resize(layer_count);
|
||||
|
||||
for (uint32_t i = 0; i < layer_count; i++) {
|
||||
images.write[i] = _dds_load_layer(f, dds_format, width, height, mipmaps, pitch, flags, src_data);
|
||||
}
|
||||
|
||||
if ((dds_type & DDST_TYPE_MASK) == DDST_2D) {
|
||||
if (dds_type & DDST_ARRAY) {
|
||||
Ref<Texture2DArray> texture = memnew(Texture2DArray());
|
||||
texture->create_from_images(images);
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return texture;
|
||||
|
||||
} else {
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return ImageTexture::create_from_image(images[0]);
|
||||
}
|
||||
|
||||
} else if ((dds_type & DDST_TYPE_MASK) == DDST_CUBEMAP) {
|
||||
ERR_FAIL_COND_V(layer_count % 6 != 0, Ref<Resource>());
|
||||
|
||||
if (dds_type & DDST_ARRAY) {
|
||||
Ref<CubemapArray> texture = memnew(CubemapArray());
|
||||
texture->create_from_images(images);
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return texture;
|
||||
|
||||
} else {
|
||||
Ref<Cubemap> texture = memnew(Cubemap());
|
||||
texture->create_from_images(images);
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
} else if ((dds_type & DDST_TYPE_MASK) == DDST_3D) {
|
||||
Ref<ImageTexture3D> texture = memnew(ImageTexture3D());
|
||||
texture->create(images[0]->get_format(), width, height, layer_count, mipmaps > 1, images);
|
||||
|
||||
if (r_error) {
|
||||
*r_error = OK;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
return Ref<Resource>();
|
||||
Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
return _dds_load_from_file(p_path, r_error);
|
||||
}
|
||||
|
||||
void ResourceFormatDDS::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
|
|
@ -832,3 +705,24 @@ String ResourceFormatDDS::get_resource_type(const String &p_path) const {
|
|||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Ref<Image> load_mem_dds(const uint8_t *p_dds, int p_size) {
|
||||
ERR_FAIL_NULL_V(p_dds, Ref<Image>());
|
||||
ERR_FAIL_COND_V(!p_size, Ref<Image>());
|
||||
Ref<FileAccessMemory> memfile;
|
||||
memfile.instantiate();
|
||||
Error open_memfile_error = memfile->open_custom(p_dds, p_size);
|
||||
ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for DDS image buffer.");
|
||||
|
||||
DDSFormat dds_format;
|
||||
uint32_t width, height, mipmaps, pitch, flags, layer_count, dds_type;
|
||||
|
||||
Vector<Ref<Image>> images = _dds_load_images_from_buffer(memfile, dds_format, width, height, mipmaps, pitch, flags, layer_count, dds_type);
|
||||
ERR_FAIL_COND_V_MSG(images.is_empty(), Ref<Image>(), "Failed to load DDS image.");
|
||||
|
||||
return images[0];
|
||||
}
|
||||
|
||||
ResourceFormatDDS::ResourceFormatDDS() {
|
||||
Image::_dds_mem_loader_func = load_mem_dds;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TEXTURE_LOADER_DDS_H
|
||||
#define TEXTURE_LOADER_DDS_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
|
||||
|
|
@ -40,7 +39,6 @@ public:
|
|||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
|
||||
ResourceFormatDDS();
|
||||
virtual ~ResourceFormatDDS() {}
|
||||
};
|
||||
|
||||
#endif // TEXTURE_LOADER_DDS_H
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ if env["builtin_enet"]:
|
|||
]
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
env_enet.Prepend(CPPPATH=[thirdparty_dir])
|
||||
env_enet.Prepend(CPPEXTPATH=[thirdparty_dir])
|
||||
env_enet.Append(CPPDEFINES=["GODOT_ENET"])
|
||||
|
||||
env_thirdparty = env_enet.Clone()
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ Error ENetConnection::create_host(int p_max_peers, int p_max_channels, int p_in_
|
|||
|
||||
void ENetConnection::destroy() {
|
||||
ERR_FAIL_NULL_MSG(host, "Host already destroyed.");
|
||||
for (List<Ref<ENetPacketPeer>>::Element *E = peers.front(); E; E = E->next()) {
|
||||
E->get()->_on_disconnect();
|
||||
for (const Ref<ENetPacketPeer> &peer : peers) {
|
||||
peer->_on_disconnect();
|
||||
}
|
||||
peers.clear();
|
||||
enet_host_destroy(host);
|
||||
|
|
@ -320,14 +320,10 @@ Error ENetConnection::_create(ENetAddress *p_address, int p_max_peers, int p_max
|
|||
}
|
||||
|
||||
Array ENetConnection::_service(int p_timeout) {
|
||||
Array out;
|
||||
Event event;
|
||||
Ref<ENetPacketPeer> peer;
|
||||
EventType ret = service(p_timeout, event);
|
||||
out.push_back(ret);
|
||||
out.push_back(event.peer);
|
||||
out.push_back(event.data);
|
||||
out.push_back(event.channel_id);
|
||||
Array out = { ret, event.peer, event.data, event.channel_id };
|
||||
if (event.packet && event.peer.is_valid()) {
|
||||
event.peer->_queue_packet(event.packet);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ENET_CONNECTION_H
|
||||
#define ENET_CONNECTION_H
|
||||
#pragma once
|
||||
|
||||
#include "enet_packet_peer.h"
|
||||
|
||||
|
|
@ -140,5 +139,3 @@ public:
|
|||
VARIANT_ENUM_CAST(ENetConnection::CompressionMode);
|
||||
VARIANT_ENUM_CAST(ENetConnection::EventType);
|
||||
VARIANT_ENUM_CAST(ENetConnection::HostStatistic);
|
||||
|
||||
#endif // ENET_CONNECTION_H
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ Error ENetMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_si
|
|||
Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
|
||||
ERR_FAIL_COND_V_MSG(!_is_active(), ERR_UNCONFIGURED, "The multiplayer instance isn't currently active.");
|
||||
ERR_FAIL_COND_V_MSG(connection_status != CONNECTION_CONNECTED, ERR_UNCONFIGURED, "The multiplayer instance isn't currently connected to any server or client.");
|
||||
ERR_FAIL_COND_V_MSG(target_peer != 0 && !peers.has(ABS(target_peer)), ERR_INVALID_PARAMETER, vformat("Invalid target peer: %d", target_peer));
|
||||
ERR_FAIL_COND_V_MSG(target_peer != 0 && !peers.has(Math::abs(target_peer)), ERR_INVALID_PARAMETER, vformat("Invalid target peer: %d", target_peer));
|
||||
ERR_FAIL_COND_V(active_mode == MODE_CLIENT && !peers.has(1), ERR_BUG);
|
||||
|
||||
int packet_flags = 0;
|
||||
|
|
@ -394,7 +394,7 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size
|
|||
|
||||
} else {
|
||||
if (target_peer <= 0) {
|
||||
int exclude = ABS(target_peer);
|
||||
int exclude = Math::abs(target_peer);
|
||||
for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
|
||||
if (E.key == exclude) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ENET_MULTIPLAYER_PEER_H
|
||||
#define ENET_MULTIPLAYER_PEER_H
|
||||
#pragma once
|
||||
|
||||
#include "enet_connection.h"
|
||||
|
||||
|
|
@ -132,5 +131,3 @@ public:
|
|||
ENetMultiplayerPeer();
|
||||
~ENetMultiplayerPeer();
|
||||
};
|
||||
|
||||
#endif // ENET_MULTIPLAYER_PEER_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ENET_PACKET_PEER_H
|
||||
#define ENET_PACKET_PEER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/packet_peer.h"
|
||||
|
||||
|
|
@ -128,5 +127,3 @@ public:
|
|||
|
||||
VARIANT_ENUM_CAST(ENetPacketPeer::PeerState);
|
||||
VARIANT_ENUM_CAST(ENetPacketPeer::PeerStatistic);
|
||||
|
||||
#endif // ENET_PACKET_PEER_H
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ENET_REGISTER_TYPES_H
|
||||
#define ENET_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_enet_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_enet_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // ENET_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ thirdparty_sources = [
|
|||
]
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
env_etcpak.Prepend(CPPPATH=[thirdparty_dir])
|
||||
env_etcpak.Prepend(CPPEXTPATH=[thirdparty_dir])
|
||||
|
||||
env_thirdparty = env_etcpak.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef IMAGE_COMPRESS_ETCPAK_H
|
||||
#define IMAGE_COMPRESS_ETCPAK_H
|
||||
#pragma once
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
|
|
@ -56,5 +55,3 @@ void _compress_bc(Image *r_img, Image::UsedChannels p_channels);
|
|||
void _compress_etcpak(EtcpakType p_compress_type, Image *r_img);
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // IMAGE_COMPRESS_ETCPAK_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef IMAGE_DECOMPRESS_ETCPAK_H
|
||||
#define IMAGE_DECOMPRESS_ETCPAK_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/image.h"
|
||||
|
||||
|
|
@ -41,5 +40,3 @@ enum EtcpakFormat {
|
|||
};
|
||||
|
||||
void _decompress_etc(Image *p_image);
|
||||
|
||||
#endif // IMAGE_DECOMPRESS_ETCPAK_H
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ETCPAK_REGISTER_TYPES_H
|
||||
#define ETCPAK_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_etcpak_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_etcpak_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // ETCPAK_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ thirdparty_obj = []
|
|||
thirdparty_dir = "#thirdparty/ufbx/"
|
||||
thirdparty_sources = [thirdparty_dir + "ufbx.c"]
|
||||
|
||||
env_fbx.Prepend(CPPPATH=[thirdparty_dir])
|
||||
env_fbx.Prepend(CPPEXTPATH=[thirdparty_dir])
|
||||
|
||||
env_thirdparty = env_fbx.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include "editor_scene_importer_fbx2gltf.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor_scene_importer_ufbx.h"
|
||||
|
|
@ -142,5 +140,3 @@ void EditorSceneFormatImporterFBX2GLTF::handle_compatibility_options(HashMap<Str
|
|||
p_import_params["fbx/importer"] = EditorSceneFormatImporterUFBX::FBX_IMPORTER_UFBX;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_SCENE_IMPORTER_FBX2GLTF_H
|
||||
#define EDITOR_SCENE_IMPORTER_FBX2GLTF_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#pragma once
|
||||
|
||||
#include "editor/import/3d/resource_importer_scene.h"
|
||||
|
||||
|
|
@ -52,7 +49,3 @@ public:
|
|||
const HashMap<StringName, Variant> &p_options) override;
|
||||
virtual void handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const override;
|
||||
};
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // EDITOR_SCENE_IMPORTER_FBX2GLTF_H
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include "editor_scene_importer_ufbx.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "../fbx_document.h"
|
||||
#include "editor_scene_importer_fbx2gltf.h"
|
||||
|
||||
|
|
@ -104,5 +102,3 @@ void EditorSceneFormatImporterUFBX::handle_compatibility_options(HashMap<StringN
|
|||
p_import_params["fbx/importer"] = EditorSceneFormatImporterUFBX::FBX_IMPORTER_FBX2GLTF;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_SCENE_IMPORTER_UFBX_H
|
||||
#define EDITOR_SCENE_IMPORTER_UFBX_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#pragma once
|
||||
|
||||
#include "editor/import/3d/resource_importer_scene.h"
|
||||
|
||||
|
|
@ -56,6 +53,3 @@ public:
|
|||
const HashMap<StringName, Variant> &p_options) override;
|
||||
virtual void handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const override;
|
||||
};
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // EDITOR_SCENE_IMPORTER_UFBX_H
|
||||
|
|
|
|||
|
|
@ -251,18 +251,16 @@ static bool _thread_pool_init_fn(void *user, ufbx_thread_pool_context ctx, const
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool _thread_pool_run_fn(void *user, ufbx_thread_pool_context ctx, uint32_t group, uint32_t start_index, uint32_t count) {
|
||||
static void _thread_pool_run_fn(void *user, ufbx_thread_pool_context ctx, uint32_t group, uint32_t start_index, uint32_t count) {
|
||||
ThreadPoolFBX *pool = (ThreadPoolFBX *)user;
|
||||
ThreadPoolFBX::Group &pool_group = pool->groups[group];
|
||||
pool_group.start_index = start_index;
|
||||
pool_group.task_id = pool->pool->add_native_group_task(_thread_pool_task, &pool_group, (int)count, -1, true, "ufbx");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _thread_pool_wait_fn(void *user, ufbx_thread_pool_context ctx, uint32_t group, uint32_t max_index) {
|
||||
static void _thread_pool_wait_fn(void *user, ufbx_thread_pool_context ctx, uint32_t group, uint32_t max_index) {
|
||||
ThreadPoolFBX *pool = (ThreadPoolFBX *)user;
|
||||
pool->pool->wait_for_group_task_completion(pool->groups[group].task_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
String FBXDocument::_gen_unique_name(HashSet<String> &unique_names, const String &p_name) {
|
||||
|
|
@ -1082,7 +1080,7 @@ Error FBXDocument::_parse_images(Ref<FBXState> p_state, const String &p_base_pat
|
|||
}
|
||||
// Fallback to loading as byte array.
|
||||
data = FileAccess::get_file_as_bytes(path);
|
||||
if (data.size() == 0) {
|
||||
if (data.is_empty()) {
|
||||
WARN_PRINT(vformat("FBX: Image index '%d' couldn't be loaded from path: %s because there was no data to load. Skipping it.", texture_i, path));
|
||||
p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
|
||||
p_state->source_images.push_back(Ref<Image>());
|
||||
|
|
@ -1658,8 +1656,7 @@ void FBXDocument::_generate_scene_node(Ref<FBXState> p_state, const GLTFNodeInde
|
|||
// Add the node we generated and set the owner to the scene root.
|
||||
p_scene_parent->add_child(current_node, true);
|
||||
if (current_node != p_scene_root) {
|
||||
Array args;
|
||||
args.append(p_scene_root);
|
||||
Array args = { p_scene_root };
|
||||
current_node->propagate_call(StringName("set_owner"), args);
|
||||
}
|
||||
current_node->set_transform(fbx_node->transform);
|
||||
|
|
@ -1746,8 +1743,7 @@ void FBXDocument::_generate_skeleton_bone_node(Ref<FBXState> p_state, const GLTF
|
|||
// Add the node we generated and set the owner to the scene root.
|
||||
p_scene_parent->add_child(current_node, true);
|
||||
if (current_node != p_scene_root) {
|
||||
Array args;
|
||||
args.append(p_scene_root);
|
||||
Array args = { p_scene_root };
|
||||
current_node->propagate_call(StringName("set_owner"), args);
|
||||
}
|
||||
// Do not set transform here. Transform is already applied to our bone.
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FBX_DOCUMENT_H
|
||||
#define FBX_DOCUMENT_H
|
||||
#pragma once
|
||||
|
||||
#include "fbx_state.h"
|
||||
|
||||
|
|
@ -99,5 +98,3 @@ public:
|
|||
const GLTFAnimationIndex p_index, const bool p_trimming, const bool p_remove_immutable_tracks);
|
||||
Error _parse(Ref<FBXState> p_state, String p_path, Ref<FileAccess> p_file);
|
||||
};
|
||||
|
||||
#endif // FBX_DOCUMENT_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FBX_STATE_H
|
||||
#define FBX_STATE_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/gltf/gltf_defines.h"
|
||||
#include "modules/gltf/gltf_state.h"
|
||||
|
|
@ -65,5 +64,3 @@ public:
|
|||
bool get_allow_geometry_helper_nodes();
|
||||
void set_allow_geometry_helper_nodes(bool p_allow_geometry_helper_nodes);
|
||||
};
|
||||
|
||||
#endif // FBX_STATE_H
|
||||
|
|
|
|||
|
|
@ -61,10 +61,6 @@ void initialize_fbx_module(ModuleInitializationLevel p_level) {
|
|||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
|
||||
// Editor-specific API.
|
||||
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
||||
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
||||
|
||||
GDREGISTER_CLASS(EditorSceneFormatImporterUFBX);
|
||||
|
||||
GLOBAL_DEF_RST_BASIC("filesystem/import/fbx2gltf/enabled", true);
|
||||
|
|
@ -72,7 +68,6 @@ void initialize_fbx_module(ModuleInitializationLevel p_level) {
|
|||
GLOBAL_DEF_RST("filesystem/import/fbx2gltf/enabled.android", false);
|
||||
GLOBAL_DEF_RST("filesystem/import/fbx2gltf/enabled.web", false);
|
||||
|
||||
ClassDB::set_current_api(prev_api);
|
||||
EditorNode::add_init_callback(_editor_init);
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FBX_REGISTER_TYPES_H
|
||||
#define FBX_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_fbx_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_fbx_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // FBX_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -62,15 +62,15 @@ if env["builtin_freetype"]:
|
|||
if env["brotli"]:
|
||||
env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
|
||||
|
||||
env_freetype.Prepend(CPPPATH=[thirdparty_dir + "/include"])
|
||||
env_freetype.Prepend(CPPEXTPATH=[thirdparty_dir + "/include"])
|
||||
# Also needed in main env for scene/
|
||||
env.Prepend(CPPPATH=[thirdparty_dir + "/include"])
|
||||
env.Prepend(CPPEXTPATH=[thirdparty_dir + "/include"])
|
||||
|
||||
env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", "FT_CONFIG_OPTION_SYSTEM_ZLIB"])
|
||||
|
||||
# Also requires libpng headers
|
||||
if env["builtin_libpng"]:
|
||||
env_freetype.Prepend(CPPPATH=["#thirdparty/libpng"])
|
||||
env_freetype.Prepend(CPPEXTPATH=["#thirdparty/libpng"])
|
||||
|
||||
sfnt = thirdparty_dir + "src/sfnt/sfnt.c"
|
||||
# Must be done after all CPPDEFINES are being set so we can copy them.
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FREETYPE_REGISTER_TYPES_H
|
||||
#define FREETYPE_REGISTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_freetype_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_freetype_module(ModuleInitializationLevel p_level);
|
||||
|
||||
#endif // FREETYPE_REGISTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@
|
|||
<return type="Dictionary" />
|
||||
<param index="0" name="instance" type="Object" />
|
||||
<description>
|
||||
Returns the passed [param instance] converted to a Dictionary. Can be useful for serializing.
|
||||
Returns the passed [param instance] converted to a [Dictionary]. Can be useful for serializing.
|
||||
[codeblock]
|
||||
var foo = "bar"
|
||||
func _ready():
|
||||
|
|
@ -133,7 +133,7 @@
|
|||
- A constant from the [enum Variant.Type] enumeration, for example [constant TYPE_INT].
|
||||
- An [Object]-derived class which exists in [ClassDB], for example [Node].
|
||||
- A [Script] (you can use any class, including inner one).
|
||||
Unlike the right operand of the [code]is[/code] operator, [param type] can be a non-constant value. The [code]is[/code] operator supports more features (such as typed arrays). Use the operator instead of this method if you do not need dynamic type checking.
|
||||
Unlike the right operand of the [code]is[/code] operator, [param type] can be a non-constant value. The [code]is[/code] operator supports more features (such as typed arrays). Use the operator instead of this method if you do not need to check the type dynamically.
|
||||
[b]Examples:[/b]
|
||||
[codeblock]
|
||||
print(is_instance_of(a, TYPE_INT))
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ void GDScriptDocGen::_doctype_from_gdtype(const GDType &p_gdtype, String &r_type
|
|||
return;
|
||||
case GDType::SCRIPT:
|
||||
if (p_gdtype.is_meta_type) {
|
||||
r_type = p_gdtype.script_type.is_valid() ? p_gdtype.script_type->get_class() : Script::get_class_static();
|
||||
r_type = p_gdtype.script_type.is_valid() ? p_gdtype.script_type->get_class_name() : Script::get_class_static();
|
||||
return;
|
||||
}
|
||||
if (p_gdtype.script_type.is_valid()) {
|
||||
|
|
@ -216,15 +216,15 @@ String GDScriptDocGen::_docvalue_from_variant(const Variant &p_variant, int p_re
|
|||
} else {
|
||||
result += "{";
|
||||
|
||||
List<Variant> keys;
|
||||
dict.get_key_list(&keys);
|
||||
LocalVector<Variant> keys = dict.get_key_list();
|
||||
keys.sort_custom<StringLikeVariantOrder>();
|
||||
|
||||
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
|
||||
if (E->prev()) {
|
||||
for (uint32_t i = 0; i < keys.size(); i++) {
|
||||
const Variant &key = keys[i];
|
||||
if (i > 0) {
|
||||
result += ", ";
|
||||
}
|
||||
result += _docvalue_from_variant(E->get(), p_recursion_level + 1) + ": " + _docvalue_from_variant(dict[E->get()], p_recursion_level + 1);
|
||||
result += _docvalue_from_variant(key, p_recursion_level + 1) + ": " + _docvalue_from_variant(dict[key], p_recursion_level + 1);
|
||||
}
|
||||
|
||||
result += "}";
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDSCRIPT_DOCGEN_H
|
||||
#define GDSCRIPT_DOCGEN_H
|
||||
#pragma once
|
||||
|
||||
#include "../gdscript_parser.h"
|
||||
|
||||
|
|
@ -52,5 +51,3 @@ public:
|
|||
static void doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String &r_enum, bool p_is_return = false);
|
||||
static String docvalue_from_expression(const GDP::ExpressionNode *p_expression);
|
||||
};
|
||||
|
||||
#endif // GDSCRIPT_DOCGEN_H
|
||||
|
|
|
|||
|
|
@ -150,6 +150,15 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
|
|||
break;
|
||||
}
|
||||
}
|
||||
// "#region" and "#endregion" only highlighted if they're the first region on the line.
|
||||
if (color_regions[c].type == ColorRegion::TYPE_CODE_REGION) {
|
||||
Vector<String> str_stripped_split = str.strip_edges().split_spaces(1);
|
||||
if (!str_stripped_split.is_empty() &&
|
||||
str_stripped_split[0] != "#region" &&
|
||||
str_stripped_split[0] != "#endregion") {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -777,8 +786,8 @@ void GDScriptSyntaxHighlighter::_update_cache() {
|
|||
List<String> comments;
|
||||
gdscript->get_comment_delimiters(&comments);
|
||||
for (const String &comment : comments) {
|
||||
String beg = comment.get_slice(" ", 0);
|
||||
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
|
||||
String beg = comment.get_slicec(' ', 0);
|
||||
String end = comment.get_slice_count(" ") > 1 ? comment.get_slicec(' ', 1) : String();
|
||||
add_color_region(ColorRegion::TYPE_COMMENT, beg, end, comment_color, end.is_empty());
|
||||
}
|
||||
|
||||
|
|
@ -787,8 +796,8 @@ void GDScriptSyntaxHighlighter::_update_cache() {
|
|||
List<String> doc_comments;
|
||||
gdscript->get_doc_comment_delimiters(&doc_comments);
|
||||
for (const String &doc_comment : doc_comments) {
|
||||
String beg = doc_comment.get_slice(" ", 0);
|
||||
String end = doc_comment.get_slice_count(" ") > 1 ? doc_comment.get_slice(" ", 1) : String();
|
||||
String beg = doc_comment.get_slicec(' ', 0);
|
||||
String end = doc_comment.get_slice_count(" ") > 1 ? doc_comment.get_slicec(' ', 1) : String();
|
||||
add_color_region(ColorRegion::TYPE_COMMENT, beg, end, doc_comment_color, end.is_empty());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDSCRIPT_HIGHLIGHTER_H
|
||||
#define GDSCRIPT_HIGHLIGHTER_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/plugins/script_editor_plugin.h"
|
||||
|
||||
|
|
@ -116,5 +115,3 @@ public:
|
|||
|
||||
virtual Ref<EditorSyntaxHighlighter> _create() const override;
|
||||
};
|
||||
|
||||
#endif // GDSCRIPT_HIGHLIGHTER_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
|
||||
#define GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
|
||||
#pragma once
|
||||
|
||||
#include "../gdscript_parser.h"
|
||||
#include "../gdscript_tokenizer.h"
|
||||
|
|
@ -82,5 +81,3 @@ public:
|
|||
|
||||
GDScriptEditorTranslationParserPlugin();
|
||||
};
|
||||
|
||||
#endif // GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
|
||||
|
|
|
|||
|
|
@ -4,6 +4,16 @@
|
|||
extends _BASE_
|
||||
|
||||
|
||||
func _enable_plugin() -> void:
|
||||
# Add autoloads here.
|
||||
pass
|
||||
|
||||
|
||||
func _disable_plugin() -> void:
|
||||
# Remove autoloads here.
|
||||
pass
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
# Initialization of the plugin goes here.
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@
|
|||
#include "editor/editor_paths.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
///////////////////////////
|
||||
|
||||
GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) {
|
||||
|
|
@ -1123,7 +1121,7 @@ Error GDScript::load_source_code(const String &p_path) {
|
|||
w[len] = 0;
|
||||
|
||||
String s;
|
||||
if (s.parse_utf8((const char *)w, len) != OK) {
|
||||
if (s.append_utf8((const char *)w, len) != OK) {
|
||||
ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode.");
|
||||
}
|
||||
|
||||
|
|
@ -1625,6 +1623,27 @@ void GDScript::clear(ClearData *p_clear_data) {
|
|||
}
|
||||
}
|
||||
|
||||
void GDScript::cancel_pending_functions(bool warn) {
|
||||
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
|
||||
|
||||
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
|
||||
// Order matters since clearing the stack may already cause
|
||||
// the GDScriptFunctionState to be destroyed and thus removed from the list.
|
||||
pending_func_states.remove(E);
|
||||
GDScriptFunctionState *state = E->self();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (warn) {
|
||||
WARN_PRINT("Canceling suspended execution of \"" + state->get_readable_function() + "\" due to a script reload.");
|
||||
}
|
||||
#endif
|
||||
ObjectID state_id = state->get_instance_id();
|
||||
state->_clear_connections();
|
||||
if (ObjectDB::get_instance(state_id)) {
|
||||
state->_clear_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GDScript::~GDScript() {
|
||||
if (destructing) {
|
||||
return;
|
||||
|
|
@ -1640,21 +1659,7 @@ GDScript::~GDScript() {
|
|||
|
||||
clear();
|
||||
|
||||
{
|
||||
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
|
||||
|
||||
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
|
||||
// Order matters since clearing the stack may already cause
|
||||
// the GDScriptFunctionState to be destroyed and thus removed from the list.
|
||||
pending_func_states.remove(E);
|
||||
GDScriptFunctionState *state = E->self();
|
||||
ObjectID state_id = state->get_instance_id();
|
||||
state->_clear_connections();
|
||||
if (ObjectDB::get_instance(state_id)) {
|
||||
state->_clear_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
cancel_pending_functions(false);
|
||||
|
||||
{
|
||||
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
|
||||
|
|
@ -2249,10 +2254,10 @@ void GDScriptLanguage::init() {
|
|||
_add_global(StaticCString::create(CoreConstants::get_global_constant_name(i)), CoreConstants::get_global_constant_value(i));
|
||||
}
|
||||
|
||||
_add_global(StaticCString::create("PI"), Math_PI);
|
||||
_add_global(StaticCString::create("TAU"), Math_TAU);
|
||||
_add_global(StaticCString::create("INF"), INFINITY);
|
||||
_add_global(StaticCString::create("NAN"), NAN);
|
||||
_add_global(StaticCString::create("PI"), Math::PI);
|
||||
_add_global(StaticCString::create("TAU"), Math::TAU);
|
||||
_add_global(StaticCString::create("INF"), Math::INF);
|
||||
_add_global(StaticCString::create("NAN"), Math::NaN);
|
||||
|
||||
//populate native classes
|
||||
|
||||
|
|
@ -2699,8 +2704,7 @@ void GDScriptLanguage::reload_scripts(const Array &p_scripts, bool p_soft_reload
|
|||
}
|
||||
|
||||
void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
|
||||
Array scripts;
|
||||
scripts.push_back(p_script);
|
||||
Array scripts = { p_script };
|
||||
reload_scripts(scripts, p_soft_reload);
|
||||
}
|
||||
|
||||
|
|
@ -2849,7 +2853,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
|
|||
while (subclass) {
|
||||
if (subclass->extends_used) {
|
||||
if (!subclass->extends_path.is_empty()) {
|
||||
if (subclass->extends.size() == 0) {
|
||||
if (subclass->extends.is_empty()) {
|
||||
get_global_class_name(subclass->extends_path, r_base_type);
|
||||
subclass = nullptr;
|
||||
break;
|
||||
|
|
@ -3066,6 +3070,62 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S
|
|||
}
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderGDScript::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
|
||||
Ref<GDScript> scr = ResourceLoader::load(p_path);
|
||||
if (scr.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const String source = scr->get_source_code();
|
||||
GDScriptTokenizerText tokenizer;
|
||||
tokenizer.set_source_code(source);
|
||||
GDScriptTokenizer::Token current = tokenizer.scan();
|
||||
while (current.type != GDScriptTokenizer::Token::TK_EOF) {
|
||||
if (!current.is_identifier()) {
|
||||
current = tokenizer.scan();
|
||||
continue;
|
||||
}
|
||||
|
||||
int insert_idx = 0;
|
||||
for (int i = 0; i < current.start_line - 1; i++) {
|
||||
insert_idx = source.find("\n", insert_idx) + 1;
|
||||
}
|
||||
// Insert the "cursor" character, needed for the lookup to work.
|
||||
const String source_with_cursor = source.insert(insert_idx + current.start_column, String::chr(0xFFFF));
|
||||
|
||||
ScriptLanguage::LookupResult result;
|
||||
if (scr->get_language()->lookup_code(source_with_cursor, current.get_identifier(), p_path, nullptr, result) == OK) {
|
||||
if (!result.class_name.is_empty() && ClassDB::class_exists(result.class_name)) {
|
||||
r_classes->insert(result.class_name);
|
||||
}
|
||||
|
||||
if (result.type == ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY) {
|
||||
PropertyInfo prop;
|
||||
if (ClassDB::get_property_info(result.class_name, result.class_member, &prop)) {
|
||||
if (!prop.class_name.is_empty() && ClassDB::class_exists(prop.class_name)) {
|
||||
r_classes->insert(prop.class_name);
|
||||
}
|
||||
if (!prop.hint_string.is_empty() && ClassDB::class_exists(prop.hint_string)) {
|
||||
r_classes->insert(prop.hint_string);
|
||||
}
|
||||
}
|
||||
} else if (result.type == ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD) {
|
||||
MethodInfo met;
|
||||
if (ClassDB::get_method_info(result.class_name, result.class_member, &met)) {
|
||||
if (!met.return_val.class_name.is_empty() && ClassDB::class_exists(met.return_val.class_name)) {
|
||||
r_classes->insert(met.return_val.class_name);
|
||||
}
|
||||
if (!met.return_val.hint_string.is_empty() && ClassDB::class_exists(met.return_val.hint_string)) {
|
||||
r_classes->insert(met.return_val.hint_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current = tokenizer.scan();
|
||||
}
|
||||
}
|
||||
|
||||
Error ResourceFormatSaverGDScript::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
|
||||
Ref<GDScript> sqscr = p_resource;
|
||||
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDSCRIPT_H
|
||||
#define GDSCRIPT_H
|
||||
#pragma once
|
||||
|
||||
#include "gdscript_function.h"
|
||||
|
||||
|
|
@ -244,6 +243,9 @@ public:
|
|||
|
||||
void clear(GDScript::ClearData *p_clear_data = nullptr);
|
||||
|
||||
// Cancels all functions of the script that are are waiting to be resumed after using await.
|
||||
void cancel_pending_functions(bool warn);
|
||||
|
||||
virtual bool is_valid() const override { return valid; }
|
||||
virtual bool is_abstract() const override { return false; } // GDScript does not support abstract classes.
|
||||
|
||||
|
|
@ -655,6 +657,7 @@ public:
|
|||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override;
|
||||
virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override;
|
||||
};
|
||||
|
||||
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
|
||||
|
|
@ -663,5 +666,3 @@ public:
|
|||
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
|
||||
virtual bool recognize(const Ref<Resource> &p_resource) const override;
|
||||
};
|
||||
|
||||
#endif // GDSCRIPT_H
|
||||
|
|
|
|||
|
|
@ -1640,13 +1640,12 @@ void GDScriptAnalyzer::resolve_annotation(GDScriptParser::AnnotationNode *p_anno
|
|||
|
||||
const MethodInfo &annotation_info = parser->valid_annotations[p_annotation->name].info;
|
||||
|
||||
const List<PropertyInfo>::Element *E = annotation_info.arguments.front();
|
||||
for (int i = 0; i < p_annotation->arguments.size(); i++) {
|
||||
for (int64_t i = 0, j = 0; i < p_annotation->arguments.size(); i++) {
|
||||
GDScriptParser::ExpressionNode *argument = p_annotation->arguments[i];
|
||||
const PropertyInfo &argument_info = E->get();
|
||||
const PropertyInfo &argument_info = annotation_info.arguments[j];
|
||||
|
||||
if (E->next() != nullptr) {
|
||||
E = E->next();
|
||||
if (j + 1 < annotation_info.arguments.size()) {
|
||||
++j;
|
||||
}
|
||||
|
||||
reduce_expression(argument);
|
||||
|
|
@ -1715,6 +1714,12 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
|
|||
static_context = p_function->is_static;
|
||||
}
|
||||
|
||||
MethodInfo method_info;
|
||||
method_info.name = function_name;
|
||||
if (p_function->is_static) {
|
||||
method_info.flags |= MethodFlags::METHOD_FLAG_STATIC;
|
||||
}
|
||||
|
||||
GDScriptParser::DataType prev_datatype = p_function->get_datatype();
|
||||
|
||||
GDScriptParser::DataType resolving_datatype;
|
||||
|
|
@ -1734,6 +1739,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
|
|||
|
||||
for (int i = 0; i < p_function->parameters.size(); i++) {
|
||||
resolve_parameter(p_function->parameters[i]);
|
||||
method_info.arguments.push_back(p_function->parameters[i]->get_datatype().to_property_info(p_function->parameters[i]->identifier->name));
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (p_function->parameters[i]->usages == 0 && !String(p_function->parameters[i]->identifier->name).begins_with("_")) {
|
||||
parser->push_warning(p_function->parameters[i]->identifier, GDScriptWarning::UNUSED_PARAMETER, function_visible_name, p_function->parameters[i]->identifier->name);
|
||||
|
|
@ -1797,7 +1803,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
|
|||
GDScriptParser::DataType parent_return_type;
|
||||
List<GDScriptParser::DataType> parameters_types;
|
||||
int default_par_count = 0;
|
||||
BitField<MethodFlags> method_flags;
|
||||
BitField<MethodFlags> method_flags = {};
|
||||
StringName native_base;
|
||||
if (!p_is_lambda && get_function_signature(p_function, false, base_type, function_name, parent_return_type, parameters_types, default_par_count, method_flags, &native_base)) {
|
||||
bool valid = p_function->is_static == method_flags.has_flag(METHOD_FLAG_STATIC);
|
||||
|
|
@ -1884,6 +1890,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
|
|||
}
|
||||
#endif
|
||||
|
||||
method_info.default_arguments.append_array(p_function->default_arg_values);
|
||||
method_info.return_val = p_function->get_datatype().to_property_info("");
|
||||
p_function->info = method_info;
|
||||
|
||||
if (p_function->get_datatype().is_resolving()) {
|
||||
p_function->set_datatype(prev_datatype);
|
||||
}
|
||||
|
|
@ -2158,7 +2168,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
|
|||
GDScriptParser::IdentifierNode *callee = static_cast<GDScriptParser::IdentifierNode *>(call->callee);
|
||||
if (callee->name == "range") {
|
||||
list_resolved = true;
|
||||
if (call->arguments.size() < 1) {
|
||||
if (call->arguments.is_empty()) {
|
||||
push_error(R"*(Invalid call for "range()" function. Expected at least 1 argument, none given.)*", call->callee);
|
||||
} else if (call->arguments.size() > 3) {
|
||||
push_error(vformat(R"*(Invalid call for "range()" function. Expected at most 3 arguments, %d given.)*", call->arguments.size()), call->callee);
|
||||
|
|
@ -2266,7 +2276,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
|
|||
GDScriptParser::DataType return_type;
|
||||
List<GDScriptParser::DataType> par_types;
|
||||
int default_arg_count = 0;
|
||||
BitField<MethodFlags> method_flags;
|
||||
BitField<MethodFlags> method_flags = {};
|
||||
if (get_function_signature(p_for->list, false, list_type, CoreStringName(_iter_get), return_type, par_types, default_arg_count, method_flags)) {
|
||||
variable_type = return_type;
|
||||
variable_type.type_source = list_type.type_source;
|
||||
|
|
@ -3323,28 +3333,24 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
|
||||
bool types_match = true;
|
||||
|
||||
{
|
||||
List<PropertyInfo>::ConstIterator arg_itr = info.arguments.begin();
|
||||
for (int i = 0; i < p_call->arguments.size(); ++arg_itr, ++i) {
|
||||
GDScriptParser::DataType par_type = type_from_property(*arg_itr, true);
|
||||
GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype();
|
||||
if (!is_type_compatible(par_type, arg_type, true)) {
|
||||
types_match = false;
|
||||
break;
|
||||
for (int64_t i = 0; i < p_call->arguments.size(); ++i) {
|
||||
GDScriptParser::DataType par_type = type_from_property(info.arguments[i], true);
|
||||
GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype();
|
||||
if (!is_type_compatible(par_type, arg_type, true)) {
|
||||
types_match = false;
|
||||
break;
|
||||
#ifdef DEBUG_ENABLED
|
||||
} else {
|
||||
if (par_type.builtin_type == Variant::INT && arg_type.builtin_type == Variant::FLOAT && builtin_type != Variant::INT) {
|
||||
parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, function_name);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (par_type.builtin_type == Variant::INT && arg_type.builtin_type == Variant::FLOAT && builtin_type != Variant::INT) {
|
||||
parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, function_name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (types_match) {
|
||||
List<PropertyInfo>::ConstIterator arg_itr = info.arguments.begin();
|
||||
for (int i = 0; i < p_call->arguments.size(); ++arg_itr, ++i) {
|
||||
GDScriptParser::DataType par_type = type_from_property(*arg_itr, true);
|
||||
for (int64_t i = 0; i < p_call->arguments.size(); ++i) {
|
||||
GDScriptParser::DataType par_type = type_from_property(info.arguments[i], true);
|
||||
if (p_call->arguments[i]->is_constant) {
|
||||
update_const_expression_builtin_type(p_call->arguments[i], par_type, "pass");
|
||||
}
|
||||
|
|
@ -3561,7 +3567,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
}
|
||||
|
||||
int default_arg_count = 0;
|
||||
BitField<MethodFlags> method_flags;
|
||||
BitField<MethodFlags> method_flags = {};
|
||||
GDScriptParser::DataType return_type;
|
||||
List<GDScriptParser::DataType> par_types;
|
||||
|
||||
|
|
@ -5574,7 +5580,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
|
|||
result.set_container_element_type(0, elem_type);
|
||||
} else if (p_property.type == Variant::DICTIONARY && p_property.hint == PROPERTY_HINT_DICTIONARY_TYPE) {
|
||||
// Check element type.
|
||||
StringName key_elem_type_name = p_property.hint_string.get_slice(";", 0);
|
||||
StringName key_elem_type_name = p_property.hint_string.get_slicec(';', 0);
|
||||
GDScriptParser::DataType key_elem_type;
|
||||
key_elem_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
|
||||
|
||||
|
|
@ -5599,7 +5605,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
|
|||
}
|
||||
key_elem_type.is_constant = false;
|
||||
|
||||
StringName value_elem_type_name = p_property.hint_string.get_slice(";", 1);
|
||||
StringName value_elem_type_name = p_property.hint_string.get_slicec(';', 1);
|
||||
GDScriptParser::DataType value_elem_type;
|
||||
value_elem_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDSCRIPT_ANALYZER_H
|
||||
#define GDSCRIPT_ANALYZER_H
|
||||
#pragma once
|
||||
|
||||
#include "gdscript_cache.h"
|
||||
#include "gdscript_parser.h"
|
||||
|
|
@ -167,5 +166,3 @@ public:
|
|||
|
||||
GDScriptAnalyzer(GDScriptParser *p_parser);
|
||||
};
|
||||
|
||||
#endif // GDSCRIPT_ANALYZER_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDSCRIPT_BYTE_CODEGEN_H
|
||||
#define GDSCRIPT_BYTE_CODEGEN_H
|
||||
#pragma once
|
||||
|
||||
#include "gdscript_codegen.h"
|
||||
#include "gdscript_function.h"
|
||||
|
|
@ -552,5 +551,3 @@ public:
|
|||
|
||||
virtual ~GDScriptByteCodeGenerator();
|
||||
};
|
||||
|
||||
#endif // GDSCRIPT_BYTE_CODEGEN_H
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ void GDScriptCache::remove_script(const String &p_path) {
|
|||
|
||||
if (HashMap<String, Vector<ObjectID>>::Iterator E = singleton->abandoned_parser_map.find(p_path)) {
|
||||
for (ObjectID parser_ref_id : E->value) {
|
||||
Ref<GDScriptParserRef> parser_ref{ ObjectDB::get_instance(parser_ref_id) };
|
||||
Ref<GDScriptParserRef> parser_ref = { ObjectDB::get_instance(parser_ref_id) };
|
||||
if (parser_ref.is_valid()) {
|
||||
parser_ref->clear();
|
||||
}
|
||||
|
|
@ -275,7 +275,7 @@ String GDScriptCache::get_source_code(const String &p_path) {
|
|||
source_file.write[len] = 0;
|
||||
|
||||
String source;
|
||||
if (source.parse_utf8((const char *)source_file.ptr(), len) != OK) {
|
||||
if (source.append_utf8((const char *)source_file.ptr(), len) != OK) {
|
||||
ERR_FAIL_V_MSG("", "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode.");
|
||||
}
|
||||
return source;
|
||||
|
|
@ -460,7 +460,7 @@ void GDScriptCache::clear() {
|
|||
|
||||
for (const KeyValue<String, Vector<ObjectID>> &KV : singleton->abandoned_parser_map) {
|
||||
for (ObjectID parser_ref_id : KV.value) {
|
||||
Ref<GDScriptParserRef> parser_ref{ ObjectDB::get_instance(parser_ref_id) };
|
||||
Ref<GDScriptParserRef> parser_ref = { ObjectDB::get_instance(parser_ref_id) };
|
||||
if (parser_ref.is_valid()) {
|
||||
parser_ref->clear();
|
||||
}
|
||||
|
|
@ -485,6 +485,7 @@ void GDScriptCache::clear() {
|
|||
parser_map_refs.clear();
|
||||
singleton->shallow_gdscript_cache.clear();
|
||||
singleton->full_gdscript_cache.clear();
|
||||
singleton->static_gdscript_cache.clear();
|
||||
}
|
||||
|
||||
GDScriptCache::GDScriptCache() {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDSCRIPT_CACHE_H
|
||||
#define GDSCRIPT_CACHE_H
|
||||
#pragma once
|
||||
|
||||
#include "gdscript.h"
|
||||
|
||||
|
|
@ -42,6 +41,8 @@ class GDScriptAnalyzer;
|
|||
class GDScriptParser;
|
||||
|
||||
class GDScriptParserRef : public RefCounted {
|
||||
GDSOFTCLASS(GDScriptParserRef, RefCounted);
|
||||
|
||||
public:
|
||||
enum Status {
|
||||
EMPTY,
|
||||
|
|
@ -122,5 +123,3 @@ public:
|
|||
GDScriptCache();
|
||||
~GDScriptCache();
|
||||
};
|
||||
|
||||
#endif // GDSCRIPT_CACHE_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GDSCRIPT_CODEGEN_H
|
||||
#define GDSCRIPT_CODEGEN_H
|
||||
#pragma once
|
||||
|
||||
#include "gdscript_function.h"
|
||||
#include "gdscript_utility_functions.h"
|
||||
|
|
@ -165,5 +164,3 @@ public:
|
|||
|
||||
virtual ~GDScriptCodeGenerator() {}
|
||||
};
|
||||
|
||||
#endif // GDSCRIPT_CODEGEN_H
|
||||
|
|
|
|||