Jump to content
  • entries
    943
  • comments
    5,899
  • views
    924,359

Some sample LE3 code


Josh

14,786 views

 Share

Here's some LE3 code for a simple program. The Graphics / Window stuff is not worked out 100%, and it's a little tricky because of the different operating systems and different kinds of windows.

 

I think we'll see a little more consistency across various languages with the LE3 syntax. It was suggested that the C syntax use the following scheme:

verb-class-noun

SetEntityPosition()
GetMaterialTexture()

I agree with this suggestion.

 

SetGraphicsDriver( OpenGLGraphicsDriver() );
CreateGraphics(1024,768,4);

World* world = CreateWorld();

//Load a shader
Shader* shader = LoadShader("Shaders/minimal.shader");

//Create a material;
Material* mat = CreateMaterial();    
mat->SetShader(shader);
mat->SetColor(1,0,0,1);

//Create a box;
Mesh* box = CreateMeshBox(1,1,1);
box->SetMaterial(mat);

Camera* camera = CreateCamera();
camera->SetClearColor( Vec4(0,1,0,1) );

box->SetPosition(0,0,-2,false);
float yaw = 0.0;

while (!window->Closed())
{        
   yaw++;
   box->SetRotation(yaw,0,0,false);
   camera->Render();
   window->Flip();
}

 Share

76 Comments


Recommended Comments



It's a little ugly right now. I have a "WindowDriver" and it creates a window.

 

The user may want a standalone window, either fullscreen or not, and that is pretty easy to handle. Where it gets messy is when they have a window of their own, like a panel in a GUI program. That part I have not worked out yet.

Link to comment

I would do it like this:

// Define objects
Graphics graphics;
World world;
Shader shader;
Material mat;
Mesh box;
Camera camera;

// Create graphics window
graphics.SetDriver( OpenGLGraphicsDriver() );
graphics.Create(1024,768,4);

world.Create();

// Load a shader
shader.Load("Shaders/minimal.shader");

// Create a material;
mat.Create();    
mat.SetShader(shader);
mat.SetColor(1,0,0,1);

// Create a box;
box.Create(1,1,1);
box.SetMaterial(mat);

camera.Create();
camera.SetClearColor( Vec4(0,1,0,1) );

box.SetPosition(0,0,-2,false);
float yaw = 0.0;

while (!window.Closed())
{        
   yaw++;
   box.SetRotation(yaw,0,0,false);
   camera.Render();
   window.Flip();
}

Link to comment

I would do it like this:

// Define objects
Graphics graphics;
World world;
Shader shader;
Material mat;
Mesh box;
Camera camera;

// Create graphics window
graphics.SetDriver( OpenGLGraphicsDriver() );
graphics.Create(1024,768,4);

world.Create();

// Load a shader
shader.Load("Shaders/minimal.shader");

// Create a material;
mat.Create();    
mat.SetShader(shader);
mat.SetColor(1,0,0,1);

// Create a box;
box.Create(1,1,1);
box.SetMaterial(mat);

camera.Create();
camera.SetClearColor( Vec4(0,1,0,1) );

box.SetPosition(0,0,-2,false);
float yaw = 0.0;

while (!window.Closed())
{        
   yaw++;
   box.SetRotation(yaw,0,0,false);
   camera.Render();
   window.Flip();
}

 

Yes, agreed. Thats better.

I would go even further but thats another story.

 

A simple way to implement the C++ version would be

to move the BMX-code into the LEO classes and we would

have a new C++ version, compatible with the old LEO and

also a bit more OOP oriented than the half-c++ that is suggested.

 

But thats up to Josh and what he thinks is best for all.

I just give my personal view of this, and now I'm not even

into the programming stuff since I started learning 3D modeling :)

Link to comment

Oh, you mean probably extreme OOP, with .Get/.Set style methods, like in C#:

// Define objects
Graphics graphics;
World world;
Mesh box;
Camera camera;

// Create graphics window
graphics.Driver.Set( OpenGLGraphicsDriver() );
graphics.Create(1024,768,4);

world.Create();

// Create a box;
box.Create(1,1,1);
box.Material.Shader.Load("Shaders/minimal.shader");
box.Material.Color.Set(1,0,0,1);

camera.Create();
camera.Color.SetClear( Vec4(0,1,0,1) );

box.Position.Set(0,0,-2,false);
float yaw = 0.0;

while (!window.Closed())
{        
   yaw++;
   box.Rotation.Set(yaw,0,0,false);
   camera.Render();
   window.Flip();
}

Link to comment

Oh, you mean probably extreme OOP, with .Get/.Set style methods, like in C#

Doing that increase the number of code that you must write, I would stay on your first way and just let us create or load entities from constructor instead of forcing to iuse .Create and .Load methods [in my opinion they are ugly :)] (if you don't write the library in C# eheh :)).

Link to comment

Doing that increase the number of code that you must write, I would stay on your first way and just let us create or load entities from constructor instead of forcing to iuse .Create and .Load methods [in my opinion they are ugly :)] (if you don't write the library in C# eheh :)).

 

That was exactly what I was thinking of.

Link to comment

They are all still missing the `window` variable definition. What is it? I'm against any sort of global variable creation by the engine like it seems to be.

Link to comment

They are all still missing the `window` variable definition. What is it? I'm against any sort of global variable creation by the engine like it seems to be.

Right now, it's doing something like this:

window = windowdriver->Create();

 

I haven't finalized how this will be set up, so I didn't include it.

 

I don't like the -> separator, but using object variables seems like an awful way to design things:

 

Mesh mesh;
if (!mesh.Load("mymesh.gmf")) Print("Failed to load mesh");
//The mesh failed to load, but it still exists...ummmm...

 

Versus this:

Mesh* mesh = LoadMesh("mymesh.gmf");
if (!mesh) Print("Failed to load mesh");

 

You'd also have a lot of problems interfacing with external languages if you don't use pointers.

Link to comment

There's also problems like this:

 

Camera* camera = CreateCamera()// returns an OpenGLCamera object if the OpenGL driver is used

//If the DirectX 11 driver is used, it returns a DirectX11Camera object

 

Camera camera; // just a base class camera; the user would have to explicitly declare an OpenGLCamera object, so their code will be different depending on what graphics driver they are using.

Link to comment

Roland and I talked and agreed the approach I am using is best, although he suggested more use of constructors instead of Create() functions.

Link to comment

There is nothing wrong with -> and Roland will tell you the same thing. It's part of using pointers to objects in C++. Everyone who knows C++ knows this. No use in trying to get around it with weird designs.

 

Mesh mesh;

if (!mesh.Load("mymesh.gmf")) Print("Failed to load mesh");//The mesh failed to load, but it still exists...ummmm...

 

I don't like this approach either, but it's not the worst. That object won't exist outside of the scope it was defined in. So if that was created in a function, it'll be destroyed when that function is finished, but yeah I prefer creating objects as pointers so they stick around outside of the method they were defined in, and I have control of when to release them.

 

About the camera you could do something like:

Graphics* gfx = new OpenGLDrivers();

// polymorphism tells gfx to use the OpenGLDrivers::CreateCamera() method
Camera* camera = gfx->CreateCamera();

 

Personally I would avoid normal C functions like CreateCamera() or CreateCube(). Seeing that seems like you really aren't in the OOP mindset yet. Should be:

 

// Entity being the base class, Mesh deriving from Entity, 
//and Box deriving from Mesh
Entity* box = new Box();
Mesh* box1 = new Box();
Box* box2 = new Box();

// GetPosition is shared by all Entity types so they all have access to it
Vec3 v = box->GetPosition();
v = box1->GetPosition();
v = box2->GetPosition();

Entity* mat = new Material();
Material* mat1 = new Material();

Link to comment

Graphics* gfx = new OpenGLDrivers();

// polymorphism tells gfx to use the OpenGLDrivers::CreateCamera() method
Camera* camera = gfx->CreateCamera();

Yep, that's exactly how it works. OpenGLGraphicsDriver->CreateCamera returns an OpenGLCamera, which is an extension of the Camera class.

 

Here's what I have implemented, as an alternative approach:

GraphicsDriver* graphicsdriver = new OpenGLGraphicsDriver;
SetGraphicsDriver(graphicsdriver);
camera = CreateCamera(); 
//alternatively, you could use graphicsdriver->CreateCamera()

 

For a true OO approach we should be doing something like this:

GraphicsDriver* graphicsdriver = new OpenGLGraphicsDriver;
World* world = graphicsdriver->CreateWorld();
world->CreatePivot();
world->LoadMesh();

But do you really want that? Sometimes it makes sense to call SetWorld() or SetGraphics() and then have it assumed that object is the one that gets used. At what point do we go from good design to just being pedantic?

 

What do you guys and girls think?

Link to comment

There is nothing wrong with -> and Roland will tell you the same thing. It's part of using pointers to objects in C++. Everyone who knows C++ knows this. No use in trying to get around it with weird designs.

 

 

 

I don't like this approach either, but it's not the worst. That object won't exist outside of the scope it was defined in. So if that was created in a function, it'll be destroyed when that function is finished, but yeah I prefer creating objects as pointers so they stick around outside of the method they were defined in, and I have control of when to release them.

 

About the camera you could do something like:

Graphics* gfx = new OpenGLDrivers();

// polymorphism tells gfx to use the OpenGLDrivers::CreateCamera() method
Camera* camera = gfx->CreateCamera();

 

Personally I would avoid normal C functions like CreateCamera() or CreateCube(). Seeing that seems like you really aren't in the OOP mindset yet. Should be:

 

// Entity being the base class, Mesh deriving from Entity, 
//and Box deriving from Mesh
Entity* box = new Box();
Mesh* box1 = new Box();
Box* box2 = new Box();

// GetPosition is shared by all Entity types so they all have access to it
Vec3 v = box->GetPosition();
v = box1->GetPosition();
v = box2->GetPosition();

Entity* mat = new Material();
Material* mat1 = new Material();

 

Haha Rick. :) Yes. That is exactly what I said.

Nothing wrong with pointers. You cant live without them sometimes.

So everything is Go..

This is a good sample of that.

Link to comment

GraphicsDriver* graphicsdriver = new OpenGLGraphicsDriver;

World* world = graphicsdriver->CreateWorld();

world->CreatePivot();

world->LoadMesh();

 

You can look at that a few different ways. I would rather pass in the world to the contructor for the entities instead of having those functions part of the world. Here you say, create this entity in this world. The other way yo are saying create this entity, and place it in this world.

 

World* world = new World(gfxDriver);

Entity* box = new Box(world);

 

The world shouldn't have CreateThis() or CreateThat(), they should just be added to a worlds collection of entities. The nice thing about that is we can now swap the same entity between worlds if a SetWorld() property was part of the Entity class. Not sure if that would cause issues though. If it doesn't, this would give us more control on things.

 

For me the idea of a "world" kind of messes things up because you now would have to pass it anytime you want to create an LE entity. I personally don't care about worlds and wish we wouldn't have to deal with them at all. Why do worlds even exist? Is it because of the deferred renderer? If so, isn't there a set number of worlds realistically used? Main, Foreground, Background? Would there be any other reasons to have us manage worlds? Each of these constructors could have an enum to specify what predefined world they should be created in:

 

Entity* box = new Box(WORLD_MAIN);

 

That's just my personal view, but I don't know the whole story on worlds.

Link to comment

Since LE3 renders things in separate layers, worlds are not really needed for anything anymore. The only reason you would want one is if you had two different "simulations" running that you don't want mixed up. So let's say you had an editor, and in one of the windows you had a model preview, and you just wanted that model and camera by themselves in one world. Well, that's a good case for still using a world class.

Link to comment

This is shaping up nicely. Very happy with this and yes ... nothing wrong with pointers. I thought Rick's example was a good one:

 

// Entity being the base class, Mesh deriving from Entity,  
//and Box deriving from Mesh 
Entity* box = new Box(); 
Mesh* box1 = new Box(); 
Box* box2 = new Box(); 

// GetPosition is shared by all Entity types so they all have access to it 
Vec3 v = box->GetPosition(); 
v = box1->GetPosition(); 
v = box2->GetPosition(); 

Entity* mat = new Material(); 
Material* mat1 = new Material();

Link to comment

Since LE3 renders things in separate layers, worlds are not really needed for anything anymore. The only reason you would want one is if you had two different "simulations" running that you don't want mixed up. So let's say you had an editor, and in one of the windows you had a model preview, and you just wanted that model and camera by themselves in one world. Well, that's a good case for still using a world class.

 

Then overload the ctor for the Entity class to either specify an actual world class, or not (and make a SetWorld() also if we want to specify). If someone wanted the functionality you are talking about then I don't see anything wrong with giving it to them but it's going to come at a cost of passing that world around if they need it. For everyone else not doing that, don't make us worry about making worlds and managing them at all.

 

The reasons you give above is valid, but it's most likely 5% of what anyone will really do. So don't cause issues for the other 95%, BUT still give the option to that 5% to be able to do it if they so choose.

 

If LE3 is using layers (which I like), in the ctor to these entities we should specify which layer we want it in I think.

 

 

Also (not related), is clipping going to be possible? I'm picturing something like in an RPG where you open up the character screen they normally have a model inside a window and that model is clipped inside that window. That would be cool if that was a little easier to do. I remember trying to do that and it being a pain without clipping areas.

Link to comment

I thought the demonstrated syntax was C, I wonder how you get classes in there Lumooja/Roland.

Besides, the "object.Load" approach is really bad, as Josh demonstrated.

 

Also, I also want to precise I would use pointers and not objects, but Josh beat me to that too.

Lastly, I don't know why you fear constructors, Lumooja. Setting the graphics properties after its creation implies that it exists but is empty, which is strange in my opinion.

 

Here's my ideal code syntax for C++, not C (I feel Josh's one is perfect for C).

Graphics* graphics;
World* world;
Mesh* box;
Camera* camera;

graphics = new Graphics(OpenGLGraphicsDriver());
graphics->Create(1024, 768, 4);

world = new World();

box = new Box(1, 1, 1); // Box : Mesh
box->GetMaterial()->SetShader(new Shader("Shaders/minimal.shader"));
box->GetMaterial()->SetColor(new Color(255, 0, 0, 255));
// Basically Color is a Vector4 represented as bytes

camera = new Camera();
camera->SetClearColor(new Color(0, 255, 0, 255));

box->SetPosition(0, 0, -2, false);

float yaw = 0.0f;

while (!window->IsClosed())
{        
   yaw++;
   box->SetRotation(yaw, 0, 0, false);

   camera->Render();
   window->Flip();
}

Link to comment

I'm having some problems with constructors. Some objects can fail to load, so obviously we can't do this:

Mesh* mesh = new Mesh("car.gmf");

Instead we do this:

Mesh* mesh = LoadMesh("car.gmf");

And it may return NULL.

 

So you may say, okay, we'll use LoadMesh and then if we create something we'll use the constructor. But sometimes creation can fail:

Graphics* graphics =  new Graphics(5000,7842215);
Texture* tex = new Texture(16384000,1024);

So it means either having an Initialize() class function, a "failedtocreate" attribute, or using constructors for some classes and Create functions for others, unless someone else has a good idea to solve this.

 

If a constructor could return NULL, that would be idea, but that is not possible.

Link to comment

try/catch is your friend. Throw an error. It's all the rage these days! It can be much better than plastering your code with if/null checks. If everything must work in a chunk of code, you surround it with 1 try/catch and boom, done.

Link to comment

That's an idea. It's a pretty fundamental change in design. Typically, you would code in such a way that your program can handle missing files, etc. :)

Link to comment

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...