• Advertisement
Sign in to follow this  
  • entries
    17
  • comments
    22
  • views
    7024

About this blog

Timeline of a 3D Engine's Development.

Entries in this blog

 

Working at the Paintball Field

Well, the boss is taking us all out paintballing today so no work for me!

As for progress, I reworked my model system a bit to get ready to begin working with bones and I'm still reading up on skeletal animation as well.

Peace outside!

NoMonkey

 

Slow Updater

Well, it seems like forever since I've posted a new journal entry so I thought I should probably get on the ball.

I haven't browsed through my journal so I'm not quite sure where I left off but I think it had something to do with me not getting a job. Well, they called me back a few months later and offered me a position which I accepted. I've now been happily working in the industry for about 9 months now!

Anyway, enough catching up on the saga of my life, let's get caught up my engine development, shall we?

My poor engine. I've neglected it for so long and just recently came back to work on it again. Can you imagine what that must be like. At first you're getting to spend tons of time with me and then all of a sudden, BAM!, I throw you in a folder and turn off the lights. I'm a bastard like that sometimes though, and you or anyone else who wants to spend time with me just has to accept this.

So now that my engine and I have made ammends, I decided to treat it to a few upgrades.

Recently I've implemented a 3DS loader, Maya loader, Batching system, Resource manager, and did a bit of reconstructive surgery on the design a bit.

Overall I'm very happy with how it's turning out although there are definitely times where I come across some older code and just can't help but punch myself in the face because I can't figure out wtf I was thinking when I wrote it. So in turn I spend a lot of time rethinking and reworking bits and pieces of the code; But who doesn't?

Next up on my plate is skeletal animation. This will only be for the maya models because that's the only thing my artists use! I'm still doing a lot of reading although everything seems fairly straight forward.

Somewhere in there I'm also going to put in a stream manager for my up and coming material manager of awesomeness! Okay, it probably won't be the most spectacular thing in the world, but it will be flexible and hopefully fast.

Also, if anyone needs assistance in loading either 3DS or Maya files, please don't hesitate to ask. Figuring out some of this stuff was a bit of a pain so I figure I'll share any knowledge I gained. Neither of them currently load any animation data... yet.

Oh, and leave me some comments if you read this. I don't care if it's just to say "Hi." or "You suck at programming."

Keep it real,

NoMonkey

NoMonkey

 

No Job For YOU!

Well, unfortunatelly I didn't get the job. They said it was a tough decision, but unfortunatelly the other candidate had more game development experience than I did. Although they did tell me they would definitely be interested in hiring me in the future when another position opens up. I know, they all say that, but he really seemed sincere about it. I guess being narrowed down to the last two candidates isn't too bad although it's still not resume material which bites.

In the mean time, I'll just continue to pump my CV out to anyone who will look at it!

In other news, I've implemented overlays into my engine. They are very basic at the moment, but will hopefully soon be the foundation to a GUI of sorts. At the moment, I am actually switching from projection to orthoganol mode which is probably a bit of a performance hit. I am going to try disabling the Z buffer and rendering before any camera movement to see if it speeds things up. Right now I'm running at 1635 FPS in full screen and 805 FPS in windowed mode so I don't know how much of a difference it will really make right now, but perhaps in the long run.

That's all for now!

NoMonkey

 

Long time no see.

Everyone clap for my monthly post :)

I thought it might be a good time to let the sooper people of journal land know what I've been up to lately.

First off, I scored an interview with a game company recently. They flew me out to meet the team and go grab a bite to eat. It was a short visit (one night in a sweet bed & breakfast), but an outstanding experience overall. I should know sometime this week whether I got the job or not.

As for the engine, I decided against what I previously decided and decided to continue with the 3D-ness. Yes, a lot of decisions were made by me.

I implemented an event system for relatively easy communication between the engine and the game. I also stole OGRE's idea for frame listeners. Overall, I am really liking the way things are turning out.

Well, that's really it. I know it was brief, but I can only spend so much time updating my journal at work :).

Keep it real!

NoMonkey

 

