скайбоксы, рендер воды, документация

This commit is contained in:
2026-06-27 18:33:55 +04:00
parent 579b9e10c9
commit b051012920
14 changed files with 1775 additions and 101 deletions
+18 -1
View File
@@ -180,6 +180,7 @@ Ref<Image> BLPLoader::parse(const uint8_t *data, size_t len) {
const size_t palette_ofs = sizeof(BLP2Header);
if (palette_ofs + 256*4 > len) return Ref<Image>();
const uint8_t *palette = data + palette_ofs;
const uint8_t *alpha = mip + (size_t)w * (size_t)h;
rgba.resize(w * h * 4);
for (uint32_t i = 0; i < w * h && i < mip_size; ++i) {
@@ -187,7 +188,23 @@ Ref<Image> BLPLoader::parse(const uint8_t *data, size_t len) {
rgba[i*4+0] = palette[idx*4+2]; // R (from BGR)
rgba[i*4+1] = palette[idx*4+1]; // G
rgba[i*4+2] = palette[idx*4+0]; // B
rgba[i*4+3] = (hdr.alphaDepth == 0) ? 255 : mip[w*h + i];
uint8_t a = 255;
if (hdr.alphaDepth == 8) {
size_t alpha_pos = (size_t)w * (size_t)h + i;
a = alpha_pos < mip_size ? mip[alpha_pos] : 255;
} else if (hdr.alphaDepth == 4) {
size_t byte_pos = i >> 1;
if ((size_t)w * (size_t)h + byte_pos < mip_size) {
uint8_t nibble = (i & 1) ? (alpha[byte_pos] >> 4) : (alpha[byte_pos] & 0x0F);
a = (uint8_t)(nibble * 17);
}
} else if (hdr.alphaDepth == 1) {
size_t byte_pos = i >> 3;
if ((size_t)w * (size_t)h + byte_pos < mip_size) {
a = (alpha[byte_pos] & (1 << (i & 7))) ? 255 : 0;
}
}
rgba[i*4+3] = a;
}
} else if (hdr.encoding == 3) {
+7
View File
@@ -199,6 +199,8 @@ Dictionary M2Loader::parse_m2(const std::vector<uint8_t> &buf, const std::string
// ── Textures ─────────────────────────────────────────────────────────────
PackedStringArray textures;
PackedInt32Array texture_types;
PackedInt32Array texture_flags;
const auto *tex_arr = safe_array<M2Texture>(buf, hdr.ofsTextures, hdr.nTextures);
if (tex_arr) {
for (uint32_t i = 0; i < hdr.nTextures; ++i) {
@@ -217,6 +219,8 @@ Dictionary M2Loader::parse_m2(const std::vector<uint8_t> &buf, const std::string
}
}
textures.push_back(to_godot(fname));
texture_types.push_back((int)t.type);
texture_flags.push_back((int)t.flags);
}
}
@@ -313,8 +317,11 @@ Dictionary M2Loader::parse_m2(const std::vector<uint8_t> &buf, const std::string
Dictionary result;
result["textures"] = textures;
result["texture_types"] = texture_types;
result["texture_flags"] = texture_flags;
result["materials"] = materials;
result["texture_combos"] = texture_combos;
result["model_path"] = to_godot(path);
result["vertices"] = vertices;
result["normals"] = normals;
result["uvs"] = uvs;
+3
View File
@@ -24,8 +24,11 @@ namespace godot {
// Return Dictionary:
// {
// "textures": PackedStringArray, # .blp texture paths (may be empty for replaceable)
// "texture_types": PackedInt32Array, # M2Texture.type per texture slot
// "texture_flags": PackedInt32Array, # M2Texture.flags per texture slot
// "materials": Array[Dictionary], # [{flags, blend_mode}]
// "texture_combos": PackedInt32Array, # textureCombos[i] = index into textures
// "model_path": String, # absolute source .m2 path
// "vertices": PackedVector3Array, # Godot-space positions
// "normals": PackedVector3Array,
// "uvs": PackedVector2Array,
+1 -1
View File
@@ -313,7 +313,7 @@ Dictionary WMOLoader::parse_group(const std::vector<uint8_t> &buf) {
auto *v = sc.array<MOTVEntry>();
uvs.resize(n);
for (uint32_t i = 0; i < n; ++i)
uvs[i] = Vector2(v[i].u, 1.0f - v[i].v);
uvs[i] = Vector2(v[i].u, v[i].v);
} else if (sc.is("MOVI")) {
uint32_t n = sc.size / 2;