This is a.. not even read-through thing. Very none-polished. Just so you know ;] Things to add: actual code for the structures, and maby a few functions?

To be able to use this info you need to know how to code, need to know something about BSP-trees or similar. You need to know how portals work. And some sort of 3D API. OpenGL for example ;]

I'll try to outline what I have figured out about the Doom3 fileformats. When a level for Doom3 is made, the .map file is the one you edit with the level-editor, and when you are done you compile this into a .proc and .cm file.. maby the .aas?? files as well? The .proc file holds the geometry of the level. Unlike Quake3 Doom3 doesn't have bezier-curves etc. There exists curved surfaces in the .map file but when it gets compiled that data is evaluated, and curved surfaces are looks even better than in Quake3 due to normalmapping. So, .proc contains geometry and .cm contains the collision model. The .map is still used, but just as in Quake3 it's only used to get info about object positions, starting position etc.
The only ones I have looked at yet are the .proc and the .map, and the .map works as in Quake3 so, I will cover the .proc file.

The .proc file starts out with a name.

Then alot of model entries:

model { /* name = */ "func_static_5651" /* numSurfaces = */ 2

/* surface 0 */ { "textures/base_wall/lfwall2" /* numVerts = */ 8 /* numIndexes = */ 12
( -6.0625 68 6.0625 0.5 1 -0.7893519998 0 -0.6139409542 ) ( 3.84375 -68 -6.65625 1 0 -0.7893519998 0 -0.6139409542 ) ( 3.84375 68 -6.65625 1 1 -0.7893519998 0 -0.6139409542 ) 
( -6.0625 -68 6.0625 0.5 0 -0.7893519998 0 -0.6139409542 ) ( -6.0625 -68 6.0625 0.4999999702 0 0.7071056366 0 0.7071079612 ) ( 5.25 68 -5.25 1 1 0.7071056366 0 0.7071079612 ) 
( 5.25 -68 -5.25 1 0 0.7071056366 0 0.7071079612 ) ( -6.0625 68 6.0625 0.4999999702 1 0.7071056366 0 0.7071079612 ) 
0 1 2 0 3 1 4 5 6 4 7 5 
}

/* surface 1 */ { "textures/base_wall/skpanelt" /* numVerts = */ 4 /* numIndexes = */ 6
( 3.84375 68 -6.65625 0 0 0.7071163058 0 -0.7070972323 ) ( 5.25 -68 -5.25 1 1 0.7071163058 0 -0.7070972323 ) ( 5.25 68 -5.25 1 0 0.7071163058 0 -0.7070972323 ) 
( 3.84375 -68 -6.65625 0 1 0.7071163058 0 -0.7070972323 ) 
0 1 2 0 3 1 
}

}

So, we need to Model structure, and a Surface structure. The Model structure has pointers to Surfaces. The first line tells us the name of the model. func_static_5651 in this case, and how many surfaces it has. The name can be matched with the same entry in the .map file to get stuff like position, rotation etc.

The surface: it starts out with the material-name. This can be matched against a material in one of the .mtr files and then hopefully rendered correctly. After that is the number of vertices and number of indices.
Then the actual vertex data: ( x -z y u v nx -nz ny )
Like in Quake3 id-software uses z as up, I use y as up-axis so I have to convert like I write above. The nx, ny and nz is the normal for the vertex. If you also uses z for up, read them in as x, y, z. :)
That is all there is to the model part, except that: The actual area, walls, floor etc has a name that starts with _area. Start off with just rendering that part and get working. Later on you can put everything else in, but everything except the _area parts need to be translated and rotated according to the entry in the .map file.

Next: interAreaPortals bit:

interAreaPortals { /* numAreas = */ 73 /* numIAP = */ 83

/* interAreaPortal format is: numPoints positiveSideArea negativeSideArea ( point) ... */
/* iap 0 */ 4 1 3 ( 696 3528 -136 ) ( 840 3528 -136 ) ( 840 3528 136 ) ( 696 3528 136 ) 
/* iap 1 */ 4 1 4 ( 552 3832 -136 ) ( 552 3720 -136 ) ( 552 3720 136 ) ( 552 3832 136 ) 
/* iap 2 */ 4 6 0 ( 856 3336 -72 ) ( 856 3448 -72 ) ( 856 3448 136 ) ( 856 3336 136 ) 
/* iap 3 */ 4 6 3 ( 840 3448 -72 ) ( 696 3448 -72 ) ( 696 3448 136 ) ( 840 3448 136 ) 

.. good comments in the .proc files but, here goes: This is the info about the portals used to render Doom3. Doom3 doesn't have a PVS like Quake3, but portals work very well so. :)
The format: Portal #, 4 points (all have 4 points), positive and negative side. Then the actual positions of those 4 points.
The positive/negative sides are the same numbers as in _area# and later on in the BSP.. easy. :)

And next, the nodes section (aka BSP):

nodes { /* numNodes = */ 12143

/* node format is: ( planeVector ) positiveChild negativeChild */
/* a child number of 0 is an opaque, solid area */
/* negative child numbers are areas: (-1-child) */
/* node 0 */ ( 1 0 0 1024 ) 1 5854
/* node 1 */ ( 1 0 0 -1024 ) 2 60

This is the bsp-tree. Used together with the portals above gives a very good culling mechanism.
And as above, quite good comments, but here goes:
Node #, plane then children in the tree, or actual areas.
If you made a Node structure, create all from the data in the .proc file then put them into a tree-like structure it just works. If you know nothing about trees, google some. ;]

Next is the shadowModel part. I know it has to do with shadows.. ;] Has cap-info etc but I haven't started on shadows in my own Doom3 Viewer so, that part is still a mystery. If anyone has any info, please send it to me. :D

This was written to fast and, probably has a lot of errors and stuff I forgot to explain. Please feel free to complain, hopefully give some pointers as to what I can do better.. ;]