Page 1 of 12

Diablo III .app

Posted: Sun Sep 11, 2011 4:29 am
by anhhungmeo1234
This is file in Diablo III, i think it's model. File simple:
http://www.mediafire.com/?5aacnbdea8mbneg

Re: Diablo III .app

Posted: Tue Sep 13, 2011 8:41 pm
by BoyC
Moving the .app research here from the game archive research forum.

I'll be updating this post as I make progress with the format.
Currently we have vertex, poly, normal, uv, tangent, bitangent and blendweight data mapped properly, there's still some stuff left to decipher.

Update #1: figured out what some of the unknown stuff is for, added hinge points
Update #2: finally found a good lead on the animation data, nothing to see yet, but I updated the script - maybe someone can work on it while I'm away
Update #3: animation stuff might have been a dead end, refactored the script a bit with new names
Update #4: some more refactoring of names as things get more clear

My current 010 editor template for parsing .app files is the following: (the text output in the editor is a wavefront object file that can be loaded into deep exploration for example)

Code: Select all

//--------------------------------------
//--- 010 Editor v3.2.1 Binary Template
//
// File: Diablo 3 appearance file template
// Author: BoyC
// Revision: v0.37
// Purpose: Analyzing 3D data in Diablo 3
//--------------------------------------

local unsigned int vxcnt=0;
local unsigned int LookCount=0;

struct ChunkData
{
    unsigned int Count<bgcolor=0xff00ff>;
    unsigned int Offset<format=hex,bgcolor=0xff00ff>;
    unsigned int Size<bgcolor=0xff00ff>;
};

struct ChunkHeader
{
    unsigned int h[4];
};

struct BONEDATA //size = 68
{
    unsigned int unk1[4];
    float unk2[3];
    unsigned int unk[3];
    float unk4[7];
};

struct BONE //size = 236
{
    char Name[64];
    int ParentID;
    float unk2[34]; //two matrices plus extra
    ChunkData UnkChunk;
    unsigned int unk[4];
    int unk3;
    Printf("# Bone: %s\n",Name);

    local int pos=FTell();
    FSeek(UnkChunk.Offset+16);
    
    if (UnkChunk.Offset)
    {
        struct 
        {
            BONEDATA bonedata[UnkChunk.Count]<optimize=false>;
        } bonedata<bgcolor=0x00f0a0,comment="Unknown purpose bone data">;        
    }

    FSeek(pos);
}; 

struct VERTEX //size = 44
{
    float x,y,z;
    unsigned char nx,ny,nz,nw;
    int unk3,unk4;
    unsigned short u,v;
    unsigned int unk1;
    char tx,ty,tz,tw;
    char bx,by,bz,bw;
    unsigned int unk2;

    //obj export part
    /**/
    local float ru=u,rv=v,rnx=nx,rny=ny,rnz=nz;
    ru=(ru-32767)/512.0f;
    rv=(rv-32767)/512.0f;
    rnx=(rnx-127)/127.0f;
    rny=(rny-127)/127.0f;
    rnz=(rnz-127)/127.0f;

    Printf("v %f %f %f\n",x,y,z);
    Printf("vt %f %f\n",ru,rv);    
    Printf("vn %f %f %f\n",rnx,rny,rnz);/**/
};

struct TRIINDICES
{
    unsigned short a,b,c;

    //obj export part
    Printf("f %d/%d/%d %d/%d/%d %d/%d/%d\n",vxcnt+a+1,vxcnt+a+1,vxcnt+a+1,vxcnt+b+1,vxcnt+b+1,vxcnt+b+1,vxcnt+c+1,vxcnt+c+1,vxcnt+c+1);
}; //complete

struct BLENDWEIGHT
{
    int BoneID;
    float BoneWeight;
}; //complete

struct BLENDDATA //size = 24
{
    BLENDWEIGHT Weights[3]<optimize=false>;
}; //complete

struct LOOKDATA //size = 248
{
    unsigned int Five;
    int MinusOne;
    unsigned int DataOffset1<format=hex>;
    unsigned int DataSize1;
    unsigned int unk[3];
    float Matrix[16];
    unsigned int unk2[2];
    unsigned int DataOffset2<format=hex>;
    unsigned int DataSize2;
    unsigned int unk3[35];
};

struct SUBOBJECT //size = 140
{
    char Name[128];
    unsigned int Offset,Size,Zero;
    