Late Update

Haven't updated in a while so here goes...

After much debate, I have decided to revert back to 2D for a while. I feel that I don't have enough base knowledge of basic gameplay to be able to seperate the engine from the game successfuly. I also think that I need to spend a little bit more time on the basics instead of diving in over my head in 3D. While it kinda blows scraping the 3D portion of the engine, it's nice to know I gained a lot from the task. Also, much of the code that I wrote will be easily usable with my 2D games as well.

My goal is to create a few more basic 2D games and then attempt a 2D game engine. The only game I have ever really taken to a playable level is breakout. Granted, while this only took a couple of weeks to finish, I somehow feel I didn't get all that I needed out of it.

Another reason I have decided upon 2D graphics is that since I am focused on creating adventure games such as the classic Monkey Island series and Sam & Max Hit the Road, I'd like to stick to that same 2D feel they had. Not to mention people will have less of a chance of vomiting when they see my programmer art. :)

Thanks for looking.

Later.

NoMonkey

 

Scene Graphs and what not

It's been a while since my last update as I haven't felt that I made much coding progress in the meantime.

I've been trying to sort out my scene graph and the implementation of a spatial structure such as an octree, kd-tree, quadtree, etc. I haven't quite figured out which one would suit my engine the best.

I'm also having an issue with determining what type of structure to hold my dynamic geometry in. I devised a way to implement them into an octree, but after reading 15 articles on it, I get the impression it is mainly designed for static geometry instead. So then if I seperate my static geometry and my dynamic geometry into two different structures, how do I relate them for collision/ray tracing/etc?

I guess what it boils down to is that I am going to have to implement something and go from there. I've come to terms with the fact that you can read articles/books your entire life but if you never bother to actually implement anything, you won't get anywhere.

Well, for all those who don't bother looking unless there's a screen shot, here ya go:



This is my scene graph in a pretty primitive state. The top block is the root and the other two are children of it. The root is rotating about x, y, and z; the front child has the same rotation applied to it, but is moving faster as it's parent has already been rotated and is also moving side to side via cos. The back child just rotates along with the parent.

Thanks for looking!

NoMonkey

 

Guess who's back, Back again?

Wahoo! My account finally got straightened out and can post in my journal once more! BTW, my username used to JohnMMena.

To get caught up on what's been going on, you can read this journal entry (or just scroll down):

August 19, 2005

NoMonkey

 

Dumb Pointers made Smarter... AND MORE

Journal Entry for 8/23/05 12:30 A.M.
Well, if you're reading this, then you've most likely noticed that I am almost at the bottom of the journal page. Oh well, I'm sure they'll get around to reactivating it soon.

Anyway, I accomplished some more on memory management tonight. I implemented a heap tracer so I will know if something doesn't get deallocated before the app dies. I decided against overloading the new/delete operators as I have found that my overloaded delete may not always get called in the event a constructor throws an exception. Instead I went with inline macros again. It all worked out great. It will tell you which file/function/namespace/line number that the pointer was allocated in on both creation and deletion. If a pointer is never freed, the tracer will output where it was originally created so you can track it down quickly.

Next on the menu is implementing all of this into my old engine! I'm finally moving on! It will all have been worth it in the long run I'm sure.



Journal Entry for 8/22/05
Well, last friday I sent a request to the GD.Net Gods for a name-change from JohnMMena to NoMonkey. Unfortunatelly when they switched the name it deactived my GD.Net service.

So for the meantime, I am just going to update my last entry until things get straightened out.

I got the Smart pointers within 1 second of the standard new/delete. I really think I finally got them where I want them... maybe :).

I also implemeneted freelist's which turned out to be a pain all because of one very weird problem. When I would use the freelist on a simple base class, it worked fine, but for shits and giggles I decided to use it on my smart pointer class. When I did this, I would get a user breakpoint somewhere in the heap debugger stating that some memory had moved blah, blah, blah and I think there was something about my momma being fat in there too. Anyway, after beating my head over the problem for hours, I found that if I didn't initialize one variable in the default constructor of the smart pointer class, it would run okay, but had memory leaks.

So after wanting to grab my shot gun, load my computer up onto a launcher and yell "PUUUUULLL!", I decided to let some fresh eyes take a look at it and sent it over to Visage.

He and I went back and forth on the possible problems and after mulling it all over we came to the conclusion that there couldn't be anything wrong with the code whatsoever. Then, out of desperation, I changed my initial variable allocation of the freelist from new to malloc and to he and I's surprise, it worked. I think his exact quote was "I feel worthless as a programmer right now."

Anyway, problem solved and everything seems to be working okay. I think I'm going to look into overloading new/delete for memory tracing next. Then once this is complete, I might be able to move on to the actual engine work! But I doubt it. :)

Keep it real!



Journal Entry for 8/19/05
Well, after consulting with Eberly (3D Game Engine Architecture) on the whole slow pointer issue, I finally got these things to run at a reasonable speed.

My new numbers at n=10,000,000 loops is now:

Empty test loop took 0.031000 seconds

Standard new/delete took 44.860000 seconds

mem_ptr new/release took 99.985000 seconds

The last one of course being my smart pointer. I ran this on a different, slower machine which is why the numbers are larger in general. The cool thing is that the spread between the standard new/delete vs. mem_ptr new/release is only 55 seconds whereas on the other machine w/ the older code it was 173 seconds. That's only ~0.00001 seconds of overhead per alloc/dealloc pair. Not to mention the time for the smart pointers is faster with the newer code on the slower machine than the older code on the faster machine. (Say that 10 times fast!)

To gain this speed, I implemented Eberly's hash table.

Given how fast I can allocate 10 million objects, I think I can finally wrap these babies up and move on!

Next up: Free Lists!

I've already found a pretty kick ass free list example that runs the above loop in less than a second. I'm also debating on memory pools, but I'm getting mixed reviews on what people think about their reliability/performance.

[UPDATE]
I made some more optimizations to the code, my numbers are now:

Empty test loop took 0.047000 seconds
Standard new/delete took 45.844000 seconds
mem_ptr new/release took 51.968000 seconds

How do you like them apples? I'm much happier with these results!
[/UPDATE]

Thanks again for looking!

NoMonkey

 

I'm quick with the slowness...

Well, unfortunatelly I found out today that my smart pointers are slower than pack sloths in the desert. I ran a time analysis between a normal pointer with new and delete and my smart pointers with new and release.

In this test, I did n=1,000,000 allocations/deallocations for each run. Here are the numbers:

Run an empty loop n times: 0.031s

Loop n times allocating and deleting regular pointers: 17.298s

Loop n times allocating and releasing Smart pointers: 190.724s

Holy shit they are slow! It takes a little over 3 minutes to run! I pray that a hash map will be able to speed this up significantly, but I seriously doubt it.

I may just have to go the typicial way of inheriting them into an object base class. I really didn't want to do it this way for various reasons, but such a lack of performance is definitely taking precedence over everything else here.

I'll post again tonight with my hash map results.

[EDIT]

Well, after trying various options, I have decided to keep it the way it is with the minor optimizations I have made. Nonetheless, I will go over the options I tried.

After a long while of learning exactly how a hash map works, I began to implement it in hopes of speeding things up significantly. Turns out it slowed it down more than anything! Because my class is a templated, I have no common comparison operator for the hash map to use therefore everything is compared by the pointer, which apparantly is very slooooowwww.

Because the only other option was google's sparse hash which was supposed to be a bit slower, I didn't bother attempting to change the datastructure any further. Instead I began to run smaller tests to get a more realistic idea of what the times would be like at a lower object rate.

I figured 100,000 objects would be a generous amount to allocate/deallocate in a given instant. The times came out only thousand's of a second apart. This, of course, is good news for me as I get to keep my smart pointers!

[/EDIT]

NoMonkey

 

Beautiful Error Logging

Tonight I got the new error logger implemented. I utilized the idea of XML/javascript from this article:

https://www.gamedev.net/reference/programming/features/xmltech/

I must say, this is one of the sexiest loggers I have ever had. The only portions I ended up using from the article were the actual files provided for download: the .XSL, .XML, and .HTML. I figured there wasn't any point in reinventing such a beatifully layed out wheel.

As for the code, I ended up making some changes to suit my needs. The article uses macro definitions to encapsulate different levels of debug information like so:


#define Log_Write_L1( linetype, linetext )
CLogFile::GetSingletonPtr()->WriteLogEntry(
(linetype),
__NAMESPACE__,
__FILE__,
__FUNCTION__,
__LINE__,
(linetext) )

//this enables you to do the following:

#if SYSTEM_DEBUG_LEVEL == 3
//enable all macros
#define Log_Write_L1( linetype, linetext ) ...
#define Log_Write_L2( linetype, linetext ) ...
#define Log_Write_L3( linetype, linetext ) ...

#elif SYSTEM_DEBUG_LEVEL == 2
//enable levels 1..2 macros
#define Log_Write_L1( linetype, linetext ) ...
#define Log_Write_L2( linetype, linetext ) ...
#define Log_Write_L3( linetype, linetext )

#elif SYSTEM_DEBUG_LEVEL == 1
//enable level 1 macros
#define Log_Write_L1( linetype, linetext ) ...
#define Log_Write_L2( linetype, linetext )
#define Log_Write_L3( linetype, linetext )

#else
//disable macros
#define Log_Write_L1( linetype, linetext )
#define Log_Write_L2( linetype, linetext )
#define Log_Write_L3( linetype, linetext )

#endif







I had to remove \ at the end of all the macro lines for formatting purposes.

While I liked the idea, I didn't like how there was no option to supply a formatted string via a va_list. I first attempted to do the following:

#define Log_Write_L1( STRING, ... )

which I soon found out doesn't work. For a while I thought I was stuck not being able to supply parameters until I found one slick solution.

The idea is to create a function which saves the line number, file name, etc. and then returns back a callback function which does the actual argument list. Now that I read what I just wrote, it isn't very clear. Let me just show what I ended up with:


#if SYSTEM_DEBUG_LEVEL == 3
//enable all macros
#define LOG_L1( LOGTYPE ) CLogger::Log( LOGTYPE , __NAMESPACE__, __FILE__, __FUNCTION__, __LINE__ )
#define LOG_L2( LOGTYPE ) CLogger::Log( LOGTYPE , __NAMESPACE__, __FILE__, __FUNCTION__, __LINE__ )
#define LOG_L3( LOGTYPE ) CLogger::Log( LOGTYPE , __NAMESPACE__, __FILE__, __FUNCTION__, __LINE__ )
#elif SYSTEM_DEBUG_LEVEL == 2
//enable levels 1..2 macros
#define LOG_L1( LOGTYPE ) CLogger::Log( LOGTYPE , __NAMESPACE__, __FILE__, __FUNCTION__, __LINE__ )
#define LOG_L2( LOGTYPE ) CLogger::Log( LOGTYPE , __NAMESPACE__, __FILE__, __FUNCTION__, __LINE__ )
#define LOG_L3( LOGTYPE )
#elif SYSTEM_DEBUG_LEVEL == 1
//enable level 1 macros
#define LOG_L1( LOGTYPE ) CLogger::Log( LOGTYPE , __NAMESPACE__, __FILE__, __FUNCTION__, __LINE__ )
#define LOG_L2( LOGTYPE )
#define LOG_L3( LOGTYPE )
#else
//disable macros
#define LOG_L1( LOGTYPE )
#define LOG_L2( LOGTYPE )
#define LOG_L3( LOGTYPE )
#endif







The CLogger::Log prototype looks like this:


typedef void (*CallBackPtr)(const char*, ...);

static CallBackPtr Log(LOGTYPES LOGTYPE, const char *szNameSpace, const char *szFileName, const char *szFunctionName, int iLineNumber);


//This is the what the callback looks like:

static void LogCallBack(const char *msg, ...);







So now I have a macro which stores a logtype (comment, error, debug, etc.), namespace, filename, function name, and line number and then returns back a pointer to a call back function. The reason these are stored here is because all of these need to be accurate to the place where the LOG_L1 was called.

This call back function then retrieves the previously stored information and writes it to the log along with the formatted message.

here is how the log would be called now:

LOG_L1(COMMENT)("This is comment number %d", iCommentNum);

Tadda! A formatted string that is sent through a macro (sort of anyway).

You might also be wondering where __NAMESPACE__ is coming from. This is a custom define at the top of each file. The macro:

#define __NAMESPACE__ = "Default"

is in the header file and is passed if a custom namespace is not defined.

Let's see, what else... Oh yeah! I also implement GUARD and UNGAURD macros for less-mess try-catch statements:


#define CLEAN_SHUTDOWN
GarbageCollector::CleanUp();
CLogger::close();

#define GUARD
try
{

#define UNGUARD
}
catch( char * str )
{
LOG_L1(ERROR)(str);
CLEAN_SHUTDOWN
}
catch (std::exception& e)
{
LOG_L1(ERROR)("Exception: %s", e.what());
CLEAN_SHUTDOWN
}
catch (...)
{
LOG_L1(ERROR)("FATAL ERROR");
CLEAN_SHUTDOWN
}


//This makes it really easy to encapsulate a function with error handline like so:


int main(void)
{
/* Begin try/catch */
GUARD

// Check for memory leaks at the end of the application.
// Results will show in the Output window.
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

mem_ptr Logger = new CLogger("ErrorLog.xml");

LOG_L1(EVENT)("Releasing Logger");

Logger.release();

throw "We've got a problem!";

/* No errors, shutdown clean. */
CLEAN_SHUTDOWN

/* End try/catch */
UNGUARD

/* Return error free */
return 0;
}






And there you have it.

A significant amount of irrelevant code has been left out of all of this to keep from boring you guys to tears.

Unfortunatelly, I still have a lot of "low-level" engine stuff to implement such as data structures, free lists, misc macros for debugging, profiler, etc. so it will be a while before you guys get any screen shots.

That's all for now!

NoMonkey

 

Smart Pointers Revealed!

I finally cleaned up all the excessive debug messages in the smart pointers and now I just have a bunch of log calls :).

Either way, here is my current solution to smart pointers.


#ifndef CMN_MEMORY_H
#define CMN_MEMORY_H

#include
#include
#include "garbage_collector.h"
#include "logger.h"


#define DEBUG_MEMPTR


template typename T>
class mem_ptr
{
private:
static std::mapint> m_mapActive;
T* m_tObj;

void addRef(void);
void remRef(int bForceDelete = false);
public:
mem_ptr() : m_tObj(NULL) {};

mem_ptr(T* tObj) : m_tObj(tObj)
{
addRef();
}

mem_ptr(const mem_ptr &p) : m_tObj(p.m_tObj)
{
addRef();
}

~mem_ptr()
{
remRef(true); // Force the delete to clean up anything not sent to the garbage collector
}

inline void release(void)
{
*this = NULL;
#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Object of type %s was released.", typeid(m_tObj).name());
#endif
}

inline bool isValid() const
{return (m_tObj!=0);}

inline T* operator =(T *o);

inline T* operator =(const mem_ptr &p);

inline operator T*() const {return m_tObj;}

inline bool operator !() {return !(m_tObj);}

inline bool operator ==(const mem_ptr &p) const
{return (m_tObj==p.m_tObj);}

inline bool operator ==(const T* o) const
{return (m_tObj==o);}

inline T* operator ->() const
{return m_tObj;}
};


template typename T>
std::mapint> mem_ptr::m_mapActive;


template typename T>
void mem_ptr::addRef(void)
{
if( !m_tObj ) return;

m_mapActive[m_tObj]++;

#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Reference increased on object of type %s. Reference count is now %d", typeid(m_tObj).name(), m_mapActive[m_tObj]);
#endif
}


template typename T>
void mem_ptr::remRef(int bForceDelete)
{
if ( !m_tObj ) return;

m_mapActive[m_tObj]--;

#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Reference decreased on object of type %s. Reference count is now %d", typeid(m_tObj).name(), m_mapActive[m_tObj]);
#endif

if( m_mapActive[m_tObj] 0 )
{
m_mapActive.erase(m_tObj);

#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Object of type %s was removed from the active list", typeid(m_tObj).name());
#endif
/* If the delete is forced, then
the object is destroyed immediately
otherwise, it is sent to the GarbageCollector
for a one time cleaup with the other objects. */
if (bForceDelete)
{
delete m_tObj;
m_tObj = 0;

#ifdef DEBUG_MEMPTR
CLogger::Write(WARNING, "Object of type %s was killed by mem_ptr::remRef()", typeid(m_tObj).name());
#endif
} else {
GarbageCollector::Recycle(m_tObj);

#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Object of type %s was sent to the Garbage Collector", typeid(m_tObj).name());
#endif
}
}
}


template typename T>
inline T* mem_ptr::operator =(T *o)
{
remRef();
m_tObj=o;
addRef();
return m_tObj;
}


template typename T>
inline T* mem_ptr::operator =(const mem_ptr &p)
{
remRef();
m_tObj=p.m_tObj;
addRef();
return m_tObj;
}


#endif










I know this isn't extremely well commented, but hopefully you get the idea. Besides, it's almost 2:00 A.M. and I'm about to pass out.

I will note, however, that the main reason for this design is to make the storage maps smaller by keeping them grouped by object type through templates. This makes traversing them a bit faster when needing to add a new reference. Also be aware that the overhead of std maps is not light. I intend on implementing hash tables/sets, lists, and other data structures later on to help with this a bit.

I also wrote a handy little console test app to log all of my pointer assignments and check for memory leaks:


int main(void)
{
// Check for memory leaks at the end of the application.
// Results will show in the Output window.
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

mem_ptr Logger = new CLogger("ErrorLog.html");

Logger->Write(COMMENT, "#0000BB\">Beginning First Test");
Logger->Write(COMMENT, "Allocating and Creating iTest1");
mem_ptrint> iTest1 = new int;

Logger->Write(COMMENT, "Creating iTest1_Copy");
mem_ptrint> iTest1_Copy;

Logger->Write(COMMENT, "Copying iTest1 to iTest1_Copy");
iTest1_Copy = iTest1;
Logger->Write(COMMENT, "#0000BB\">Ending First Test");

Logger->Write(COMMENT, "#0000BB\">Beginning Second Test");
Logger->Write(COMMENT, "Creating iTest2");
mem_ptrint> iTest2;

Logger->Write(COMMENT, "Allocating iTest2");
iTest2 = new int;

Logger->Write(COMMENT, "Creating and Allocating iTest2_Copy");
mem_ptrint> iTest2_Copy = new int;

Logger->Write(COMMENT, "Assigning iTest2_Copy to iTest2.
This should dereference iTest2_Copy's initialized allocation and reassign it");
iTest2_Copy = iTest2;
Logger->Write(COMMENT, "#0000BB\">Ending Second Test");

// Intentionally neglect to release 2 of the objects
// to verify the app is still killing them. This
// will generate warnings.
iTest1.release();
iTest2_Copy.release();

Logger.release();

GarbageCollector::CleanUp();

Logger->Write(COMMENT, "#0000BB\">EXITING APPLICATION");

/* Return error free */
return 0;
}










Here is what this log looks like:



The reason for the warnings at the bottom is that I am testing to make sure that the objects get destroyed regardless of the Garbage Collector getting ahold of them. If the last reference to the object goes out of scope before it is released and inserted into the Garbage collector, then the smart pointer is forced to delete the object during destruction. This is not preferred and is why you see a warning when I fail to release iTest1_Copy and iTest2. Also note that the smart pointers are cleaning up for me even once I return from main(); This is noted in the log after "EXITING APPLICATION".

The reason the logger continues to work is because I made it static for testing purposes. It will be a singleton when implemented and will no longer be created as a mem_ptr.

As you can see, I haven't gotten around to implementing the XML/JS version of the logger yet. This is just a place holder for the mean time.

Feel free to let me know what you think; Love it, hate it, whatever.

Thanks again for looking!

NoMonkey

 

Memory Management revealed!

Here is my current smart pointer.


#ifndef CMN_MEMORY_H
#define CMN_MEMORY_H

#include
#include
#include "garbage_collector.h"
#include "logger.h"


#define DEBUG_MEMPTR


template
class mem_ptr
{
private:
static std::map m_mapActive;
T* m_tObj;

void addRef(void);
void remRef(int bForceDelete = false);
public:
mem_ptr() : m_tObj(NULL) {};

mem_ptr(T* tObj) : m_tObj(tObj)
{
addRef();
}

mem_ptr(const mem_ptr &p) : m_tObj(p.m_tObj)
{
addRef();
}

~mem_ptr()
{
remRef(true); // Force the delete to clean up anything not sent to the garbage collector
}

inline void release(void)
{
*this = NULL;
#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Object of type %s was released.", typeid(m_tObj).name());
#endif
}

inline bool isValid() const
{return (m_tObj!=0);}

inline T* operator =(T *o);

inline T* operator =(const mem_ptr &p);

inline operator T*() const {return m_tObj;}

inline bool operator !() {return !(m_tObj);}

inline bool operator ==(const mem_ptr &p) const
{return (m_tObj==p.m_tObj);}

inline bool operator ==(const T* o) const
{return (m_tObj==o);}

inline T* operator ->() const
{return m_tObj;}
};


template
std::map mem_ptr::m_mapActive;


template
void mem_ptr::addRef(void)
{
if( !m_tObj ) return;

m_mapActive[m_tObj]++;

#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Reference increased on object of type %s. Reference count is now %d", typeid(m_tObj).name(), m_mapActive[m_tObj]);
#endif
}


template
void mem_ptr::remRef(int bForceDelete)
{
if ( !m_tObj ) return;

m_mapActive[m_tObj]--;

#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Reference decreased on object of type %s. Reference count is now %d", typeid(m_tObj).name(), m_mapActive[m_tObj]);
#endif

if( m_mapActive[m_tObj] {
m_mapActive.erase(m_tObj);

#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Object of type %s was removed from the active list", typeid(m_tObj).name());
#endif
/* If the delete is forced, then
the object is destroyed immediately
otherwise, it is sent to the GarbageCollector
for a one time cleaup with the other objects. */
if (bForceDelete)
{
delete m_tObj;
m_tObj = 0;

#ifdef DEBUG_MEMPTR
CLogger::Write(WARNING, "Object of type %s was killed by mem_ptr::remRef()", typeid(m_tObj).name());
#endif
} else {
GarbageCollector::Recycle(m_tObj);

#ifdef DEBUG_MEMPTR
CLogger::Write(COMMENT, "Object of type %s was sent to the Garbage Collector", typeid(m_tObj).name());
#endif
}
}
}


template
inline T* mem_ptr::operator =(T *o)
{
remRef();
m_tObj=o;
addRef();
return m_tObj;
}


template
inline T* mem_ptr::operator =(const mem_ptr &p)
{
remRef();
m_tObj=p.m_tObj;
addRef();
return m_tObj;
}


#endif

NoMonkey

 

Memory Management

I waited a couple of days to post as I hadn't done much work on the engine and didn't want to waste server space otherwise.

What have I been working on? As the title states: Memory Management. About a year ago a buddy of mine and I developed our own memory management of sorts. It was based on the Enginuity's algorithm although we didn't like the typicial system of splitting up the reference counting and the smart pointer. We also didn't like how the smart pointer was limited to the base Object type. So we made our own twist where we could use this for anything from integers to custom classes.

It probably has a ton of holes in it, but it's always fun to know you made something that wasn't directly out of a text book! It's also highly likely that it has been done before and people stay away from it for a reason :).

Anyway, I lost the code for it when my laptop hd crashed so I finally got ahold of him and he sent the old code over to me.

After dusting off the file, I made a few optimizations to it and also added a basic garbage collector. I ran various tests against it and it proved memory-leak free (according to crtdbg anyway!).

The code is still a little messy since I haven't implemented a Logger yet and tons of debug messages inhabit it's contents. When I get it cleaned up, I'll post some code examples of it if anyone seems interested.

As for the Logger, I plan to implement something based on this article:

https://www.gamedev.net/reference/programming/features/xmltech/default.asp

It appears to be a very clean solution and I'm pretty psyched to see the results. Talk about sounding like a nerd. Nonetheless, it will be highly benificial.

Regarding the basic structure of the engine: I have decided to stick with my original design of accessing handles although I will most likely take a more polymorphic approach instead. This probably means nothing to you readers, but it will show itself in time.

Thanks for looking!

NoMonkey

 

Plugging away.

Not too much going on today with the engine. I'm working on the basic Object class and on an RTTI system.

Tomorrow I plan to get the smart pointers implemented and perhaps overload new and delete for reference counting.

I apologize for the weak update!

-NoMonkey

NoMonkey

 

ND Engine

I figured I might as well post a pic of the engine before I tear it all apart for the revamping.



It really is much faster than 85 fps! I currently have V-Sync enabled to prevent tearing.

So as you can see, it's not too terribly complex. There was actually a newer version with lighting but it got lost when my laptop hd crashed.

It has a pretty cool setup to where you request handles to objects from the engine itself. Such as if you wanted to write some text, you would do the following:


// When initializing...
HTEXT *pText = new HTEXT();

pEngine->getHText( 15, "Comic Sans MS", pText );
pText->setColor( 255, 255, 0 );

// When rendering...
pText->setPos( 10, 10 );
pText->drawText( "ND Engine Demo" );

// The game accessible render function is going to be removed
// in the up coming version so the engine will
// care for the order of drawing.




It really added a nice layer of seperation from the engine to the game. There could be many public functions in the actual CText class that the engine could access, but the game itself could only access those members exposed by the handle.

This ideally was going to follow suit with models, lighting (which it did) and all other objects in the engine.

I may still take this route during the revamp, we'll just have to see.

Thanks again for looking!

NoMonkey

 

Ned The Naive

Well, here he is:



This is Ned, Ned the Naive. He's a character I came up with about 6 months ago while playing around in MS Paint. I did the glow effect in PS about 5 minutes ago for fun.

He has a whole profile which I will post in the coming days to give you guys an idea of exactly what type of guy Ned is. I might even throw up some info on his family and environment. He will be used as the main character in my future point-and-click adventure this engine is being built for.

There are no pictures other than this one as I could never come up with a body that I was happy with. I have began to *attempt* to model his head in Maya, but I'm a programmer so it's going to be slow progress there.

Anyway, hope you guys like him!

NoMonkey

 

I Heart Reading

I have finally began to actually read my latest purchase: "3D Game Engine Architecture" and let me say this, if you are interested in developing your own 3D engine, then this book is a must have. I am only about 100 pages into it and already have a brain full of ideas to improve upon my already existing "engine" (err.. DX wrapper of sorts).

My current "engine" is built upon a design that a buddy of mine and I came up with by browsing through the Enginuity series and some other articles around GD.Net. It is DX API, Window OS specific although I am in the works of revamping it for portability thanks to my new handy-dandy book! (Okay, I'll shut up about the book now!). It is in an infant stage in that the low-level portions are still being built although fun features like lighting, text, input, and the camera are currently implemented. I also have this sweet cube that spins in circles!

My goal for this engine is to create a point-click 3D adventure based on Ned, my beloved MS Paint drawing. He's pretty sweet to look at so I'll put up some pictures of him later this evening.

I'd also like to create a top down similuation with pirates stranded on an island. Hopefully I can create a robust enough engine to make both of these games a reality.

That's all for now!

NoMonkey

Sign in to follow this  
  • Advertisement