P3D File Format - ODOLV7
Jump to navigation
Jump to search
Overall
// uint unsigned integer 32bit // word unsigned short integer 16bit struct ODOL { char Signature[4]; //"ODOL" uint Version; // 7 uint LodCount; // at least one struct Lod[LodCount] { uint VerticesCount; uint VerticesAttribs[VerticesCount]; // if VerticesCount > 255 then array is compresed by LZ algorithm. see LZ in ODOL. uint VerticesCount; // again same value struct UVset[VerticesCount]; // if VerticesCount > 127 then array is compresed by LZ algorithm. see LZ in ODOL. uint VerticesCount; // again same value struct VerticesPosition[VerticesCount]; uint VerticesCount; // again same value struct VerticesNormal[VerticesCount]; float fvalue[12]; // unknown values // containts some max/min vertices positions and so far uint TexturesCount; char Textures[...]; // zero ended 'C' strings 'd','a','t','a','\','1','.','p','a','a','\0','d','a','t','a','\','2','.','p','a','a','\0'... //read until count of founded char('\0') equil TexturesCount; uint Table1stCount; word Table1st[Table1stCount];// if Table1stCount > 511 then array is compresed by LZ algorithm. see LZ in ODOL. uint Table2ndCount; // Table2ndCount is same value like VerticesCount word Table2nd[Table2ndCount];// if Table2ndCount > 511 then array is compresed by LZ algorithm. see LZ in ODOL. //tables can by used to join vertices, each face has got 3 or 4 vertices that are seperated for each face in odol format //every vertex is owned only by 1 face //mlodvertexindex = Table1st[ Table2nd[ odolvertexindex ] ]; uint FacesCount; uint uvalue; // unknown value struct Face[FacesCount]; uint uvalue2; // unknown value char uchar[18*uvalue2]; // unknown value uint NamedSelectionCount struct NamedSelection[NamedSelectionCount] uint NamedPropetiesCount; struct NamedPropeties[NamedPropetiesCount] uint uvalue7;// unknown value struct ustruct[uvalue7]; // unknown value uint ProxiCount; struct Proxi[ProxiCount]; }; // end of lod uint ResolutionCount; // same as LODCount float Resolution[ResolutionCount]; . . . // folows some unknow data. }; // end of ODOL;
Faces
struct Face { uint Attribs; word TextureIndex; //if ((int)TextureIndex==-1) no texture; char CountOfVertices; // 3 or 4 word VerticesIndex[CountOfVertices]; //! size of array is not constant. };
NamedSelection
struct NamedSelection { char name[...]; // zero ended string uint VerticesSelectedCount; word VerticesSelected[VerticesSelectedCount];// if VerticesSelectedCount > 511 then array is compresed by LZ algorithm. see LZ in ODOL. uint uvalue3; // unknown value word uarray[uvalue3];// unknown value uint uvalue4; // unknown value uint uarray[uvalue4];// unknown value // if VerticesSelectedCount > 255 then array is compresed by LZ algorithm. see LZ in ODOL. char uchar; // unknown value uint uvalue5; // unknown value uint uarray[uvalue5];// unknown value uint FacesSelectedCount; word FacessSelected[FacesSelectedCount]// if FacesSelectedCount > 511 then array is compresed by LZ algorithm. see LZ in ODOL. uint uvalue6; // unknown value char uarray[uvalue6];// unknown value };
VerticesPosition
struct VerticesPosition { float x,y,z; };
VerticesNormal
struct VerticesNormal { float x,y,z; };
UVset
struct UVset { float U,V; };
Proxi
struct Proxi { char Name[...] // zero ended string struct ustruct {...};// size same as char[56]; // unknown value };
ustruct
struct ustruct // unknown value { uint uvalue8;// unknown value uint uvalue9;// unknown value char uarray[12*uvalue9];// unknown value :-( i know nothing about it };
NamedPropeties
struct NamedPropeties { char Name[...]; char Value[...]; // 'n','o','s','h','a','d','o','w','\0','1','\0'... };
LZ in ODOL
Lempel-Ziv compression
pascal code
function LZBlockRead(var F:file; var outdata:array of byte;szout:integer):byte; var k, r, pr, pi,po,i,j:integer; flags:word; buf:array[0..$100e] of byte; c:byte; crc:integer; begin po:=0; pi:=0; flags:=0; r:=0; for k := 0 to $100F-1 do buf[k] := $20; while (po < szout) do begin flags:= flags shr 1; if ((flags and $100)= 0) then begin BlockRead(F,c,1); // direct reading from file inc(pi); flags := c or $ff00; end; if (flags and 1)=1 then begin if (po >= szout)then break; BlockRead(F,c,1); // direct reading from file inc(pi); outdata[po] := c; inc(po); buf[r] := c; inc(r); r :=r and $fff; end else begin i:=0; BlockRead(F,i,1); // direct reading from file inc(pi); j:=0; BlockRead(F,j,1); // direct reading from file inc(pi); i :=i or ((j and $f0) shl 4); j := (j and $0f) + 2; pr := r; for k := 0 to j do begin c := buf[(pr - i + k) and $fff]; if (po >= szout) then break; outdata[po]:= c; inc(po); buf[r]:= c; inc(r); r :=r and $fff; end; end; end; BlockRead(F,crc,4); // unknow 4bytes data on end of record , I suppose that it is some like CRC or MD5 checksum . result:= pi; end;
C code
int Decode(unsigned char *in,unsigned char *out,int szin,int szout) { szin = szin > 0? szin: 0x7fffffff; int i, j, k, r = 0, pr, pi = 0,po = 0; unsigned int flags = 0; unsigned char buf[0x100F], c; for (i = 0; i < 0x100F; buf[i] = 0x20, i++); while (pi < szin && po < szout) { if (((flags >>= 1) & 256) == 0) { if(pi >= szin)break; c = in[pi++]; flags = c | 0xff00; } if (flags & 1) { if(pi >= szin || po >= szout)break; c = in[pi++]; out[po++] = c; buf[r++] = c; r &= 0xfff; } else { if(pi + 1 >= szin)break; i = in[pi++]; j = in[pi++]; i |= (j & 0xf0) << 4; j = (j & 0x0f) + 2; pr = r; for (k = 0; k <= j; k++) { c = buf[(pr - i + k) & 0xfff]; if(po >= szout)break; out[po++] = c; buf[r++] = c; r &= 0xfff; } } } return pi; }