News
Sep.8.2000 - CornFlake News:
Update on the new site, go check out the beta version of the NEW and improved Cornlake Zone over at http://www.cornflakezone.com/main.php. This is brand new so I'd like to shake out the bugs asap. I appreciate you guys banging on it for a while. In particular checkout the discussion forum. You can post comments and ask questions and generally have a good time. Head on over there NOW!!!
August.24.2000 - CornFlake News:
BIG news. www.thecodevault.net ( coming soon in September ) has agreed to host the site!!! In the next few weeks we'll be moving over to the new internet address "http://www.cornflakezone.com". This will become the permanent, banner free home of the site and will only improve over time. Until I do manage to move in over there, the tutorials will be on hold for a while. Sorry but at least you can all look forward to a new and improved version of the site.
August.11.2000 - Community News:
Ok gang, sorry for the lack of updates. I've had connectivity problems and work's been crazy yada, yada yada. News is the selection tutorial has gone down a treat. If you haven't read it yet scroll on down and dig in. The next addition's going to be a doozy. It's all about building a nice Lathe. Should be ready in another few days.
Now, down to business. A lot of you have been having trouble downloading the tutorials and sample code/executables from the site. I'd like to point out that this is out of my hands and is a fault of tripod.com being unreliable. Don't forget this site is hosted free, mainly because I can't afford the monthly payments on a host.
Which brings me to my next point: I need to find a hosting vendor who can give me some free space, I'll supply the domain name or work with whatever you can give me. If you belong to an organization who could host the site ( opengl.org, nVidia.com and gamedev.net I'm talking to YOU ) or would like host the site, please contact me ( email on the right). I don't know how much longer I can go on using tripod.com. Thanks.
Other news is Don Murtad has added me as a link. Thanks Don! I encourage you to email me your page if you've added me as a link and I'll return the favour. http://members.home.com/murtad/ , check it out. You can use the button on the right as your link image.
Finally, keep your eyes peeled for some kind of demo I've started work on. It'll involve the OGLM tool and will surely knock your socks off. That's about it for now, if you have any questions as always, email me - openglmodeller@yahoo.com.
July.18.2000 - Modelling News:
I'm afraid I haven't had time to complete any decent models, the ones I've been using thus far I've thrown together, literally! I wanted to post some screen shots though of a semi-decent model so here they are: Shot 1,
Shot 2,
Shot 3. These are shots of Sapient Corporation's logo. I wanted to create something semi-complex and this was what I picked. It was pretty simple but it did highlight a number of issues with the modeller which I need to fix in order to make it really useable. I also threw in environment mapping for the texture shot, pretty nice eh? Stay tuned.
July.13.2000 - Community news: http://shockonline.homestead.com/OpenGLGameProgramming.html
is Frag-Daddys's page and I just heard he's posted an excellent tutorial on collision
detection. Head on over there. I've posted more content to
the OGLM tutorial. All about SELECTION and a smattering of code too. This is pretty detailed and is an excellent tool to use when writing your games. Enjoy.
July.06.2000 - Quick mini-update. I had a good weekend but am
having a terrible week. Looks like I won't have time to update until next week. Work is
just too busy right now. I'll be working this entire weekend and probably into next week
too. In anycase I have made major changes to the OGLM. It now allows elements to share
vertices and hence make a single continuous mesh. It also has the guts of the animation
coded. I just need to slap an interface on the thing and I'm done. Thanks to Derrick
Dixon, Robert Zukowski and Frag Daddy among others for all the feedback/interest. Keep it
up. I'm working on a beautiful model for you all to checkout soon and with a bit of luck
it'll be animated too. Later...
June.28.2000 - Here's the deal, I've been getting up at 5:30am
and working until 8:00pm. It doesn't leave a lot of time for modelling work. Plus I'd like
to expand the site with peoples' contributions but it looks like you guys aren't
interested as I haven't had any responses. The traffic is holding pretty steady at about
70 people per day, I'm struggling with motivation at this point as I'm not getting enough
rest as it is. Oh well, enough complaining, I'll try and get the next tutorial added
shortly. I'm also struggling with the format of this page so I've made it a little wider
to make it easier to read. I've also added the screenshot on the right of "X-Box
Joe". He's my first attempt at a xbox-robot look-a-like. Ok the textures aren't the
best but the model-mesh is sound. Hope you like it. That's about it for now.
June.19.2000 - Wow, it's sure been a while since I've
posted any updates to this site. I wanted to let you guys know that the site's not dead.
I've been working steadily away on things, it's tough but no one said it would be easy. If
it were easy to create a modelling tool and hold down a job, EVERYONE would be doing it.
I've had some home improvements, visitors to entertain and a ton of work to get through so
things have been slow getting to the site. Despite all this I've made significant
head-way. In fact with the exception of tidying up the interface I would estimate that I'm
almost done coding. The OGLM now has a preview window where you can load objects before
you add them to the scene. You can add children of objects and build a true hierarchy. You
can also create objects like the Goblet in the picture within about 2 minutes of work,
literally ! This is through use of the Lathe tool I've added to OGLM. I've updated the
executable download, it now has a bunch of textures and a small readme.txt, I'll be
working on this more in the future. In addition I'll update the tutorial to tell you how
to build these cool tools like the lathe. For now you'll have to make do with the
walkthrough of how to code the Loading and Saving routines for your modellers. Stay
tuned...
April.7.2000 - Alright, it's Friday. It's been a tough week. REALLY busy
at work these days. Managed to put the following quick demo together. It's called Space
Mountain. It uses the space ship model and a small terrain which I also created with the
modeller. Read more. I've also updated the download of the
OGLM so go get it again as this update has a LOT more functionality than the first. It's
still a little buggy so be gentle. If you break it you get to keep ALL the pieces ;-).
I've gotten limited feedback on the article but what I've received has all been very good
so I'm going to keep updating it. sorry for the week without any more article but I've
been coding till all hours of the day and night. Mainly the modeller and Space Mountain.
Hope you enjoy it and as always let me know how to improve this site. A lot of people have
derived value, I'd like to see a lot more people using it.
April.3.2000 -
Wow ! Modelling is hard. I gotta make this thing a little easier to use. News is I've just
completed my second model. It's a space ship, here's a screen shot. click on the image for
a larger version. What'dya think ? Not bad for an amature. This model took about 1 hour to
make from start to finish. The longest part was the texture. I'll be working on my racing
game this week and I expect to use this guy.
Ok update, the racing game turned into space mountain which is up on the
site.Enjoy.
I've added another screen shot with a space backdrop to the page.
This is just to give you the comfort level that my article is actually going somewhere
and will work. More tomorrow.
April.1.2000 - Lots happening these days. I've just completed
my first BASIC model. It's a landscape with a few textures. It's still very basic but only
due to the limited number of hours in a day. I've uploaded a screenshot to give folks an
idea of what it's like. Next up I plan to use this to enchance my car racer. I'm going to
add on more to the article VERY soon so keep checking back. Also looks like opengl.org is going to give the site a mention. Fingers
crossed ;-) Check it out at the OGLM piece.
Mar.27.2000 - Happy day! NeHe has just added a link to this
page on his site. If you haven't you should definitely check his page out. It's been a
great help to me as it has a ton of tutorials and is all about helping the programming
community. Check it out at NeHe Productions. Thanks
NeHe !
In response I've updated the OGLM article to add more functionality
to the modeller and almost complete the number of classes that we need.
Mar.25.2000 - Today I decided due to the number of hits, to
give out the code to my Car Racer. It's EXTREMELY basic as such,
it'll give you all a good idea how to write a basic game. Basically, this is the project I
was working on when I decided to write the OGLM.
Mar.24.2000 - News Flash - Today's my birthday so
I've decided to give away something ( instant Karma ). I've just posted the source code to
an openGL screensaver. It's well commented and should give you
all a tremendous head start when writing a screen saver. All initialization is done for
you. All you have to do is add in the drawing code. Enjoy.
Mar.20.2000 - I just added "The Making of OGLM" Just for all you out there who are struggling with writing a
3d modeller. It's the hope that this will give you all some pointers. Let me know if it
helps or if I'm skimming over stuff too much. I'll be happy to post code snippets here to
help you all out.
Feb.16.2000- Alright, time to make this useful.
Last few weeks I've been kinda busy. I've been working on a bunch of stuff with OpenGL.
Predominantly the OGLM, Open GL Modeller. I started writing a nice 2-D racing game and
then quickly found I need a way of editing and creating models. Hence the modeller. I'm
also documenting the development of it which I'll clean up and post here eventually.
Oct.31.1999 - Add links to all the software so
far.
Oct.30.1999 - Finally got the site to look
semi-ok. Things are starting to materialize and hopefully I can stick with this layout for
a while. I changed the Cornflake logo from just grey to the more interesting Gold/Yellow
color. Created the background blue and black started on a navigation bar.
Oct.29.1999 - Created 'Fran-Browser', a web
browser in C++ using some Active X controls I found lying around my machine. Works
pretty easy and wasn't too hard. Must look into adding ftp support.
Oct.28.1999 - Created my first Palm Pilot PRC file
from scratch using the gnu C Compiler. Mental note = Must add a link to the pilot SDK and
the GCC web-site. Very cool.
OpenGL - Jun.22.2000
This is my editor. I'm about 60% done. It's basically being written so that I
can create some models and terrains for some games I'm working on and coordinate
animations of these models. Check out the updates above and to the tutorial below. You can
create, move, edit, rotate, add cylinders, cubes and strips. I'm in the process of adding
point manipulation, texture mapping and a bunch of other stuff. The models save to binary
which is nice. There are also a number of cool tools I've added such as Lathe, Extrude and
preview. Partial save, is semi-working right now. I'll keep you all posted.
I've tried this on a few laptops with no cards and
the framerate is pretty good. I've developed it on a 3dfx Voodoo 3000 PIII450mhz and
experienced problems with the selection algorithm I've used. As a result I've switched to
an nVidia card on my laptop and that seems to work perfect. I'm now boycotting all 3dfx
products. They suck !. Let me know if there's any problems with other cards. Anyway,
that's all for now.
The Making of OGLM
Introduction
This document is intended to describe the steps taken when building a
3Dimensional Modelling tool. Im going to attempt to write this document in an easy
to understand format. Thus you shouldnt need very much programming background to
understand it. If you have any questions regarding specific pieces of the development,
email me directly and Ill adjust/add the content to this document to help you out.
Having said that, the first draft will assume some familiarity with both OpenGL and C++
but only the basics. Youll be surprised just how easy it was to build. Im also
not releasing the source code yet until Im very confident in the demand for it. Read
on
And now a disclaimer: The views expressed here are my own, Im not in any
way an expert and hence the way I do things is not necessarily the best way to do them.
When you dont know how to do anything, this document might help you. If you are
smarter than I, you probably not learn a lot. Etc
.
Whats OGLM and Why did I build it ?
OGLM stands for OpenGL Modeller. Not very creative naming I know but what are
you going to do? If you have any suggestions for alternative names, let me know. Ill
be happy to consider them. In any case, the reasons Ive begun to write this ( note I
say begun meaning Im not even close to done yet ) are as follows:
- To give me a way to create simple OpenGL objects which I can add to the games
Im writing.
- Develop a better understanding of OpenGL objects creation and the pitfalls
associated with them. By this I mean triangle meshes, texture mapping them, etc.
- Ultimately Id like to add animation to the modeller and understand how to
define motion paths and inverse kinematic rotations etc,
- You should also know that Ive (with my friend Killian Breslin ) already
written a similar type editor, complete with texture mapping, motion recording etc. for
Solaris. This editor didnt use OpenGL and we had to write all the graphics functions
ourselves. It also wasnt as user friendly as wed have liked but it did allow
us to create and animate three characters for our game, The Dungeon of Death.
Where Do We Start?
We start with the tools of the trade. Im going to discuss here the tools I
use to build the editor. As I only work on this type of programming in my spare time I
have very few resources at my disposal. I dont necessarily have very much money to
spend on compilers etc. however I do highly recommend splashing out on a copy of Visual
C++ though. When you want to code something properly, its definitely worth the
investment.
Graphics Card: I use a 3Dfx Voodoo3 3000. Ive had some trouble getting the
most up to date drivers ( from 3Dfx ) to work and as a result Ive rolled back my
drivers to the ones which came with my machine. It a good thing I still had the recovery
CD that came with my machine or Id be hosed. 3Dfx have given me no guidance as to
what drivers support what versions of OpenGL and to be honest Ive been very
frustrated with them as a result. That said, their card is excellent even if it does only
have 16mb of Video Ram.
Machine: I code on a Gateway Essential 450Mhz with a PIII. Its not a bad
machine and I feel like anything more powerful would be a little bit extravagant (read
waste of money). I also have a 17" Monitor which is essential, youll go blind
with anything smaller.
Lets Start slinging some Code.
Here comes the easy part, building the application shell. Just open VC++ and go
create a new project. I originally chose a simple Win32 Application ( non-console ). This
gave me a simple application and I started coding. Pretty soon I was ready to add things
like a toolbar and a status bar so I used things like CreateStatusWindow(). This
didnt do me any good though as it turns out you have to resize these yourself. At
that point I made a conscious descision to use the MFC. This gave me these type things by
default along with a lot of standard functionality built in. At this point if memory
serves, you should have the following generated for you:
- An application class
- A Main Frame Class This holds the document in our case the
application should have a Single Document Interface or SDI and hence we only have on
document instance.
- A Document Class This houses the document view.
- A View Class This is where well add in our message handlers etc.
Well also invoke our OpenGL calls from here.
- ToolBar resource
- Perhaps a dialogue resource which links into a ReBar? Well see
Try compiling and running at this point ( hit Ctrl-F5 ). You should have a nice
little application which pretty much does nothing but run and quit. I left printing
support in and added support for 5 as opposed to 4 files in the most recent list. This was
just my personal preference. Of course bear in mind that printing will NOT work until you
code it. This should have taken less time to do then it took to actually read this page !
Oh well, hopefully Ill improve my writing style as this doc goes on.
The Best Laid Plans
Eventually wed like to have an application which displays four views of
any scene. Youve all seen CAD applications like this in magazines etc. The layout
will look just like this:
Elevation |
Side Elevation |
Plan |
3Dview |
Ok this is a basic representation but as Ive already said,
Im pretty lazy.
Wed also like to be able to click in each of the quadrants and move things
around, add items, stretch objects, move vertices, rotate things, zoom in and out, etc.
The question arises, how are we going to layout our code so that it doesnt
become a big mess and a nightmare to maintain. This is the point in the show where I like
to turn off the computer, go make a cup of tea, eat a cream bun and read a book. After
letting the thought simmer in my head for a few hours, it all becomes clear. Id
encourage you to do the same.
Since theres going to be four independent views and each view is basically
the same thing just seen from a different angle, we need to create a single class which
encapsulates this functionality. Then well simply create four instance of the same
class, set a few parameters in each to make them work slightly differently and draw each
one in turn. Lets call this class our GLScene().
Act 1 Scene 1 paragraph 3
Lets start building our GLScene Class. Right click on the project window
and select Create New Class. If memory serves you should change the class to Generic Class
and type in the name GLScene. Here where visual C is so handy. It creates CPP and
Header files for you and adds them to the project. Now were ready to create some
member functions. At this point I figure Id like to enforce a standard. All OpenGL
related functions Im going to prefix with a "GL". Dont ask why.
Right click on the newly created class and select add member functions. We
should create a couple of functions right away:
GLInit() Initializes some member variables. Not sure what these are at
this point but I know were going to need them. Were also going to need to
intialize some OpenGL type factors and this is where Im forecasting Ill do
that.
GLDraw Every scene should know how to draw itself so I know Im
going to need this. For now Ill just make a call to draw a torus here. Were
going to use the auxilary library for that.auxTorus(10,80); This is going to be replaced
later with something to draw the objects in our scene.
GLResize Heres another function Ill add to the Scene class.
This function is called when the main frame is resized. It recalculates the boundaries of
the scene so that the contents of the scene are kept in proportion with the master frame.
I know Ill need this since other OpenGL programs have given general protection fault
errors if I dont resize the scene.
Im also going to add a few member variables. Im not a big stickler
on the public and private issues here so for now Ill make them all public and decide
later. Im also going to enforce another naming convention for all class member
variables. Im going to prefix them with a "m_". No reason, I just like
them that way.
M_x1,m_x2,m_y1,m_y2 - These are going to help me figure out the bounds of the
scene so that I can setup my viewport accordingly.
Now another question: Where are we going to make this call to draw each scene
from? OpenGL is quickly becoming supported on a number of different platforms, e.g. Linux,
Windows, Solaris, Macintosh etc. Naturally wed like to maximize the time we spend
writing this modeller and make it as portable as possible. One way to do this is to add a
layer of abstraction between the silly OS and the modeller code itself. With this in mind
were going to create another class. This is going to be called the GLManager.
Its going to manage the four scenes and also house all messages mapping code. What
do I mean by that ? Well every operating system works in pretty much the same way, the
hardware and the users interact with the system through messages. When I click the mouse
on the screen I create a message in the operating system which is then mapped to the
current application. Depending on where I click and which button I use, the application
can then choose to act on this message or not.
Normally a windows application handles messages in either the Document class or
the Main Frame. In our case were going to use the view class. Im going to add
a member variable to the View class which is an instantiation of the GLManager class. From
here well pass off all the clicking messages etc to the GLManager. That way, if I
ever want to port the code to a different platform, I can simply replace this single piece
and recompile. The core modeling functionality wont have to change.
Lets start building my GLManager class. Create a new class as before and
add the following member variables.
M_SideView = This is a class of type GLScene. Its going to hold the side
view of whatever it is Im modelling. I create three more member variables of this
type, one the plan, elevation and 3Dview accordingly.
Preparing the Window
Just like we added an Init function to the scene class, we should do the same
for the manager. This is where well perform the SetPixelFormat functionality and get
the window ready for drawing using OpenGL. Were also going to need some hDC and hRC
variables here. These will help us when we need to set the device context etc.
Lets go ahead and create the SetPixelFormat function right now. We add
this to the GLManager class. It takes a single parameter which we pass in from the Cview
class. The parameter is the hWnd handle which well use to create the Device and
Rendering contexts from.
Repainting the Screen
Lets also add a Draw function for the Manager. This is how the Document
View and the Manager are going to interact. Lets hook them in right now:
Normally a document repaints when the application receives the WM_PAINT window.
This only gets generated when we interact with the window. For example when we resize the
window or drag another window over it. We need a way to make this happen without user
interaction. For that well use a Timer. The Timer ticks off every 10th of a second.
This is just enough times per second to fool the eye into thinking its smooth
animation.
I do this by creating a Timer in the OnCreate() function of the view class. This
is done like so
SetTimer(101,10,NULL);
This is going to trigger a WM_TIMER message every 10 milliseconds. This is
useful but only if we implement the WM_TIMER message handler.
A Message handler is easy to create. Simply right click on the class ( in this
case our view class ) and select "Add Windows Message handler". From the
leftmost window which pops up select the message ( in this case WM_TIMER ). Hit "Add
and Edit". Youll be brought to the implementation of the message handler. VC++
handles creation of all the prototypes and declarations etc in the class.
Now we need to tell the window to send a WM_PAINT message. Easily done. In the
OnTimer message handler we just created insert the following.
// Invalid this view.
Invalidate(FALSE);
Now add this to the manager in the Draw function
// Make the rendering context current
wglMakeCurrent(m_hDC,m_hRC);
// Only clear the buffer once.
// This clears ALL screen buffers.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GLScenePlan.Draw();
etc.....
You'll also want to add the following to the View's OnDraw function
// Call our external OpenGL code
m_GLManager.GLDraw();
// Swap our scene to the front
m_GLManager.GLSwapBuffers();
Note how I slipped in the GLSwapBuffers call, that's just a simple 1 line
function that swaps the buffers using SwapBuffers(m_hDC);
At this point it occurs to me that Id like an ortho graphic projection in
the side, plan and elevation view and a perspective projection in the 3Dview. This leads
me to add a new member function to the GLScene class.
GLSetProjection(). This function sets the projection mode for the scene.
Im going to know which projection mode is used by maintaining a flag on the scene (
add another member variable: m_sceneprojection).
At this point you should have a good grasp of what Im trying to achieve
here. Each of the four scenes acts as an independent window onto our set of objects.
Im going to perform operations which effect ALL scenes in the GLManager. Things
which effect a single scene will be managed at the scene class. Weve already
implemented an example of this idea with the GLScenes Draw function.
Lets try compiling and see what happens now. Its a good idea to
compile every opportunity you get. This keeps you sane. I also like to hit the Save All
button before I execute my code. This pays dividends when your program crashes the
compiler and you lose your changes. So getting back, hit Ctrl-F5 at this point and you
should get a window, which repaints itself. If youve implemented the torus
functionality in the scene class you should also see these.
Now that we have four views of a scene, its time to make them display
slightly differently. To this end I now add three new variables to the scene class. These
rotate in the three different axes. Im going to call these m_RotateX, m_RotateY,
m_RotateZ.
These are going to be set individually to rotate each scene so that we see the
correct side of the objects. So in the manager, create a function glInit() and put some
code in there to set every scenes rotations individually. Try something like
this
// Reset The Current Viewport And Perspective Transformation
glViewport(m_x1, m_y1, m_width, m_height);
// Reset the current projection matrix
GLSetProjection();
// Reset The Model Matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Time to Draw something
Ok, heres where the rubber meets the road. Every scene has an origin.
Were going to draw a few colored lines at the origin to represent the axes.
Were going to add a few functions and some code here so try and stay with me. First
lets add a member function to the Scene class. Its going to just draw the axes so a
logical name would be GLDrawAxes();
In it well put just openGL code to draw the axes. Heres that code:
// We want the axes lines a little thicker
glLineWidth(3.0);
glBegin(GL_LINES);
glColor3f(1,0,0);
glVertex3f(0,0,0 );
glVertex3f(10,0,0);
glColor3f(0,1,0);
glVertex3f(0,0,0 );
glVertex3f(0,10,0);
glColor3f(0,0,1);
glVertex3f(0,0,0 );
glVertex3f(0,0,10);
glEnd();
// Set the line width back to the norm
glLineWidth(1.0);
In the Scene Draw function well add this to draw the axes.
// Draw the Axis in the scene
DrawAxes();
Try running now and you should get a nice editor with 4 views, axes in
each one.
I like it but what does it do?
Right now our program does nothing. Up until this point we've been focusing on
setting stuff up. We've covered the window, the device context, the rendering context and
repainting. We've even cleared the screen and thrown in an axis. We still haven't touched
on the modeling aspect of this project. Well then it sounds to me like we need to get
started.
In order to model stuff, I decided to go out, get a cigarette and a nice hot cup of tea.
Then I sat on my doorstep for a while and I stared at the world. I found myself watching
the world go by and wondering: what's the basic unit of all this stuff? How can I capture
the walker, the jogger, the jogger's dog, the trees, the cars, the ground the drive on and
everything else. This was the type of stuff I want to be able to model.
I came up with the notion of the element.
There are really two different types of things to model: Living and dead. This translates
to moving and non-moving in the simplest sense. From this I found that they're both just
composed of the same thing, for the purpose of this discussion we'll call that thing an
element.
An element is made up of a simple mesh. Imagine I took my hand and put it in a rubber
glove. That's a mesh. A mesh is basically analogous to a fisherman's net. The holes
represent polygons in our scene. The lines in the net represent the edges of those
polygons. The intersections of the lines represent the points in the mesh.
An element knows how to do things. It knows how to draw itself. It should know how to
rotate and translate itself. It should also know how to add a triangle to itself and
delete one from itself. It should have a good idea of how many points, triangles etc are
contained in it and it should know how to manage them. It might also know what color it is
and whether or not it's texture mapped. That's a lot for a silly little thing called an
element. Guess who's going to have to teach it these things, that's right you and I. Oh
and before I forget an element might contain other elements. Take for example your upper
arm. It rotates around your shoulder. When it does so, it takes your lower arm with it. In
this sense, the lower arm is a child of the upper arm. Like-wise, fingers on your hand are
a child of the lower arm. That would make them grandchildren of the upper arm! Confused
yet? Don't worry we'll get to all that later.
Let's get building
Let's create our element class. As before right click on the project and select
new class, generic and type in a good class name. I'm going to trust you to pick a good
name so don't let me down.
An element needs member variables. The most crucial thing in an element are the vertices.
We could create a member variable for the vertices but we don't have a class of type
vertex! We should create one
you know the drill. Let's call it GLPoint. We'll give it
an x,y and z member variable all of type float. That should do it.
We'll also need a triangle class. This is so that we can draw each triangle and re-use
vertices across triangles. Just create another class with 3 member variables of type
integer. Why integer and not GLPoint? Simple, the triangle doesn't store the point
information, the element does. The triangle stores 3 integers which are each indexes into
the element point array. Make sense? Good.
Now back to the element. Let's create an array of vertices (I know, I know we should
create them as needed using a linked list but I can't deal with that right now).
In any case I'm throwing in
GLTriangle m_triangles[100];
GLPoint m_vertices[100];
Int m_num_vertices;
Int m_num_triangles;
Into the element class definition. Let's also throw in an integer called m_num_vertices.
This will keep track of how many vertices are in our scene. Make sure to initialize this
variable in the class constructor to 0. Otherwise you never know what might happen.
Remember I said that an element knows how to draw itself ? Well it doesn't but it will.
Let's write that code now. Add a member function to GLElement called Draw(). It should
bring you to that function to implement it. Can you guess what we're going to do in there?
Write some code that loops through all the triangles in the scene and draws a GL_TRIANGLE
for each one. The best way to do this is something like
GlBegin(GL_TRIANGLES);
Loop in here
GlEnd();
Using GL_TRIANGLES beats GL_TRIANGLE as there's less glBegin and glEnd calls. Remember
that.
This is all fine but we need to call this function. Right now the scene just draws the
axes. We should call this function from the scene's Draw function. Guess what ? The scene
can't call a function on an object that it doesn't know about. Ok this presents a problem.
I could declare the elements on the scene class but then we'd maintain 4 different
versions of the same element. We can't do that. It'd be better if we had the manager act
like a manager and manage the objects. Here's how we'll do that.
Create a new class, which is called GLObject. I'm setting this up so that the GLObject has
many elements. A scene has one reference to the GLObject and the manager actually OWNS the
GLObject. That way there's only one set of data, used by all 4 viewports/scenes and
maintained ( saved, loaded etc.) by the manager. To complete this trick, add a member
variable to the GLObject which is an array of elements. You should add an array which is
the elements and an integer which is the number of elements in the GLobject . This
m_num_elements integer should be initialized to zero in the constructor. Ok now add a
member variable to the GLManager of type GLObject. Finally, add a member variable to the
scene which is a GLObject * note that's a pointer to a GLObject, not an actual GLObject.
So now the scenes have a pointer to the object but that's all. We'll need to set that
pointer to point to the GLManager's actual GLObject. I did this in the GLInit function of
the manager. Remember when we put code in there to call glInit on the scenes? Well now
we'll pass in the GLObject pointer to that function. That code looks like this
// Declaration
Void GLScene::GLInit(GLObject *object);
// Now the function call in the manager: pass in the address of the object member variable
m_planview.GLInit( &m_object );
Allright, now the scenes know about the Object, so they can call the object to draw
itself. Add this code into the Draw function of the scene. Looks a little like this
M_object->GLDraw();
Note you have to use the -> thing as it's a pointer to a GLObject, not an actual
GLObject. Inside the GLObject GLDraw() function , we'll loop from 0 to m_num_elements and
call the Draw function on each one. I'm sure you can handle that code.
Come With Me If You Want To Compile
So at this point we can compile the code but if you try and run it, it'll either
bomb or draw nothing at all. Why's that? Well because we're drawing 0 elements and each
element has 0 vertices and 0 triangles! Man this is tough. We've built a lot and I'm
having trouble keeping it straight in my head. Pretty soon we're going to level off the
creation of new classes and from there we'll just add functionality to the class structure
that we have. Let's regroup for a moment and list off the classes you should have at this
point.
- An application class
- A Main Frame Class This holds the document in our case the application
should have a Single Document Interface or SDI and hence we only have on document
instance.
- A Document Class This houses the document view.
- A View Class This is where well add in our message handlers etc. Well
also invoke our OpenGL calls from here.
- ToolBar resource
- Perhaps a dialogue resource etc.
This was all generated by VC++, now we'll list what YOU've created.
- A Manager class - holds the Object and the Scenes
- An Element Class - Holds the Vertices and the Triangles
- A 3D Point class - Holds the points
- A Scene - Holds a reference to the Object so that it can use the functions on it.
- An Object class - Holds all the elements
- A Triangle class - Holds 3 integers which are the indexes into the element Vertex array.
You should definitely compile and fix any bugs at this point. There shouldn't be any but
you never know.
All this and nothing to show for it
That's all going to change. We have everything we need to display our models but
we're missing one vital thing. Our model factory! Yes that's right, we're going to create
a class now that'll create elements of different shapes and sizes so that we can insert
them into our scene.
Create a class and call it GLElementGenerator. This is going to have a few functions and
no member variables. The first function we'll build will take a single paramater, a
pointer to an element. Looks like this
Void GLElementGenerator::CreateCube(GLElement *element)
In this function we'll add code to build a simple cube onto the element pointer. This will
be called from the GLManager whenever someone clicks on the right button. Let's create the
button now. Using the pane on the left, change to the resources view. Then click on
ToolBars. Add a button to the toolbar by drawing something in the gray toolbar button on
the right. This creates a new button. Hit Alt-Enter to bring up the buttons' properties.
You'll see a random name generated by VC++ in the ID of the button. Type something
meaningful in this. Since we're going to use this button to create a cube, call the
button, ID_ADD_CUBE or something like that.
Next go back to the Class view and right click on the View class, select Add Windows
Message Handler. A window will pop up and you should select the ID from the list box in
the MIDDLE of the window, not the one on the left ( it won't show up here anyway ). Select
ID_ADD_CUBE and hit the Add and Edit button.
This brings you to the code with a TODO statement saying you should add your own code
here. Let's do it. Type something like m_GLManager.GLAddCube(); We haven't implemented
this function yet so let's do that now. Right click on the manager class and select add
member function, type GLAddCube in the box and hit ok. Again, this brings us to a TODO
statement.
Right click again and add a member variable to GLManager which of type GLElementGenerator
called m_generator. This is how the manager will use the generator. Next go back to the
Addcube function in the Manager and call the CreateCube function from there. It'll look
something like this:
M_generator.CreateCube( m_object.m_elements[m_num_elements] );
M_object.m_num_elements ++;
Note that after the call we increment the number of elements in the Object. Actually I
moved this to a small function on the Object class that does the same thing. That way, the
thing is encapsulated a little more. It means you have to move the generator to the Object
class also. It's up to you
Now time to implement CreateCube(). Go to the create cube function and add something like
the following.
// Set the number of vertices and triangles
Element->m_num_vertices = 3;
Element->m_num_triangles = 1;
// Setup the element vertices
Element->m_vertices[0].x = 0;
Element->m_vertices[0].y = 0;
Element->m_vertices[0].z = 0;
Element->m_vertices[1].x = 20;
Element->m_vertices[1].y = 20;
Element->m_vertices[1].z = 20;
Element->m_vertices[2].x = 10;
Element->m_vertices[2].y = 10;
Element->m_vertices[2].z = 10;
// Set the triangles vertex indeces
Element->m_triangles[0].a = 0;
Element->m_triangles[0].b = 0;
Element->m_triangles[0].c = 0;
Compile and run this. You can try hitting the toolbar button now and you should see a nice
triangle appear in the scene. In ALL 4 scenes actually. You can go back to CreateCube to
make it REALLY create a cube. I'm not going to bore you with that explanation, unless you
ask me to.
A Good Days' Work
Phew that was a lot of work. At this point the object model ( pardon the pun )
is pretty solid. It might not be the best way to organize things but hey, I said at the
start I'm no expert. I leave it up to your discretion.
Next time we'll add in loading and saving and the creation of some more meaningful
objects. We still can't select any points or faces. That's a bummer. We also can't move
anything around. I'm going to cover these soon but let's walk before we run
I've
received good feedback so far but I need more suggestions as to how to improve the site. LET ME KNOW.
Add a Mesh
Alright, at this point I'm going to allow you all a little extra credit. We have
the element generator class created and it should allow you to create some useful
functions. The first one that pops into my head is a function to create a polygon mesh of
triangles. We have the code written to draw the elements ( cycles through all the
element's triangles and draws each one in turn ), so it should be easy for you all to
create some code to build a simple mesh. I wanted to make mine as useful as possible so I
had it take 2 arguments, width and height which become the width and height of my polygon
mesh. Here's the code in case you're too lazy to write it yourself. You'll notice I have
texture coordinates generated in here too. More on this later. You'll probably get some
compiler errors when you compile this but just add variables as you need them and take
your best guess as to what their types are. Mostly integers, there shouldn't be to much
that you can't figure out yourself.
// This function adds a simple mesh
void GLElementGenerator::AddMesh(GLElementMesh *element, int width, int height)
{
int i = 0;
int j = 0;
int k = 0;
// Define the element
element->m_num_vertices = width * height;
// Multiply the total triangles by two as it's a square
element->m_num_triangles = ((width-1) * (height-1) ) * 2;
// This element has a center of gravity ( anchor )
// rooted at the origin ( until it's moved )
element->m_anchor.x = 0;
element->m_anchor.y = 0;
element->m_anchor.z = 0;
// Setup the vertices
for (i=0 ; i < height ; i++ ) {
for (j=0 ; j < width ; j++ ) {
element->m_vertices[(i * width)+j].x = j * 10;
element->m_vertices[(i * width)+j].y = 0 ;
element->m_vertices[(i * width)+j].z = i * 10;
}
}
// Setup the triangles in the mesh
for ( i = 0 ; i < height-1 ; i++ ) {
for ( j = 0 ; j < width-1 ; j++ ) {
element->m_triangles[k ].m_selected = FALSE;
// One side of the
square
// a,b and c are each
vertices indeces
element->m_triangles[k ].a = i * width + j ;
element->m_triangles[k ].b = i * width + j + 1 ;
element->m_triangles[k ].c = i * width + j + width ;
element->m_triangles[k ].m_red = 1 ;
element->m_triangles[k ].m_blue = 1 ;
element->m_triangles[k ].m_green = 1 ;
// Now the texture
coordinates
element->m_triangles[k ].m_tex_coord_a.x = (float) i / (height-1);
element->m_triangles[k ].m_tex_coord_a.y = (float) j / (width-1);
element->m_triangles[k ].m_tex_coord_b.x = (float) i / (height-1);
element->m_triangles[k ].m_tex_coord_b.y = (float) (j + 1) / (width-1);
element->m_triangles[k ].m_tex_coord_c.x = (float) (i + 1) / (height-1);
element->m_triangles[k ].m_tex_coord_c.y = (float) j / (width-1);
k ++;
// The other side of
the square
element->m_triangles[k ].a = i * width + j + width ;
element->m_triangles[k ].b = i * width + j + 1 ;
element->m_triangles[k ].c = i * width + j + width + 1;
element->m_triangles[k ].m_red = 1 ;
element->m_triangles[k ].m_blue = 1 ;
element->m_triangles[k ].m_green = 1 ;
// Now the texture
coordinates
element->m_triangles[k ].m_tex_coord_a.x = (float) (i + 1) / (height-1);
element->m_triangles[k ].m_tex_coord_a.y = (float) j / (width-1);
element->m_triangles[k ].m_tex_coord_b.x = (float) i / (height-1) ;
element->m_triangles[k ].m_tex_coord_b.y = (float) (j + 1 )/ (width-1);
element->m_triangles[k ].m_tex_coord_c.x = (float) (i + 1 ) / (height-1) ;
element->m_triangles[k ].m_tex_coord_c.y = (float) (j + 1 ) / (width-1) ;
k ++;
}
}
}
You'll also notice I have assigned color variables to each triangle. These will
be used later on when we go to draw the triangles. The other essential item I've added to
each element is the anchor point. It's of type Point3D and is used to rotate the object
around. By this point I trust you all to be able to create functions on a class and member
variables so I'm not going to explain how to do that any more. Next up is Loading and
Saving, hint we're using the CArchive class provided by MFC.
Should I Save or Should I Load Now?
At this point we have a number of classes which hold data. The data varies from
triangle vertex data to point data to colors to a whole bunch of other stuff. This is fine
but not much use if we can't save the information. This is pretty simple to do and while
we're at it lets' write some code to load the information too. The way we do this is to
make use of the MFC classes.
On the view class, create an implementation of the Windows message "SERIALIZE".
This is the way MFC saves and loads information. You'll find the function is created with
an argument of "CArchive" type. This is the class to which we write the
information.
The problem is that since the MFC calls the same function for both saving or loading, how
do we know whether to save of load from the CArchive ?
Answer: The MFC puts the class into a loading or storing state automatically. You can find
out what the state is by calling IsStoring() method on the archive. This returns TRUE if
it's saving and FALSE if it's loading. Check out the following code snippet:
if (ar.IsStoring())
{
// storing code
m_GLManager.Save(ar);
}
else
{ // loading code
m_GLManager.Load(ar);
}
Notice how I defer to the manager to do the saving. The manager passes the buck also and
defers to the objects. Each object knows how to save itself. That's the general idea. So
create a Save and Load function on each and pass in the archive object.
Then to actually save something just use the << and >> operators. The <<
writes data TO the archive ( saves it ) and the >> takes data FROM the archive (
loads it ). Check out this code snippet from my element mesh class:
void GLElementMesh::GLSave(CArchive &ar)
{
int i;
// Write in the number of vertices
ar << m_num_vertices;
// Write out the vertices
for (i=0 ; i <m_num_vertices ; i++) {
m_vertices[i].Save(ar);
}
m_anchor.Save(ar);
// Write out the color of the element
ar << m_red;
ar << m_green ;
ar << m_blue ;
// Write out the number of strips
ar << m_num_triangles;
// Write out the triangles
for (i=0 ; i <m_num_triangles ; i++) {
m_triangles[i].Save(ar);
}
// Write out the texture
ar << m_texture_idx;
// Write out the children
ar << m_num_children ;
}
This is for saving. Notice how everything is in a certain order? In order to load the
data, I need to do things in the exact same order, the only thing that changes is the
<< operator to the >> operator. Make sure you do things in the correct
sequence otherwise you'll load the right data into the wrong spot.
When you run this, notice how you get the file open and the file save dialogs for free.
You also get the save as dialog for free. You'll notice the save and load dialogs have a
file type field. This is probably blank for you right now.
If you open your resource file you'll see an ID_MAINFRAME entry in the string table. This
attribute covers stuff like the Application name, the File Types and extensions etc that
are valid for the application.
If you enter something like this in there you'll get a nice file type in your application
when you run it.
Mantisoft OGLM\nScene\nOGLM\nOGLM Scenes (*.oglm)\n.oglm\nOGLM.Document\nOGLM Document
The first few strings ( separated by \n newline characters ) are the application titles
for the mainframe and the documents. The next are for the file types drop down. The next
is the extension for your files, the final things are pretty trivial and can be ignored.
That's about it for now, saving and loading your objects should be functional. If you have
trouble with this ( it's sooooo easy with MFC ) email me and I'll be happy to help you.
Time to Step Back, WAAaaay Back
At this point it's probably a good idea to review the features the modeller
incorporates and in addition attempt to determine where the modeller is lacking.
We Have...
4 different views of an object, one of them is 3D + perspective.
Can create meshes but can't input paramaters.
Need to cover...
How to create a dialogue in MFC and pass parameters to and from it. From here we'll get
our inputs for the mesh.
How to select a point
How to move a point
How to select a triangle face
How to change the views from 4 equal to 3 and 1
How to build a lathe
How to build an extrusion tool
That's a lot so let's take it one step at a time...
Eeny, Meeny, Miney, Mo = Selection
Before we go any further, lets' talk about point selection. Let's say I add a point to my
scene, how can I use the mouse to move it around ? Good question. I still haven't fully
figured this one out but let me explain how to select it for now. There's a couple of ways
to implement selection. The redbook mentions two. The first is the use of the openGL
selection buffer. Basically a buffer is an area into which you draw stuff. Example the
off-screen buffer is where the scene gets rendered and then when it's complete we swap the
off-screen and the on screen buffer to display the scene. This is how double-buffering
works. You always draw to the off-screen buffer.
With the selection buffer we do the same thing but with a twist. As each item is drawn to
the selection buffer, it's given a name. In other words you make an openGL call to
register that item with the openGL state machine. This sounds technical and it is to a
certain extent. I'm not going to go into this anymore than to say I've tried implementing
this and run into a large number of problems. The first and most bothersome is that the
selection buffer doesn't work consistantly across video cards. Meaning what works on one
doesn't work on another. I've also run into buffer-overflow meaning as I name all my
points ( potentially thousands ) I reach a point where the buffer is full and can't name
anymore elements. There are ways around this problem but I thought better of figuring them
out. If you'd like more information on selection go to the SGI. redBook examples page
(http://www.sgi.com/software/opengl/examples/redbook/) and search for selection on the
page.
No on to the way I did end up implementing selection. This method is also endorsed by the
RedBook so even though I'm not strictly using openGL buffers it's still an excellent way
of implementing selection. I've also found that this works quite well on all graphics
cards except Voodoo. So stay away from voodoo's if you want to implement selection.
Alternatively you could implement this with Glide from 3dfx if you wanted it to work on a
voodoo card. It would work no problem. Here's how it works.
The scene is basically made up of a number of points, lines an faces. Let's stick with the
simple method of point selection. The first thing we do is render the points in the scene.
This is simple, just add some code to the Draw functions of an element to cycle through
it's points and glVertex each one inside a glBegin(GL_POINTS ). Remember to set the point
size to something meaningful, probably 5.0 is good for most purposes. Ok, now the user can
see what we want them to pick. Remember to compile as often as possible, we're about to
get tricky...
Next we want to draw the same scene but in a RAINBOW of colors that the user won't eve
see. Here's how it's going to work...
1) We draw the regular scene to the screen in the normal colors.
2) We draw the same scene in a RAINBOW of colors to the off-screen buffer, giving each
element in each view a unique color. This color will be it's identifier.
3) The user clicks the screen to select a point
4) We get the mouse x and y coordinates from where the user clicked, find out which color
IN THE OFF-SCREEN selection scene they clicked on and with some simple arithmetic and
manipulation we find out which point they selected.
5) We set the points' selected property to "ON" and it draw's itself in a
special high-lighted color in the regular screen scene.
Make sense ? Try downloading the OGLM executable and test this out. My points go from
being normal colors to being red. We do the same thing when the user wants to deselect the
point except if the point is already selected then we set selection to be "OFF"
for that vertex.
Ok so that's all well and good, how the heck are we going to do that ? Hmm, how the heck
am I going to explain how I did that?
At this point we should revisit where the points or vertices are stored. I've actually
changed my position on this one. I had originally thought it would be good to have to
elements own the vertices from which they are built. This is fine but it does raise a
couple of issues. The first is that the vertices cannot be shared between elements. In
other words all elements are distinct, they cannot be joined together. The second issue
I've discovered with this is that vertices cannot be re-used across elements which leads
to a waste of resources. In order to figure this out I decided one day to move the ACTUAL
storage of the vertices from the element to the parent which is the object ( remember we
said that the scene was made up of an object and an object is made up of a number of
elements ).
This seems like a big deal but in reality, once you move the actual storage of the points
from the element to the object, everything works out fine. There's no real syntax change
even. The key here is that you can use a reference to an class just hte same as if it were
the class itself. Pretty cool.
Since the points are owned by the object, I just add a small draw type function to cycle
through all the points, drawing each one in turn in a new color. Here's the code to do
that:
// This function draws an element ( hopefully to the back buffer )
void GLElementMesh::GLDrawSelection(int *names_offset, int selection_mode)
{
int i;
Point3D a;
Point3D b;
Point3D c;
GLubyte red;
GLubyte green;
GLubyte blue;
int modifier = 256;
// Disable texture mapping
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
// If we're looking to select a triangle then...
if (selection_mode == OGLM_SELECTION_TRIANGLE ) {
// Loop through the element's triangles
// drawing each one in turn
glBegin(GL_TRIANGLES);
for (i=0 ; i < m_num_triangles ; i ++ ) {
// First get the
vertices
a =
m_vertices[m_triangles[i].a];
b =
m_vertices[m_triangles[i].b];
c =
m_vertices[m_triangles[i].c];
(*names_offset)++ ;
red = ( (*names_offset)
% modifier ) ;
green = ( (
(*names_offset) >> 8 ) % modifier ) ;
blue = ( (
(*names_offset) >> 16 ) % modifier ) ;
// IF this triangle is
selected then display it as white
glColor3ub(red, green,
blue);
// Next draw the
triangle
glVertex3f(a.x,a.y,a.z);
glVertex3f(b.x,b.y,b.z);
glVertex3f(c.x,c.y,c.z);
}
glEnd();
}
// If we're trying to select a point then...
else if ( selection_mode == OGLM_SELECTION_POINT ) {
// Loop through the element's triangles
// drawing each one in turn
glBegin(GL_POINTS);
for (i=0 ; i < m_num_vertices ; i ++ ) {
// First get the
vertices
//a = m_vertices[i];
a =
m_vertices[m_vertex_indeces[i]];
(*names_offset)++ ;
red = ( (*names_offset)
% modifier ) ;
green = ( (
(*names_offset) >> 8 ) % modifier ) ;
blue = ( (
(*names_offset) >> 16 ) % modifier ) ;
// set the color for
this point
glColor3ub(red, green,
blue);
// Next draw the point
glVertex3f(a.x,a.y,a.z);
}
glEnd();
}
// Finally draw the childrens' points or triangles as the case may be
for (i = 0 ; i < m_num_children ; i ++ ) {
m_children[i]->GLDrawSelection(names_offset,
selection_mode);
}
}
Couple of things to note here: The first is that I'm disabling lighting etc
which might effect the color of the thing that's drawn. The second is that I'm passing in
a names_offset counter which I use to "name" stuff. All this means is that I'm
giving each item a unique name or color. You'll see why in a second. Tha final thing to
note is the recursive piece at the end which refer to children. Don't worry too much about
this for now, I meant to explain children and the heirarchy thing this week but have not
had time to do it justice. I'll get back to it later. It's simply that each element has a
number of children which it's responsible for and thy TOO are elements who ALSO have
children. I just think of my family and it helps give each element a personality! Just
kidding.
Getting back to selection: When something is clicked, we need to find ou what it
was. For this we need the following code:
// This function processes which points are clicked on and
// has the logic to mark them as selected.
void GLManager::GLProcessSelection(int xPos, int yPos)
{
unsigned char pixels[3] ; // need 3 bytes to store Red, Green and Blue
values
int red, green, blue ;
int selected =0 ;
int modifier = 256;
int i = 0;
glClearColor(0,0,0,0);
glDisable(GL_DITHER);
// Draw a special selection scene to the back buffer
// This scene renders every object in a unique color.
// we figure out which was pressed by detecting what's
// the color under the mouse
GLDrawSelection();
// Get the color under the mouse.
glReadPixels(xPos,m_height - yPos, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
pixels);
red = ((int)pixels[0] );
green = ((int)pixels[1] ) * modifier ;
blue = ((int)pixels[2] ) * modifier * modifier ;
selected = red + green + blue -1;
// If we're selecting a point...
if (m_selection_mode == OGLM_SELECTION_POINT) {
// If we're selecting in a normal drawing
// scenario ( not the lathe or preview)
if ((m_drawing_mode == OGLM_DRAWING_NORMAL ) ||
(m_drawing_mode ==
OGLM_DRAWING_THREEANDONE ) ||
(m_drawing_mode ==
OGLM_DRAWING_ADDTRIANGLE ) ){
if (selected <
m_object.GLGetTotalNumberVertices() ){
// Set the point to the selected thing
m_object.m_current_point = selected;
//m_object.GLSetSelectedPoint();
m_object.m_vertices[selected].SetSelected();
// If we're adding triangles then have
// the object add this point to the list of selected
// vertices for the triangle
if (m_drawing_mode == OGLM_DRAWING_ADDTRIANGLE ) {
m_object.GLSetTriangleIndex(selected);
}
}
}
else if (m_drawing_mode == OGLM_DRAWING_LATHE )
{
// Otherwise we're
previewing the lathe
if (selected <
m_preview_object.GLGetTotalNumberVertices() ){
// Set the point to the selected thing
m_preview_object.m_current_point = selected;
m_preview_object.GLSetSelectedPoint();
}
}
}
// It's a triangle
else if (m_selection_mode == OGLM_SELECTION_TRIANGLE) {
if (selected <
m_object.GLGetTotalNumberVertices() ) {
// Set the current
triangle to the selected thing
m_object.m_current_triangle = selected;
m_object.GLSetSelectedTriangle();
}
}
}
Whenever the screen is clicked I call this function. It takes the x, y coordinates of the
screen click and works out what color is under the mouse at that point in the screen.
Since everything is drawn with a unique color I can work out which item is selected !
Pretty cool eh? I do this with a readpixels call, see above.
I think that should do it for me now. Sorry I missed out on heirarchys this
week. I also need to cover the Lathe etc. patience. Patience...
>> Download << -
last updated - June.23.2000
Space Mountain - April.07.2000
This is the latest thing I've coded. It's a simple program which moves a
rocket ship around a small terrain. I've created both these models with the OGLM modelling
tool I've built. See above. It's pretty cool if you ask me and it was quick to code. I
only had to create about 50 lines of code for the whole program. The rest was re-used from
the modeller. It's great having built this thing to be finally able to create something
worthwhile. If you haven't considered reading the article above I highly recommend it. In
addition if you download the OGLM ( see above ) then you can use it to edit the models in
Space Mountain! You could try adding a little house or a bump in the landscape. It should
work but persevere as the OGLM is still a little tricky to use.
>> Download <<
Car Racer - Mar.25.2000
It's EXTREMELY basic as such, it'll give you all a good idea how to write a
basic game. Basically, this is the project I was working on when I decided to write the OGLM. In any case, this uses some textures to build a grid which is the
track. It also has collision detection and a nice hand brake effect ( press the space bar
when travelling at speed ). I think there's some code commented out to change the
viewpoint from third person ( currently) to first person. Change it however you want and
let me know if there's any problems. Maybe someone could redraw the tiles and send them
back to me? Anyway folks, I hope it's helpful.
>> Download <<
Screen Savers - Mar.24.2000
I've just added the code to a skeleton screen saver. This code is basically all
you need to create your own screen saver. I can't take credit for writing all of it as
I've pasted a lot of stuff from other sources but it's pretty simple anyway so I'm sure no
one will mind if I share it. It's a VC++ project, it creates a device context, rendering
context, intializes the GL and draws a nice teapot. You can change this easily. Look for
the RenderScene function. All you have to do is add in the drawing code. I don't have a
screen shot as I haven't figured out how to get a shot from a screen save ! Enjoy.
>> Download <<
Maze of Madness
The maze of Madness (MOM) was a project built by Killian Breslin and I for our
third year in Dublin City University. It's a take off of the popular Wolfenstein 3D game
which gave birth to Doom. It's pretty cool as it features texture mapped representations
of our class mates on the walls. The frame-rate on this thing is pretty amazing and I have
to give credit to Killian aka Wig for working on that. He took the code and converted it
to assember like a good thing and got the speed WAAAY up, even on a 386 it runs pretty
fast but good luck finding one these days...
Other cool features are Soundblaster support
and Novell network game support. This means you can play your buddy over the office
network. Be warned though I'm not responsible for any bad things that happen as a result
of this or any of the other programs on this site. That said, there's not really anything
bad that these programs could cause.
>> Download <<
Dungeon of Death
This is probably one of my more shining moments. This was a game built again by
Killian and I. We created the Dungeon as our fourth year project. The effort took about
4-5months from initial concept.
The we developed this for Solaris which added to the difficulty. There's
comprehensive documentation and code available on demand.
Features include such niceties as texture mapped
characters. A full 3D-editor also built for Solaris which we used to create the model
files. Once these are created you can animate them and save their motions ( for instance a
kick or punch ). The game then uses these files to animate the characters.
We also added network support and included some other sound features etc.
The battle takes place on the moon with Earth in the background. As the players
rotate we have a nice shadow effect on the ground to give the illusion of realism.
There are four characters in the game which we
constructed using the editor. This was another case of us using our fellow students as
cheap labour. We auditioned people for the parts of our characters. I've included to the
right, pictures of the end product. We have Spikey Back and The Dude ( yellow texture
mapped polygon hair).
We also included a computer opponent who gets progressively smarter. He'll
try and block your movements if you attempt to hit him and then he'll kick your ass so
watch out.
Last time I compiled this was about 2 years ago on Solaris with network card
installed so forgive me if this don't compile anymore. I've also managed to get it running
on Linux with the network stuff ripped out.
>> Download Code << >> Download Documentation <<
Gloop
Gloop was kind of a joke but I wrote it anyway. It originally was born out
of a drunken stuper I found myself in. I thought of the idea again when sober and decided
to write it.
It involves Gloop falling from the ceiling of this cave. The cave dwellers
collect it and use it to build missiles etc. There's more but I'm not going to go into it
here. Let me know if you're interested.
>> Download <<
Murns of Mayhem
The Murns was another one of those freaky type games I started to write. It's
still a work in progress but pretty entertaining. All the graphics functionality was built
from scratch and uses VGA mode 13h ( remember that guy ?). There's no sound and no
enemies. Oh well, it's still fun to watch the guy run around like a maniac.
To sum it
up this is basically an example of fast 2-D tile based programming. There's no openGL or
anything as this was back in the days when that stuff was greek to me. The speed the murn
moves at is comparable to Sega Sonic and in total it took about 1 week to get to this
point. Features include keyboard handlers, blitting, hand drawn graphics by moi.
>> Download <<
|