Created
May 20, 2023 20:37
-
-
Save Fothsid/0d01f5d2f3c6d48de8963f5171a2933b to your computer and use it in GitHub Desktop.
Resident Evil Outbreak .NBD pattern file for ImHex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Resident Evil Outbreak .NBD pattern file for ImHex | |
// Made by Fothsid. | |
// | |
// WARNING: Doesn't work for the majority of EFxx.NBD files, | |
// as those have incorrect subchunk/data count values. | |
// Seems like the game relies solely on the chunk size | |
// when parsing the models. | |
// Wasn't tested with room models, but theoretically should work just fine. | |
// | |
#include <std/string.pat> | |
#pragma eval_depth 250 | |
#pragma pattern_limit 200000 | |
bool room_nbd = false; | |
struct NBDEntry { | |
char type[3]; | |
char pad; | |
u32 offset; | |
u32 size; | |
u32 texCount; | |
}; | |
struct TID { | |
u32 count; | |
u32 ids[count]; | |
}; | |
struct CompressedTexture { | |
u32 size; | |
u8 data[size]; | |
}; | |
enum ChunkType : u32 { | |
TextureRef = 0x00000000, | |
Model = 0x00000001, | |
MeshList = 0x00000002, | |
Mesh = 0x00000004, | |
PrimLists = 0x00000005, | |
MaterialList = 0x00000009, | |
TextureList = 0x0000000A, | |
Date = 0x00020000, | |
TriStripsFW = 0x00030000, | |
TriStripsPW = 0x00040000, | |
MaterialRefs = 0x00050000, | |
TStripMaterials = 0x00060000, | |
Vertices = 0x00070000, | |
Normals = 0x00080000, | |
TexCoords = 0x000A0000, | |
VertexColors = 0x000B0000, | |
Weights = 0x000C0000, | |
RenderAttribs = 0x000F0000, | |
NodeRefs = 0x00100000, | |
MaterialConstant= 0x00120000, | |
MaterialLambert = 0x00130000, | |
MaterialPhong = 0x00140000, | |
MaterialVColors = 0x00150000, | |
}; | |
enum AHIChunkType : u32 { | |
Hierarchy = 0xC0000000, | |
RootsType1 = 0x80000000, | |
RootsType2 = 0x00000000, | |
Node = 0x40000001, | |
MeshNode = 0x40000002, | |
JointNode = 0x40000003 | |
}; | |
struct Date { | |
u32 value; | |
} [[sealed, format("format_date")]]; | |
fn format_date(Date date) | |
{ | |
return std::format("{:02}-{:02}-2{:03}", (date.value >> 8) & 0xFF, | |
(date.value >> 16) & 0xFF, | |
(date.value >> 24) & 0xFF); | |
}; | |
struct TriStrip { | |
u32 count; | |
u32 indices[count&0x7FFFFFFF]; | |
}; | |
struct RenderAttribs { | |
u32 version; // Always 0x10000 | |
u32 material; | |
u32 specular; | |
u32 cull; | |
u32 scissor; // Always seems to be 1 | |
u32 light; // Used; but have to figure out what it does exactly | |
u32 wrap; | |
u32 uvScroll; | |
u32 disableFog; | |
u32 fadeCol; | |
u32 specialShader; // Not used. | |
u32 alphaSrc; | |
u32 alphaDst; | |
u32 alphaOp; | |
u32 zOp; // IGNORE. The game forces everything to ZOP_LESS | |
u32 zWrite; | |
u32 filtering; | |
u32 addressMode; | |
}; | |
struct vec4 { float x, y, z, w; }; | |
struct vec3 { float x, y, z; }; | |
struct vec2 { float x, y; }; | |
struct Node { | |
u32 id; | |
s32 parentId; | |
s32 childId; | |
s32 nextId; | |
vec4 scale; | |
vec4 rotation; | |
vec4 translation; | |
s32 meshId; | |
s32 groupId; | |
u32 _dummy0[46][[hidden]]; | |
}; | |
struct Material { | |
vec4 ambient; | |
vec4 diffuse; | |
vec4 specular; | |
float shininess; | |
u32 textureCount [[hidden]]; | |
u32 _dummy0[50] [[hidden]]; | |
u32 textureRefIds[textureCount]; | |
}; | |
struct WeightNode { | |
u32 nodeId; | |
float weight; | |
}; | |
struct Weight { | |
u32 count [[hidden]]; | |
WeightNode nodes[count] [[inline]]; | |
}; | |
struct TextureRef { | |
u32 id; | |
u32 width; | |
u32 height; | |
u32 tiling; | |
u32 dummy[60] [[hidden]]; | |
}; | |
struct AMOChunk { | |
ChunkType type; | |
u32 count [[hidden]]; | |
u32 size [[hidden]]; | |
match (type) { | |
(ChunkType::Model | | |
ChunkType::MeshList | | |
ChunkType::Mesh | | |
ChunkType::PrimLists | | |
ChunkType::MaterialList | | |
ChunkType::TextureList): AMOChunk data[count] [[inline]]; | |
(ChunkType::Date): Date data; | |
(ChunkType::TriStripsFW | | |
ChunkType::TriStripsPW): TriStrip data[count]; | |
(ChunkType::MaterialRefs | | |
ChunkType::TStripMaterials | | |
ChunkType::NodeRefs): u32 data[count]; | |
(ChunkType::Vertices | | |
ChunkType::Normals): vec3 data[count]; | |
(ChunkType::TexCoords): vec2 data[count]; | |
(ChunkType::VertexColors): vec4 data[count]; | |
(ChunkType::Weights): Weight data[count]; | |
(ChunkType::RenderAttribs): RenderAttribs data [[inline]]; | |
(ChunkType::MaterialConstant | | |
ChunkType::MaterialLambert | | |
ChunkType::MaterialPhong | | |
ChunkType::MaterialVColors): Material data [[inline]]; | |
(ChunkType::TextureRef): TextureRef data [[inline]]; | |
} | |
}; | |
struct AHIChunk { | |
AHIChunkType type; | |
u32 count [[hidden]]; | |
u32 size [[hidden]]; | |
match (type) { | |
(AHIChunkType::Hierarchy): AHIChunk data[count] [[inline]]; | |
(AHIChunkType::RootsType1 | | |
AHIChunkType::RootsType2): u32 data[count]; | |
(AHIChunkType::Node | | |
AHIChunkType::MeshNode | | |
AHIChunkType::JointNode): Node data [[inline]]; | |
} | |
}; | |
struct NBDHeader { | |
NBDEntry list[3] [[hidden]]; | |
if (list[0].type == "TID") { | |
TID tid @ list[0].offset; | |
room_nbd = true; | |
} | |
else if (list[0].type == "TEX") { | |
CompressedTexture textures[list[0].texCount] @ list[0].offset; | |
} | |
if (!room_nbd) { | |
NBDEntry addons[4] [[hidden]]; | |
AMOChunk model @ list[1].offset; | |
AHIChunk hierarchy @ list[2].offset; | |
if (addons[1].type == "SDW") { | |
u8 shadowData[addons[1].size] @ addons[1].offset; | |
} | |
if (addons[2].type == "AMO") { | |
AMOChunk addonModel @ addons[2].offset; | |
} | |
if (addons[3].type == "AHI") { | |
AHIChunk addonHierarchy @ addons[3].offset; | |
} | |
} | |
else { | |
NBDEntry addons[2] [[hidden]]; | |
AMOChunk stageModel @ list[1].offset; | |
AHIChunk stageHierarchy @ list[2].offset; | |
AMOChunk effectModel @ addons[0].offset; | |
AHIChunk effectHierarchy @ addons[1].offset; | |
} | |
}; | |
NBDHeader header @ 0x00; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment