Monday 19 January 2015

Building TRViewer – part 5

If you are not an experienced programmer it can be difficult knowing where to start analysing a complex program like TRViewer.

C/C++ console programs usually start at the function named “main” so you look for that and start tracing the program from there.

Graphical User Interface (GUI) C/C++ programs also start at the “main” function but it may not be easy to find it, MFC hides it for instance and sometimes it’s called _tmain or WinMain.

Even if you do find it, it may not be much use since it usually just runs the program loop.

To analyse a GUI program like TRViewer, consider how you interact with the program.

TRViewer is an MFC program that follows the Document/View architecture which can be determined from the file names contained in the MFC folder of the solution.

If the MFC wizard is used to create a program the default names generally follow convention shown below for TRViewer.
  • TRViewer.cpp
  • TRViewerDoc.cpp
  • TRViewerView.cpp
To open a file you can click “Open” in the file menu.

In MFC programs menu items and toolbar buttons are linked to functions in the code by using a message map.

To see what function the “Open” menu item is linked to look for the message map in the *.cpp file with the same name as the program.

Message map

In line 54 of TRViewer.cpp  we see that the Open menu item (ID_FILE_OPEN) is linked to a function called CWinApp::OnFileOpen.

CWinApp is an MFC class so the function OnFileOpen is not a function written specifically for TRViewer and is not found in TRViewer’s code.

The OnAppAbout function which is executed when the About menu item is clicked would be found in TRViewer’s code since the function name is not prefixed with “CWinApp::”.

We will have to look elsewhere to see what happens when a file is opened.

In MFC when a file is opened a document object has to be created and so this is the next place the file could be processed.

The code for the document class is contained in TRViewerDoc.cpp.

There are no entries in the message map so no buttons or menu items are linked directly to the document object.

We do however find an OnOpenDocument function which I guess must be executed by MFC code when a user clicks OK in the open file dialog since it is not called anywhere in TRViewer’s code.

OnOpenDocument

This is where we can begin tracing what happens when a file is opened. We will assume we open a TR4 file.

When tracing a function you start at the top line and work your way to the bottom line.

If any line contains a function name (a call to a function) jump to (or “step into”) that function and again work from top to bottom. However, do not jump to standard C/C++ functions or MFC functions but only functions written for TRViewer.

When the end of the function is reached return to the function that called it at the next executable line.

In line 91 CDocument::OnOpenDocument is an MFC function (CDocument is an MFC class) so we won’t bother jumping to it but instead “step over” it to line 94.

Line 94 calls the function m_TRFile.boLoad so we will jump to that function.

In Visual Studio’s Editor you can jump to a function by right clicking on a function’s name and selecting “Go to Definition”. Make sure you click on the function’s name which will be the part after the last dot. In this case right click on “boLoad”.

boLoad

At line 125 the file is opened.

At line 140 the file size is obtained.

At line 158 the file is copied into memory.

At line 184 the function boParseTRLevel is called so we will step into that function.

boParseLevel

In lines 1906 to 1917 the version of the TR file is determined.

At line 1944 the vParseTR4File function is called if we opened a TR4 file.

vParseTR4File

This is where the file loaded in memory is read and the top level structures (Textures, Geometry, Sounds, NGHeader) of the TR file are extracted and uncompressed if needed.

At line 1867 the function vParseGeometry is called to extract the map, meshes, animation, texture, etc data from the uncompressed Geometry section.

vParseGeometry

The progress bar in the following is the “Loading” progress bar”.
At line 1305 the progress bar position is set to 0.

At line 1358 after the room geometry has been read the progress bar position is increased.

At line 1395 after the mesh data has been read the progress bar position is increased.

At line 1425 after the animation data has been read the progress bar position is increased.

At line 1455 after the moveable, static and sprite data has been read the progress bar position is increased.

At line 1474 after the camera and sound sources data has been read the progress bar position is increased.

At line 1512 after the box, overlaps, zone and texture data has been read the progress bar position is increased.

At line 1574 after the items, cinematic frames and demo data has been read the progress bar position is increased.

At line 1604 after the sound data has been read the progress bar position is increased (to 100%).
We come to the end of the function so return (step out) to vParseTR4File at the line after vParseGeometry was called.

Return to vParseTR4File

There is one executable line after the call to vParseGeometry and then the function ends so we return to line 1945 in boParseTRlevel.

Return to boParseTRlevel

Assuming no errors (exceptions) we skip the catch block and the next executable line is 1990.
boDontConvert is false so we jump to vConvertFromTRLevel at line 1999.


Step into vConvertFromLevel

In this function the unused textures are determined and some TR file structures are converted into TRViewer’s custom structures.

The “Converting” progress bar is used in this function to show progress and increases from 0% to 100%.

The function ends and we return to boParseTRLevel at line 2000.

Return to boParseTRLevel second time

Assuming no exceptions we skip the catch block and resume executing at  line 2009 where the dialog showing the progress bars is destroyed.

We come to the end of the function and return to OnOpenDocument, to line 94.

Return to OnOpenDocument

The class member m_boFileLoaded is set to true if the file was loaded without error.
The m_TRFile class member has been populated.

The function returns true if the file was loaded without error.

I guess that the function must return true for MFC to open a view of the document in a child window of the application.


prev | next | first

No comments:

Post a Comment