What do you think about the design of my game engine?

Started by
6 comments, last by JackOfAllTrades 12 years, 3 months ago
I'm just going to give you a chunk of code which would be a simple program using my API. Tell me if you see something that can be done better. Note: I still need to create constructors for a few of the higher level classes.





#include <windows.h>
#include <mmsystem.h>
#include <winnt.h>
#include <Ovgl.h>

HWND hWnd;
Ovgl::Instance* Inst;
Ovgl::RenderTarget* RenderTarget;
Ovgl::Window* Window;
Ovgl::MediaLibrary* MediaLibrary;
Ovgl::Scene* Scene;
Ovgl::Actor* Actor;
Ovgl::Camera* Camera;
Ovgl::Emitter* Emitter;
Ovgl::Texture* Texture1;
Ovgl::Texture* Texture2;
Ovgl::Mesh* Mesh;
Ovgl::Object* Object;
Ovgl::Light* Light;
bool g_Quit = false;

void MouseMove(long x, long y)
{
Camera->setPose( &((Ovgl::MatrixRotationY(x / 1000.0f ) * Ovgl::MatrixRotationX( -y / 1000.0f)) * Camera->getPose() ) );
}

void KeyDown(char key)
{
if(key == (char)27)
{
g_Quit = true;
}
if( key == 'W')
Camera->setPose( &(Ovgl::MatrixTranslation( 0.0f, 0.0f, 0.1f ) * Camera->getPose() ) );
if( key == 'S')
Camera->setPose( &(Ovgl::MatrixTranslation( 0.0f, 0.0f, -0.1f ) * Camera->getPose() ) );
if( key == 'A')
Camera->setPose( &(Ovgl::MatrixTranslation( 0.1f, 0.0f, 0.0f ) * Camera->getPose() ) );
if( key == 'D')
Camera->setPose( &(Ovgl::MatrixTranslation( -0.1f, 0.0f, 0.0f ) * Camera->getPose() ) );
}

int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
// Create Main Instance
Inst = new Ovgl::Instance( 0 );

// Create Window
Window = new Ovgl::Window( Inst, "Test");
Window->LockMouse(true);
Window->SetFullscreen( true );
Window->SetVSync( true );
Window->On_MouseMove = MouseMove;
Window->On_KeyDown = KeyDown;

// Create Render Target
RenderTarget = new Ovgl::RenderTarget(Inst, Window, &Ovgl::Vector4(0.0f, 0.0f, 0.999f, 0.999f), NULL);
RenderTarget->bloom = 4;
RenderTarget->motionBlur = true;
RenderTarget->multiSample = true;
RenderTarget->debugMode = false;

// Create Media Library
MediaLibrary = new Ovgl::MediaLibrary(Inst, "");

// Create empty scene
Scene = MediaLibrary->CreateScene();

// Add light to scene.
Light = Scene->CreateLight(&Ovgl::MatrixTranslation( -1.8f, 4.0f, -3.35f ), &Ovgl::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ));

// Add camera to scene
Camera = Scene->CreateCamera(&Ovgl::MatrixTranslation( 0.0f, 0.0f, 0.0f ));

// Set camera as view for render target
RenderTarget->view = Camera;

// Create cubemap texture
Texture1 = MediaLibrary->ImportCubeMap( "..\\media\\textures\\skybox\\front.png", "..\\media\\textures\\skybox\\back.png", "..\\media\\textures\\skybox\\top.png",
"..\\media\\textures\\skybox\\bottom.png", "..\\media\\textures\\skybox\\left.png", "..\\media\\textures\\skybox\\right.png");

// Create 2D texture
Texture2 = MediaLibrary->ImportTexture("..\\media\\textures\\test.jpg");

// Import mesh
Mesh = MediaLibrary->ImportFBX( "..\\media\\meshes\\test.fbx", false, true );

// Add object to scene
Object = Scene->CreateObject(Mesh, &Ovgl::MatrixTranslation( 0.0f, -5.0f, 0.0f ));
Object->materials[0]->setFSTexture("txDiffuse", Texture2);

// Set scene sky box
Scene->skybox = Texture1;


DWORD previousTime = timeGetTime();

// Main message loop
while( !g_Quit )
{
DWORD currentTime = timeGetTime();
DWORD elapsedTime = currentTime - previousTime;
Scene->Update(elapsedTime);
RenderTarget->Render();
Window->DoEvents();
previousTime = currentTime;
}

// Release all
delete Inst;
return 0;
}



One design idea I really want some opinions on is where rects which use values below one use relative instead of absolute positions. Example: { 0, 0, 0.5, 0.5} = top left quarter of screen. Another example of absolute positioning: { 0, 0, 1024, 768} = full screen if screen is 1024x768

An example of this in action would be where I define my render target: RenderTarget = new Ovgl::RenderTarget(Inst, Window, &Ovgl::Vector4(0.0f, 0.0f, 0.999f, 0.999f), NULL);
Advertisement
Note: I am not a professional programmer, nor have I completed my game library. Everything below is my opinion and may very well be wrong.

1) Relative screen positions are better than absolute, because screen sizes can change.

2) Your MediaLibrary should seamlessly handle the directory lookup; looking in the textures directory for textures; looking in the meshes directory for meshes and scanning elsewhere as directed if not found there. You should just need to give it a file name.

3) Relevantly, your MediaLibrary should also seamlessly handle both existance and lack of a file extension in the name given.

4) Why not have a "Model" subclass of "Object" that has initialization functions that can handle common mesh-related operations? Or, if "Object" is your "Model" class, put common initialization functions there.

That's about all, I think. If this is your first attempt, it looks a lot better than mine. :)

Note: I am not a professional programmer, nor have I completed my game library. Everything below is my opinion and may very well be wrong.

1) Relative screen positions are better than absolute, because screen sizes can change.

2) Your MediaLibrary should seamlessly handle the directory lookup; looking in the textures directory for textures; looking in the meshes directory for meshes and scanning elsewhere as directed if not found there. You should just need to give it a file name.

3) Relevantly, your MediaLibrary should also seamlessly handle both existance and lack of a file extension in the name given.

4) Why not have a "Model" subclass of "Object" that has initialization functions that can handle common mesh-related operations? Or, if "Object" is your "Model" class, put common initialization functions there.

That's about all, I think. If this is your first attempt, it looks a lot better than mine. smile.png


1) The idea is to offer both relative and absolute with the same amount of information. Sometimes you may not want a control panel to stretch when the resolution is changed.

2) This is a general purpose library. There is no absolute media directory.

3) Well that's something I can add in for convenience but it's not something I consider high priority.

4) I honestly don't understand this one?
[color=#000088]void[color=#000000] [color=#660066]MouseMove[color=#666600]([color=#000088]long[color=#000000] x[color=#666600],[color=#000000] [color=#000088]long[color=#000000] y[color=#666600])....
[color=#000088]void[color=#000000] [color=#660066]KeyDown[color=#666600]([color=#000088]char[color=#000000] key[color=#666600])...... you'll need to handle KeyUp too


From your engine point of view, any input device should just generate events, which may be linked to certain action.
For example you could use left/right arrow key to generate "rotate_x" event (same as moving mouse in x direction) and pass that event to your camera.


[color=#000000] [color=#660066]RenderTarget[color=#000000] [color=#666600]=[color=#000000] [color=#000088]new[color=#000000] [color=#660066]Ovgl[color=#666600]::[color=#660066]RenderTarget[color=#666600]([color=#660066]Inst[color=#666600],[color=#000000] [color=#660066]Window[color=#666600],[color=#000000] [color=#666600]&[color=#660066]Ovgl[color=#666600]::[color=#660066]Vector4[color=#666600]([color=#006666]0.0f[color=#666600],[color=#000000] [color=#006666]0.0f[color=#666600],[color=#000000] [color=#006666]0.999f[color=#666600],[color=#000000] [color=#006666]0.999f[color=#666600]),[color=#000000] NULL[color=#666600]);
[color=#000000] [color=#660066]RenderTarget[color=#666600]->[color=#000000]bloom [color=#666600]=[color=#000000] [color=#006666]4[color=#666600];
[color=#000000] [color=#660066]RenderTarget[color=#666600]->[color=#000000]motionBlur [color=#666600]=[color=#000000] [color=#000088]true[color=#666600];
[color=#000000] [color=#660066]RenderTarget[color=#666600]->[color=#000000]multiSample [color=#666600]=[color=#000000] [color=#000088]true[color=#666600];


In my opinion bloom, motionblur are hardly properties of RenderTarget. Bloom and motion blur are something you do usually in post process.
Also, a rendertarget and a texture are rather similar in concepts as you may bind a render target as a texture for rendering.

Cheers!
The sample follows the tradition of sample programs by beginning with a big block of global variables -- not sure if this is because it's just a sample, or if this is indicative of expected usage wink.png tongue.png

[font=courier new,courier,monospace]KeyDown[/font] isn't framerate independant, which like the above, might be because it's just a sample, or it might be indicative of the quality of the engine...

I would prefer the initial object creation to look like regular C++ local variables, and the API to be uniform in it's methods of object creation instead of some being [font=courier new,courier,monospace]new[/font]'ed and some being [font=courier new,courier,monospace]->Create*[/font]'ed. e.g.Ovgl::Instance Inst;
Ovgl::Window Window( Inst, "Test");
Ovgl::RenderTarget RenderTarget(Inst, Window, Ovgl::Vector4(0.0f, 0.0f, 0.999f, 0.999f), NULL);
Ovgl::MediaLibrary MediaLibrary(Inst, "");
Ovgl::Scene Scene(MediaLibrary);
Ovgl::Light Light(Scene, Ovgl::MatrixTranslation( -1.8f, 4.0f, -3.35f ), Ovgl::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ));


I'm confused by the Vector4 parameters all being passed by pointer-to-temporary, I'd prefer them to be being passed by const-reference.

I'd prefer the engine to implement a timer, rather than mixing in some Win32 code here: [font=courier new,courier,monospace]DWORD previousTime = timeGetTime();[/font]

This: [font=courier new,courier,monospace]delete Inst; // Release all[/font]
...is very non-obvious behaviour from the code that has come before. Why don't I also have to write [font=courier new,courier,monospace]delete MediaLibrary;[/font] or [font=courier new,courier,monospace]Scene->ReleaseLight(Light)[/font], etc?
Can I release those sub-resources without deleting everything? If I do write [font=courier new,courier,monospace]delete MediaLibrary;[/font] will [font=courier new,courier,monospace]Inst[/font] also (double) delete it later?

[quote name='Narf the Mouse' timestamp='1326672091' post='4903078']
Note: I am not a professional programmer, nor have I completed my game library. Everything below is my opinion and may very well be wrong.

1) Relative screen positions are better than absolute, because screen sizes can change.

2) Your MediaLibrary should seamlessly handle the directory lookup; looking in the textures directory for textures; looking in the meshes directory for meshes and scanning elsewhere as directed if not found there. You should just need to give it a file name.

3) Relevantly, your MediaLibrary should also seamlessly handle both existance and lack of a file extension in the name given.

4) Why not have a "Model" subclass of "Object" that has initialization functions that can handle common mesh-related operations? Or, if "Object" is your "Model" class, put common initialization functions there.

That's about all, I think. If this is your first attempt, it looks a lot better than mine. smile.png


1) The idea is to offer both relative and absolute with the same amount of information. Sometimes you may not want a control panel to stretch when the resolution is changed.

2) This is a general purpose library. There is no absolute media directory.

3) Well that's something I can add in for convenience but it's not something I consider high priority.

4) I honestly don't understand this one?
[/quote]
1) Makes sense.

2) Why not, then, allow the current media directories to be set by the programmer?

3) Fair enough. It is rather minor.

4) Looking at it when I'm more awake, I'm not sure what I was talking about, either. I think part of it is simple uncertainty over whether "Object" is a base class for 3D objects in your code, or whether it only reperesents models. If the first, a dedicated model class would be suggested. If the second, there's no point here. :)

The sample follows the tradition of sample programs by beginning with a big block of global variables -- not sure if this is because it's just a sample, or if this is indicative of expected usage wink.png tongue.png

[font=courier new,courier,monospace]KeyDown[/font] isn't framerate independant, which like the above, might be because it's just a sample, or it might be indicative of the quality of the engine...

I would prefer the initial object creation to look like regular C++ local variables, and the API to be uniform in it's methods of object creation instead of some being [font=courier new,courier,monospace]new[/font]'ed and some being [font=courier new,courier,monospace]->Create*[/font]'ed. e.g.Ovgl::Instance Inst;
Ovgl::Window Window( Inst, "Test");
Ovgl::RenderTarget RenderTarget(Inst, Window, Ovgl::Vector4(0.0f, 0.0f, 0.999f, 0.999f), NULL);
Ovgl::MediaLibrary MediaLibrary(Inst, "");
Ovgl::Scene Scene(MediaLibrary);
Ovgl::Light Light(Scene, Ovgl::MatrixTranslation( -1.8f, 4.0f, -3.35f ), Ovgl::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ));


I'm confused by the Vector4 parameters all being passed by pointer-to-temporary, I'd prefer them to be being passed by const-reference.

I'd prefer the engine to implement a timer, rather than mixing in some Win32 code here: [font=courier new,courier,monospace]DWORD previousTime = timeGetTime();[/font]

This: [font=courier new,courier,monospace]delete Inst; // Release all[/font]
...is very non-obvious behaviour from the code that has come before. Why don't I also have to write [font=courier new,courier,monospace]delete MediaLibrary;[/font] or [font=courier new,courier,monospace]Scene->ReleaseLight(Light)[/font], etc?
Can I release those sub-resources without deleting everything? If I do write [font=courier new,courier,monospace]delete MediaLibrary;[/font] will [font=courier new,courier,monospace]Inst[/font] also (double) delete it later?


I agree with the const-references instead of pointers. I'm not sure why I've been using pointers. I also agree with the implementation of a timer within the library. As for deleting of instances. Classes constructed from an instance are very intertwined with that instance. Deletion of an instance means the destruction of all classes it owns even if I didn't delete those classes. However, one can delete child classes independent of the instance but behind the scenes references to the child classes are being cleared from the instance.

4) Looking at it when I'm more awake, I'm not sure what I was talking about, either. I think part of it is simple uncertainty over whether "Object" is a base class for 3D objects in your code, or whether it only reperesents models. If the first, a dedicated model class would be suggested. If the second, there's no point here. smile.png


Objects are 3d objects within the scene and I do indeed have an interdependent model class which is named "Mesh" but perhaps model would me a better name since there is much more information inside the mesh class than just mesh information..

This topic is closed to new replies.

Advertisement