    local int pos=FTell();
    FSeek(Offset+16);
    
    struct 
    {
        LOOKDATA lookdata[LookCount]<optimize=false>;
    } LookDataList<bgcolor=0x00a0f0,comment="Look Descriptors">;        

    FSeek(pos);
};

struct MESH //size = 372
{
    int unk1;
    ChunkData VertexChunk; //vertex size = 44
    ChunkData WeightChunk; //weight size = 24
    int Zero1;
    ChunkData IndexChunk; // 16bit index buffer for a triangle list
    ChunkData UnknownChunk; // points to an array of chunkdatas, could be anim
    int unk5[4];
    char SubObjectName[128];
    char MeshName[128];
    float funk1[6]; //bounding box? 
    unsigned int Zero2;
    unsigned int unk[4];

    Printf("# unk1: %4d vxcount: %4d\n",unk1,VertexChunk.Count);
    Printf("# mesh %s is part of subobject %s\n",MeshName,SubObjectName);

    local unsigned int Pos=FTell();

    if (VertexChunk.Offset)
    {
        FSeek(VertexChunk.Offset);
        struct 
        {
            ChunkHeader ch;
            VERTEX vx[VertexChunk.Count]<optimize=false>;
        } Vertices;        
    }
    
    if (WeightChunk.Offset)
    {
        FSeek(WeightChunk.Offset);
        struct 
        {
            ChunkHeader ch;
            BLENDDATA w[VertexChunk.Count]<optimize=false>;
        } BlendWeights;        
    }

    if (IndexChunk.Offset)
    {
        FSeek(IndexChunk.Offset);
        struct 
        {
            ChunkHeader ch;
            TRIINDICES w[IndexChunk.Count/3]<optimize=false>;
        } Triangles;        
    }

    FSeek(Pos);
    vxcnt+=VertexChunk.Count;
}; 

struct HARDPOINT //size = 96
{  
    char Name[64];
    int ParentBone;
    float qx,qy,qz,qw; //rotation as a quaternion
    float x,y,z; //position
};

struct COLLISIONOBJ //size = 104
{
    unsigned int x[26];
};

struct NAME
{
    char Name[64];
};

struct 
{
    unsigned int DEADBEEF[8];
    unsigned int Counter1;

    ChunkData BoneChunk; // size = 236
    
    FSeek(FTell()+30*4);

    ChunkData MeshChunk; // size = 372

    FSeek(FTell()+9*4);

    float FloatAray1[4]; //bounding sphere?

    ChunkData CollisionChunk; // size = 104

    FSeek(FTell()+3*4);

    ChunkData HPChunk; // size = 96

    FSeek(FTell()+5*4);

    float One;
    FSeek(FTell()+6*4);

    ChunkData UnkChunk1;

    FSeek(FTell()+4);

    ChunkData UnkChunk2;

    FSeek(FTell()+4);

    ChunkData UnkChunk3;

    FSeek(FTell()+8);

    float FloatArray2[6]; //bounding box?

    FSeek(FTell()+10*4);

    char xobject[256];
    char xobjectpath[256];
    char xmesh[256];
    char xmeshpath[256];

    FSeek(FTell()+4*4);

    unsigned int LookCnt;
    LookCount=LookCnt;

    ChunkData SubObjectChunk; // size = 140

    FSeek(FTell()+4);

    ChunkData LookNameChunk; // size = 64 count = Counter1

    FSeek(FTell()+18*4);

    //previously referenced data starts here, header size is 0x628h

    Printf("# Bone Count: %d\n",BoneChunk.Count);
    Printf("# Mesh Count: %d\n",MeshChunk.Count);
   

    if (BoneChunk.Offset)
    {
        FSeek(BoneChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            BONE bone[BoneChunk.Count]<optimize=false>;
        } Bones<bgcolor=0xa0a0a0,comment="Bone data">;
    }

    if (MeshChunk.Offset)
    {
        FSeek(MeshChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            MESH mesh[MeshChunk.Count]<optimize=false>;
        } Models<bgcolor=0xb0f0b0,comment="Model data">;        
    }

    if (SubObjectChunk.Offset)
    {
        FSeek(SubObjectChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            SUBOBJECT group[SubObjectChunk.Count]<optimize=false>;
        } SubObjects<bgcolor=0xc0c0f0,comment="SubObjects">;        
    }

