Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class UnjReader {
- constructor() {
- this.materials = []
- this.vertex_groups = [];
- this.bones = [];
- this.direct_calls = [];
- }
- parse(arraybuffer) {
- if (arraybuffer.byteLength < 16) {
- return false;
- }
- this.view = new DataView(arraybuffer);
- const MAGIC_NUOB = 0x424f554e;
- const magic = this.view.getUint32(0x00, true);
- const length = this.view.getUint32(0x04, true);
- const header_ofs = this.view.getUint32(0x08, true);
- const three = this.view.getUint32(0x0c, true);
- if (magic !== MAGIC_NUOB) {
- return false;
- }
- if (length !== arraybuffer.byteLength - 8) {
- return false;
- }
- if (header_ofs > arraybuffer.byteLength) {
- return false;
- }
- this.header_ofs = header_ofs;
- if (three !== 3) {
- console.warn("Omg, is this not a three?")
- }
- this.readheader();
- this.readMaterials();
- this.readVertexGroups();
- this.readBones();
- this.readDrawCalls();
- return true;
- }
- readHeader() {
- const ofs = this.header_ofs;
- const unj_header_t = {
- center: {
- x: this.view.getFloat32(ofs + 0x00, true),
- y: this.view.getFloat32(ofs + 0x04, true),
- z: this.view.getFloat32(ofs + 0x08, true),
- },
- radius: this.view.getFloat32(ofs + 0x0c, true),
- material_count: this.view.getUint32(ofs + 0x10, true),
- material_ofs: this.view.getUint32(ofs + 0x14, true),
- vertex_group_count: this.view.getUint32(ofs + 0x18, true),
- vertex_group_ofs: this.view.getUint32(ofs + 0x1c, true),
- index_group_count: this.view.getUint32(ofs + 0x20, true),
- index_group_ofs: this.view.getUint32(ofs + 0x24, true),
- bone_count: this.view.getUint32(ofs + 0x28, true),
- bone_tree_depth: this.view.getUint32(ofs + 0x2c, true),
- bone_ofs: this.view.getUint32(ofs + 0x30, true),
- draw_count: this.view.getUint32(ofs + 0x34, true),
- draw_ofs: this.view.getUint32(ofs + 0x38, true)
- };
- this.header = unj_header_t;
- }
- readMaterials() {
- const mat_count = this.header.material_count;
- // First we read the number of textures in each material and then get the offset
- // to each of the respective material definitions
- for (let i = 0; i < mat_count; i++) {
- const ofs = this.header.material_ofs;;
- const unj_matlist_size = 8;
- const unj_matlist_t = {
- diffuse_texture_count: this.view.getUint8(mat_ofs + i * unj_mat_size + 0x00),
- effect_texture_count: this.view.getUint8(mat_ofs + i * unj_mat_size + 0x01),
- material_ofs: this.view.getUint32(mat_ofs + i * unj_matlist_size + 0x04)
- }
- this.materials[i] = {
- color: {},
- offset: unj_matlist_t.material_ofs,
- diffuse_textures: new Array(unj_matlist_t.diffuse_texture_count),
- effect_textures: new Array(unj_matlist_t.effect_texture_count)
- }
- }
- // Then we 'seek' to each one of the respective material definitions, read the
- // color values for the material, and then the texture preferences
- this.materials.forEach(mat => {
- let ofs = mat.offset;
- // We skip the first 8 bytes, since we don't know what it does
- ofs += 8;
- // Then we read the mapping type of the respective textures
- for (let i = 0; i < mat.diffuse_textures.length; i++) {
- const byte = this.view.getUint8(ofs + 1);
- ofs += 4;
- mat.diffuse_textures[i] = {};
- switch (byte) {
- case 1:
- mat.diffuse_textures[i].mappingType = "env";
- break;
- default:
- mat.diffuse_textures[i].mappingType = "uv";
- break;
- }
- }
- // Then we read all of the color values for the material
- for (let i = 0; i < 12; i++) {
- const a = this.view.getUint8(ofs + 0);
- const b = this.view.getUint8(ofs + 1);
- const c = this.view.getUint8(ofs + 2);
- const d = this.view.getUint8(ofs + 3);
- ofs += 4;
- switch (d) {
- case 0x54:
- mat.color.emissive = {
- r: a / 255,
- g: b / 255,
- b: c / 255
- };
- break;
- case 0x55:
- mat.color.ambient = {
- r: a / 255,
- g: b / 255,
- b: c / 255
- };
- break;
- case 0x56:
- mat.color.diffuse = {
- r: a / 255,
- g: b / 255,
- b: c / 255
- };
- break;
- case 0x57:
- mat.color.specular = {
- r: a / 255,
- g: b / 255,
- b: c / 255
- };
- break;
- case 0x58:
- const alpha = a / 255;
- mat.color.emissive = mat.color.emissive || {};
- mat.color.ambient = mat.color.ambient || {};
- mat.color.diffuse = mat.color.diffuse || {};
- mat.color.specular = mat.color.specular || {};
- mat.color.emissive.a = alpha;
- mat.color.ambient.a = alpha;
- mat.color.diffuse.a = alpha;
- mat.color.specular.a = alpha;
- break;
- case 0x5b:
- // convert bytes to float
- mat.color.specular_coefficient = [a, b, c, d];
- break;
- }
- }
- // Then we read all of the texture properties
- for (let i = 0; i < mat.diffuse_textures.length; i++) {
- do {
- const a = this.view.getUint8(ofs + 0);
- const b = this.view.getUint8(ofs + 1);
- const c = this.view.getUint8(ofs + 2);
- const d = this.view.getUint8(ofs + 3);
- ofs += 4;
- switch (d) {
- case 0x21:
- mat.diffuse_textures[i].disableLighting = (a === 1);
- break;
- case 0x22:
- mat.diffuse_textures[i].alphaTestEnabled = (a === 1);
- break;
- case 0x23:
- mat.diffuse_textures[i].zTestEnabled = (a === 1);
- break;
- case 0x24:
- mat.diffuse_textures[i].stencilTestEnabled = (a === 1);
- break;
- case 0x27:
- mat.diffuse_textures[i].colorTestEnabled = (a === 1);
- break;
- case 0x28:
- mat.diffuse_textures[i].logicOpEnabled = (a === 1);
- break;
- case 0x48:
- // convert bytes to float
- mat.diffuse_textures[i].scaleU = [a, b, c, d];
- break;
- case 0x49:
- // convert bytes to float
- mat.diffuse_textures[i].scaleV = [a, b, c, d]
- break;
- case 0x4A:
- mat.diffuse_textures[i].offsetU = [a, b, c, d];
- break;
- case 0x4B:
- mat.diffuse_textures[i].offsetV = [a, b, c, d];
- break;
- case 0x5E:
- mat.diffuse_textures[i].diffuseEnabled = a < 2;
- break;
- case 0xC7:
- mat.diffuse_textures[i].clampU = (a & 1) !== 0;
- mat.diffuse_textures[i].clampV = (b & 1) !== 0;
- break;
- case 0xC9:
- mat.diffuse_textures[i].textureFunction = (a & 7);
- mat.diffuse_textures[i].textureFunctionUsesAlpha = (b === 1);
- break;
- case 0xDB:
- mat.diffuse_textures[i].alphaFunction = a;
- mat.diffuse_textures[i].alphaRef = b;
- break;
- case 0xDE:
- mat.diffuse_textures[i].zTestFunction = a;
- break;
- case 0xDF:
- mat.diffuse_textures[i].blendMode = b;
- mat.diffuse_textures[i].blendFactorA = a;
- mat.diffuse_textures[i].blendFactorB = a;
- break;
- case 0xE0:
- mat.diffuse_textures[i].blendFixedA = (c << 16) | (b << 8) | a;
- break;
- case 0xE1:
- mat.diffuse_textures[i].blendFixedB = (c << 16) | (b << 8) | a;
- break;
- case 0xE6:
- mat.diffuse_textures[i].logicOp = a;
- break;
- case 0xE7:
- mat.diffuse_textures[i].zWriteDisabled = a ? true : false;
- break;
- case 0xE8:
- mat.diffuse_textures[i].maskRGB = (c << 16) | (b << 8) | a;
- break;
- case 0xE9:
- mat.diffuse_textures[i].maskAlpha = (c << 16) | (b << 8) | a;
- break;
- }
- } while (d !== 0x0b);
- }
- // Then we read the texture id
- for (let i = 0; i < mat.diffuse_textures.length; i++) {
- mat.diffuse_textures[i].texture_id = this.view.getUint32(ofs, true);
- ofs += 4;
- }
- });
- }
- readVertexGroups() {
- // First we 'seek' to the vertex group definitions and read the
- // uv count and the offset to the vertex list definition
- let ofs = this.header.vertex_group_ofs;
- for (let i = 0; i < this.header.vertex_group_count; i++) {
- const unj_vertex_group_t = {
- uv_count: this.view.getUint32(ofs + 0, true),
- group_ofs: this.view.getUint32(ofs + 4, true)
- }
- this.vertex_groups[i] = unj_vertex_group_t;
- ofs += 8;
- }
- // Then we seek to each one of the vertex list definitions and
- // read the number of bone influences, which bones, how many vertices
- // and the format of the stored vertices in the vertex list
- for (let i = 0; i < this.header.vertex_group_count; i++) {
- ofs = this.vertex_groups[i].group_ofs;
- const unj_vertex_list_t = {
- unkown_1: this.view.getUint32(ofs + 0x00, true),
- vertex_format: this.view.getUint32(ofs + 0x04, true),
- unknown_2: this.view.getUint32(ofs + 0x08, true),
- unknown_3: this.view.getUint8(ofs + 0x09),
- vertex_length: this.view.getUint8(ofs + 0x0a),
- nop: this.view.getUint12(ofs + 0x0e, true),
- vertex_count_ofs: this.view.getUint32(ofs + 0x10, true),
- vertex_list_ofs: this.view.getUint32(ofs + 0x14, true),
- bone_binding_ofs: this.view.getUint32(ofs + 0x18, true),
- bone_binding_count: this.view.getUint32(ofs + 0x1c, true),
- total_vertex_count: this.view.getUint32(ofs + 0x20, true),
- unknown_4: this.view.getUint32(ofs + 0x24, true),
- unknown_5: this.view.getUint32(ofs + 0x28, true),
- vertex_scale: this.view.getFloat32(ofs + 0x2c, true)
- };
- // Read the number of vertices in the vertex list
- ofs = unj_vertex_list_t.vertex_count_ofs;
- unj_vertex_list_t.vertex_count = this.view.getUint32(ofs, true);
- // Read each of the bone influences for the group
- unj_vertex_list_t.bones = new Array();
- ofs = unj_vertex_list_t.bone_binding_ofs;
- for (let k = 0; k < unj_vertex_list_t.bone_binding_count; k++) {
- unj_vertex_list_t.bones[k] = this.view.getUint32(ofs, true);
- ofs += 4;
- }
- // Then we save all of the values from the struct into instance memory
- for (let key in unj_vertex_list_t) {
- this.vertex_groups[i][key] = unj_vertex_list_t[key];
- }
- }
- // Then we seek to the vertex list and read the values for the vertices
- for (let i = 0; i < this.header.vertex_group_count; i++) {
- const UINT8 = 1;
- const INT8 = 1;
- const INT16 = 2;
- const FLOAT = 3;
- const bones = this.vertex_groups[i].bones;
- const vertices = new Array(this.vertex_groups[i].vertex_count);
- const scale = this.vertex_groups[i].scale;
- const format = this.vertex_groups[i].vertex_format;
- const stride = this.vertex_groups[i].vertex_length;
- const uv_count = this.vertex_groups[i].uv_count;
- const uvFormat = (format & 0x3);
- const colorFormat = (format >> 2) & 0x7;
- const normalFormat = (format >> 5) & 0x3;
- const positionFormat = (format >> 7) & 0x3;
- const weightFormat = (format >> 9) & 0x3;
- // Then we seek to the vertex list and read the values
- let ofs = this.vertex_groups[i].vertex_list_ofs;
- for (let k = 0; k < vertices.length; k++) {
- const vertex = {};
- const start = ofs;
- // Read bone weight
- vertex.weight = [];
- switch (weightFormat) {
- case UINT8:
- for (let j = 0; j < bones.length; j++) {
- vertex.weight[j] = {
- bone_id: bones[j],
- weight: this.view.getUint8(ofs) / 0x7f
- }
- ofs++;
- }
- break;
- case INT16:
- for (let j = 0; j < bones.length; j++) {
- vertex.weight[j] = {
- bone_id: bones[j],
- weight: this.view.getInt16(ofs, true) / 0x7fff
- }
- ofs += 2;
- }
- break;
- case FLOAT:
- for (let j = 0; j < bones.length; j++) {
- vertex.weight[j] = {
- bone_id: bones[j],
- weight: this.view.getFloat32(ofs, true);
- }
- ofs += 4;
- }
- break;
- }
- // Read uv values
- vertex.uvs = [];
- switch (uvFormat) {
- case INT8:
- for (let j = 0; j < uv_count; j++) {
- vertex.uvs[j] = {
- u: this.view.getInt8(ofs + 0) / 0x7f,
- v: this.view.getInt8(ofs + 1) / 0x7f
- }
- ofs += 2;
- }
- break;
- case INT16:
- if (ofs % 2) {
- ofs += 2 - (ofs % 2);
- }
- for (let j = 0; j < uv_count; j++) {
- vertex.uvs[j] = {
- u: this.view.getInt16(ofs + 0) / 0x7fff,
- v: this.view.getInt16(ofs + 2) / 0x7fff
- }
- ofs += 4;
- }
- break;
- case FLOAT:
- if (ofs % 4) {
- ofs += 4 - (ofs % 4);
- }
- for (let j = 0; j < bones.length; j++) {
- vertex.uvs[j] = {
- u: this.view.getFloat32(ofs + 0),
- v: this.view.getFloat32(ofs + 4)
- }
- ofs += 8;
- }
- break;
- }
- // Read colors (we assume ARGB4444)
- if (colorFormat) {
- if (ofs % 2) {
- ofs += 2 - (ofs % 2);
- }
- let byte1 = this.view.getUint8(ofs + 0);
- let byte2 = this.view.getUint8(ofs + 1);
- ofs += 2;
- vertex.color = {
- r: ((byte1 >> 0) & 0xf) / 0x0f,
- g: ((color1 >> 4) & 0xf) / 0x0f,
- b: ((color2 >> 0) & 0xf) / 0x0f,
- a: ((color2 >> 4) & 0xf) / 0x0f
- };
- }
- // Read normals
- switch (normalFormat) {
- case UINT8:
- vertex.normal = {
- x: this.view.getUint8(ofs + 0) / 0x7f,
- y: this.view.getUint8(ofs + 1) / 0x7f,
- z: this.view.getUint8(ofs + 2) / 0x7f
- }
- ofs += 3;
- break;
- case INT16:
- if (ofs % 2) {
- ofs += 2 - (ofs % 2);
- }
- vertex.normal = {
- x: this.view.getInt16(ofs + 0) / 0x7fff,
- y: this.view.getInt16(ofs + 2) / 0x7fff,
- z: this.view.getInt16(ofs + 6) / 0x7fff
- }
- ofs += 6;
- break;
- case FLOAT:
- if (ofs % 4) {
- ofs += 4 - (ofs % 4);
- }
- vertex.normal = {
- x: this.view.getFloat32(ofs + 0),
- y: this.view.getFloat32(ofs + 4),
- z: this.view.getFloat32(ofs + 8)
- }
- ofs += 12;
- break;
- }
- // Read Position
- switch (positionFormat) {
- case UINT8:
- vertex.position = {
- x: this.view.getUint8(ofs + 0) / 0x7f * scale,
- y: this.view.getUint8(ofs + 1) / 0x7f * scale,
- z: this.view.getUint8(ofs + 2) / 0x7f * scale
- }
- ofs += 3;
- break;
- case INT16:
- if (ofs % 2) {
- ofs += 2 - (ofs % 2);
- }
- vertex.position = {
- x: this.view.getInt16(ofs + 0) / 0x7fff * scale,
- y: this.view.getInt16(ofs + 2) / 0x7fff * scale,
- z: this.view.getInt16(ofs + 6) / 0x7fff * scale
- }
- ofs += 6;
- break;
- case FLOAT:
- if (ofs % 4) {
- ofs += 4 - (ofs % 4);
- }
- vertex.position = {
- x: this.view.getFloat32(ofs + 0) * scale,
- y: this.view.getFloat32(ofs + 4) * scale,
- z: this.view.getFloat32(ofs + 8) * scale
- }
- ofs += 12;
- break;
- }
- const end = ofs;
- if (end - start !== vertex_length) {
- throw new Error("Phission Mailed, better luck next time");
- }
- vertices[k] = vertex;
- }
- // Last we replace the vertex group with the finalized vertex list
- this.vertex_groups[i] = vertices;
- }
- }
- readBones() {
- let ofs = this.header.bone_ofs;
- for (let i = 0; i < this.header.bone_count; i++) {
- const unj_bone_t = {
- flags: this.view.getUint32(ofs + 0x00, true),
- bone_id: this.view.getUint16(ofs + 0x04, true),
- parent_id: this.view.getUint16(ofs + 0x06, true),
- child_id: this.view.getUint16(ofs + 0x08, true),
- sibling_id: this.view.getUint16(ofs + 0x0a, true),
- position: {
- x: this.view.getFloat32(ofs + 0x0c, true),
- y: this.view.getFloat32(ofs + 0x10, true),
- z: this.view.getFloat32(ofs + 0x14, true)
- },
- rotation: {
- x: this.view.getInt32(ofs + 0x18, true),
- y: this.view.getInt32(ofs + 0x1c, true),
- z: this.view.getInt32(ofs + 0x20, true)
- },
- scale: x: this.view.getFloat32(ofs + 0x24, true),
- y: this.view.getFloat32(ofs + 0x28, true),
- z: this.view.getFloat32(ofs + 0x2c, true)
- },
- transform[16] = [
- this.view.getFloat32(ofs + 0x30, true),
- this.view.getFloat32(ofs + 0x34, true),
- this.view.getFloat32(ofs + 0x38, true),
- this.view.getFloat32(ofs + 0x3c, true),
- this.view.getFloat32(ofs + 0x40, true),
- this.view.getFloat32(ofs + 0x44, true),
- this.view.getFloat32(ofs + 0x48, true),
- this.view.getFloat32(ofs + 0x4c, true),
- this.view.getFloat32(ofs + 0x50, true),
- this.view.getFloat32(ofs + 0x54, true),
- this.view.getFloat32(ofs + 0x58, true),
- this.view.getFloat32(ofs + 0x5c, true),
- this.view.getFloat32(ofs + 0x50, true),
- this.view.getFloat32(ofs + 0x54, true),
- this.view.getFloat32(ofs + 0x58, true),
- this.view.getFloat32(ofs + 0x5c, true)
- ],
- bound_sphere: {
- x: this.view.getFloat32(ofs + 0x60, true),
- y: this.view.getFloat32(ofs + 0x64, true),
- z: this.view.getFloat32(ofs + 0x68, true),
- r: this.view.getFloat32(ofs + 0x6c, true)
- },
- unknown: this.view.getInt32(ofs + 0x70, true),
- half_dimensions: {
- x: this.view.getFloat32(ofs + 0x74, true),
- y: this.view.getFloat32(ofs + 0x78, true),
- z: this.view.getFloat32(ofs + 0x7c, true)
- }
- }
- this.bones[i] = unj_bone_t;
- ofs += 0x90;
- }
- readDrawCalls() {
- let ofs = this.header.draw_ofs;
- const groups = [];
- for (let i = 0; i < this.header.draw_count; i++) {
- const unj_drawgroups_t = {
- unknown_byte_1: this.view.getUint8(ofs + 0x00),
- unknown_byte_2: this.view.getUint8(ofs + 0x01),
- unknown_short_1: this.view.getUint16(ofs + 0x02, true),
- direct_draw_count: this.view.getUint32(ofs + 0x04, true),
- direct_draw_ofs: this.view.getUint32(ofs + 0x08, true),
- indexed_draw_count: this.view.getUint32(ofs + 0x0c, true),
- indexed_draw_ofs: this.view.getUint32(ofs + 0x10, true)
- }
- groups[i] = unj_drawgroups_t;
- ofs += 0x14;
- };
- groups.forEach(group => {
- ofs = group.indexed_draw_ofs;
- for (let i = 0; i < group.indexed_draw_count; i++) {
- const unj_direct_call_t = {
- center: {
- x: this.view.getFloat32(ofs + 0x00, true),
- y: this.view.getFloat32(ofs + 0x04, true),
- z: this.view.getFloat32(ofs + 0x08, true),
- },
- radius: this.view.getFloat32(ofs + 0x0c, true),
- top_level_bone: this.view.getUint32(ofs + 0x10, true),
- unknown_int1: this.view.getUint32(ofs + 0x14, true),
- material_group: this.view.getUint32(ofs + 0x18, true),
- vertex_group: this.view.getUint32(ofs + 0x1c, true),
- unknown_int2: this.view.getUint32(ofs + 0x20, true)
- }
- ofs += 0x24;
- this.direct_calls.push(unj_direct_call_t);
- }
- });
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement