3D engine example by Howie

I see a lot of the same questions asked in these forums. I also know online examples don’t always give a clear picture of how to do something. Nothing like clean, well commented code to help you see how it is done. This engine only uses OpenGL as a rasterizer, everything else is in software. You did want to learn the hard way, didn’t you? Not to worry, it’s not all that hard. :stuck_out_tongue:

http://www.howiesfunware.com/3DEngineByHowie.zip

Loading models, lighting, textures and collision/reaction are just a few things it does. You can use BMP, tga, gif & jpg for your textures. The example has you running through a simple map FPS style. I wrote a program that parsers Wavefront OBJ files and makes native files the engine loads so your free to design complicated models for easy loading.

Going through the door ways is a little sticky. Need to design the door ways a little differently. For this simple example, it will do for now.

There’s a file by the name of “File description.txt” that describes each file in the zip. Have fun. :smiley:

Originally posted by howie:
[b]I see a lot of the same questions asked in these forums. I also know online examples don’t always give a clear picture of how to do something. Nothing like clean, well commented code to help you see how it is done. This engine only uses OpenGL as a rasterizer, everything else is in software. You did want to learn the hard way, didn’t you? Not to worry, it’s not all that hard. :stuck_out_tongue:

http://www.howiesfunware.com/3DEngineByHowie.zip

Loading models, lighting, textures and collision/reaction are just a few things it does. You can use BMP, tga, gif & jpg for your textures. The example has you running through a simple map FPS style. I wrote a program that parsers Wavefront OBJ files and makes native files the engine loads so your free to design complicated models for easy loading.

Going through the door ways is a little sticky. Need to design the door ways a little differently. For this simple example, it will do for now.

There’s a file by the name of “File description.txt” that describes each file in the zip. Have fun. :smiley: [/b]
Unfortunately, I use OpenGL with Cygwin. Is there any easy way to modifiy your codes such that I can use them with cygwin?

I don’t know what Cygwin is but yes, this would be very easy. The 3D library files are kept general and are not tied to anything. The file “Example.cpp” is for working with Windows and the 3d Library files. Ignore the Window handling parts and look at how the 3D library files are used (CMeshTri, CTextureLib, CLightList, CMatrix).

Specificly look at functions…
InitGLwindow()
LoadGameObjects()
GameLoop()
RenderBuffer()
ReactToCollision()
GetUserImput()
in Example.cpp

This engine is all code. No LIB’s and DLL’s are used. Spend some time going over Example.cpp, going through the code, reading the comments. Then work you way through the 3D library files the same way to get a feel for how all this is done.

Thanks a lot for the code! I wish I had it a week ago :slight_smile:

You said you’d made many members public to increase the speed but isn’t it true that a compiler converts functions like:

float getUpVector () { return m_upvector; }

into the same code as if m_upvector was a public variable? Or it depends upon the compiler?

I will steal your light class, that’s for sure :slight_smile:

Could be. I’m not sure. Good C++ design suggests all data needs to be protected and only set via class functions. Speed is everything in our field so making some variables public helps in the speed department.

Originally posted by howie:
I don’t know what Cygwin is but yes, this would be very easy. The 3D library files are kept general and are not tied to anything. The file “Example.cpp” is for working with Windows and the 3d Library files. Ignore the Window handling parts and look at how the 3D library files are used (CMeshTri, CTextureLib, CLightList, CMatrix).

cygwin is a *NIX like implement on MS Windows.
Usually, a project under Linux has a Makefile for compiling. You sources don’t have a Makefile. I don’t know to compile it. What compile options do you use?

I don’t do much with make files.

thanks for all the hard work, howie!

ypsd, maybe you can write a conversion as an exersize!

Originally posted by howie:
Could be. I’m not sure. Good C++ design suggests all data needs to be protected and only set via class functions. Speed is everything in our field so making some variables public helps in the speed department.
You could use inline functions to set and get protected variables. Then you have clean C++ code and speed.

Kilam.

thanks for all the hard work, howie!

ypsd, maybe you can write a conversion as an exersize!
Thanks! The conversion code is there. The file is “CObjParser.cpp”. Parsing a text based file format is not that hard, it just gets messy fast.

You could use inline functions to set and get protected variables.
There is overhead in calling a function, even if it is inline. The way an inline is compiled down to assembly differs from compiler to compiler and sometimes it’s handled like a regular function. The variables that I made public are usually arrays and we are only talking about a few of them.

:slight_smile: I uploaded a new zip file with some changes. All the code for the converter is there. :slight_smile:

Originally posted by howie:
There is overhead in calling a function, even if it is inline. The way an inline is compiled down to assembly differs from compiler to compiler and sometimes it’s handled like a regular function. The variables that I made public are usually arrays and we are only talking about a few of them.
It depends on your compiler settings. Only using the inline-keyword in the code won’t help.
I just made a little sample with VC++ with a class variable d which is set/get via functions and as comparison directly (variable is public). The assembler code is the same:

1:    class InlineTestC
2:    {
3:    public:
4:      InlineTestC()  { d = 0.0; }
5:      ~InlineTestC() {}
6:
7:      inline double GetDiameter() { return d; }
8:      inline void   SetDiameter(double _d) { d = _d; }
9:
10:     double d;
11:   };
12:
13:   void main(void)
14:   {
00401000   push        ebp
00401001   mov         ebp,esp
00401003   sub         esp,10h
15:     InlineTestC cl;
00401006   mov         dword ptr [cl],0
0040100D   mov         dword ptr [ebp-0Ch],0
16:     double myD;
17:
18:   // Inline:
19:     cl.SetDiameter(5.432);
00401014   mov         dword ptr [cl],353F7CEEh
0040101B   mov         dword ptr [ebp-0Ch],4015BA5Eh
20:     myD = cl.GetDiameter();
00401022   mov         eax,dword ptr [cl]
00401025   mov         dword ptr [myD],eax
00401028   mov         ecx,dword ptr [ebp-0Ch]
0040102B   mov         dword ptr [ebp-4],ecx
21:
22:   // Direct:
23:     cl.d = 5.432;
0040102E   mov         dword ptr [cl],353F7CEEh
00401035   mov         dword ptr [ebp-0Ch],4015BA5Eh
24:     myD = cl.d;
0040103C   mov         edx,dword ptr [cl]
0040103F   mov         dword ptr [myD],edx
00401042   mov         eax,dword ptr [ebp-0Ch]
00401045   mov         dword ptr [ebp-4],eax
25:   }
00401048   mov         esp,ebp
0040104A   pop         ebp
0040104B   ret

It’s even done with VC++ 6 which has a rather bad optimizer :wink:

Kilam.

I agree. :slight_smile:

For this engine, since the main goal is to show how things are done, I don’t want to hide the data too much. It’s easer to see how it works when the implemintation is not hidden.