    if (HPChunk.Offset)
    {
        FSeek(HPChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            HARDPOINT hardpoint[HPChunk.Count]<optimize=false>;
        } HardPoints<bgcolor=0xd0f0f0,comment="These are hardpoints where other models can be attached to this one">;        
    }

    if (CollisionChunk.Offset)
    {
        FSeek(CollisionChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            COLLISIONOBJ Collisions[CollisionChunk.Count]<optimize=false>;
        } CollisionObjects<bgcolor=0xf0e0f0,comment="Seems to be collision mesh data">;        
    }

    if (LookNameChunk.Offset)
    {
        FSeek(LookNameChunk.Offset+16);
        struct 
        {
            NAME Name[LookCount]<optimize=false>;
        } LookNames<bgcolor=0xf0a0a0,comment="Look Names">;                
    }


} HEADER<bgcolor=0xf0f000>;

Re: Diablo III .app

Posted: Tue Sep 13, 2011 9:48 pm
by BoyC
This post is reserved for images of the best current results.

Image

Re: Diablo III .app

Posted: Tue Sep 13, 2011 10:15 pm
by Corbo
You're amazing!
I have no programming knowledge but I will help you in anyway I can, testing, ideas and such.

So far I've tested a few of the characters and they all seem to break, perhaps cause they are rigged? Static models seem to work out the best.
The leah model exports almost perfectly except for some normal issues.

Re: Diablo III .app

Posted: Tue Sep 13, 2011 11:16 pm
by BoyC
Well the characters don't actually break. I think the wizard_female.app and the rest of them are actually only the models prepared for the login screen with complete sets of armor. There are several meshes in each file and they are merged together with this method. Once we have all the pieces in place I'll do an exporter to a format that supports multiple models, that should fix this issue.
EDIT:
Same thing happens if you load critters for example - if you check out the wireframe, you can actually see the bone structure inside the animal ;)

Re: Diablo III .app

Posted: Thu Sep 15, 2011 9:39 am
by npd2006
//--------------------------------------
//--- 010 Editor v3.2.1 Binary Template
//
// File: Diablo 3 appearance file template
// Author: BoyC
// Revision: v0.37
// Purpose: Analyzing 3D data in Diablo 3
//--------------------------------------
With the old version, I can extract the output to obj files, but with your current version (v0.37), I cannot. Is it a test version ??

Re: Diablo III .app

Posted: Thu Sep 15, 2011 10:10 am
by BoyC
Oh sorry the output stuff has been commented out for speedy testing. I've fixed it now but there won't be any difference in the output yet - these are progress updates on mapping the format.

Re: Diablo III .app

Posted: Thu Sep 15, 2011 2:42 pm
by litaotao
Can anyone put a tool for extract obj? :)

Re: Diablo III .app

Posted: Fri Sep 16, 2011 1:20 pm
by afrokid
Edit: Nevermind, was using the wrong files.

Re: Diablo III .app

Posted: Fri Sep 16, 2011 5:08 pm
by MrRawr
How goes your progress in this department man?

I'm a little stuck over in the .tex / .gam department so I thought I would poke around here :P

Re: Diablo III .app

Posted: Sat Sep 17, 2011 5:59 pm
by npd2006
Your script worked very well BoyC. Most of mesh are extracted successfully. But when I imported it to Maya it still some trouble:
1. Mesh UV need to be flip Vertical.
2. When I extract the character, they are multiple mesh are in the single object that I was really hard to arrange them.

One more, mesh extracted have problem when import to 3DS max, they look melting. Though they are saved as .obj

Re: Diablo III .app

Posted: Mon Sep 19, 2011 6:41 pm
by MrRawr
1. Mesh UV need to be flip Vertical.

I'm getting the same.... how do you flip vertical xD

Re: Diablo III .app

Posted: Mon Sep 19, 2011 7:10 pm
by BoyC
Replace the line "rv=(rv-32767)/512.0f;" with "rv=1-(rv-32767)/512.0f;"

Re: Diablo III .app

Posted: Tue Sep 20, 2011 3:03 am
by npd2006
How about the multiple mesh in one file ?

Re: Diablo III .app

Posted: Tue Sep 20, 2011 9:52 am
by BoyC
npd2006 wrote:How about the multiple mesh in one file ?
Still working on that but I'm swamped in real life stuff atm.