In this part we will see how to create and render a custom node.
To create our custom node, we'll need to create a new class driver, because all fonctions to create an 3D object, to begin with nothing, are not implemented in UDriver as CDriverUser. UDriver and CDriverUser are user class of an IDriver instance.
Then them class don't implement we need, we going to create a new class name MDriver implementation of CDriverUser.
What do we need ? First MDriver must manage the Vertex Buffer and Index buffer. But we need to rendu them too.
If we look at IDriver class, we can see 3 interestings functions : activeVertexBuffer (CVertexBuffer &VB), activeIndexBuffer(CIndexBuffer &IB) and renderTriangles(CMaterial &mat, uint32 firstIndex, uint32 ntris). They return bool.
We have now :
file m_driver.h :
#ifndef M_DRIVER_H
#define M_DRIVER_H
#include <nel/3d/driver_user.h>
using namespace NL3D;
class MDriver : public NL3D::CDriverUser
{
public :
MDriver ();
virtual ~MDriver();
static MDriver *createDriver();
virtual bool activeVertexBuffer (CVertexBuffer &VB);
virtual bool activeIndexBuffer(CIndexBuffer &IB);
virtual bool renderTriangles(CMaterial &mat, uint32 firstIndex, uint32 ntris);
};
#endif // M_DRIVER_H
We only use IDriver instance.
file m_driver.cpp :
#include "../include/m_driver.h"
using namespace NLMISC;
using namespace NL3D;
MDriver::MDriver()
{
}
MDriver::~MDriver()
{
purgeMemory();
}
MDriver *MDriver::createDriver()
{
return new MDriver();
}
bool MDriver::activeVertexBuffer (CVertexBuffer &VB)
{
return _Driver->activeVertexBuffer (VB);
}
bool MDriver::activeIndexBuffer(CIndexBuffer &IB)
{
return _Driver->activeIndexBuffer(IB);
}
bool MDriver::renderTriangles(CMaterial &mat, uint32 firstIndex, uint32 ntris)
{
return _Driver->renderTriangles(mat, firstIndex, ntris);
}
We can now create our custom 3D node.
For this tutorial we going to create a 3D cube. The displayCube function will do it.
In file main.cpp we going to put only minimum code.
#include <nel/misc/path.h>
#include <nel/misc/file.h>
#include <nel/misc/common.h>
#include <nel/3d/u_scene.h>
#include <nel/3d/texture.h>
#include <nel/3d/texture_mem.h>
#include <nel/3d/u_light.h>
#include <nel/3d/u_camera.h>
#include <nel/3d/u_driver.h>
#include <nel/3d/u_instance.h>
#include "../include/m_driver.h"
using namespace NLMISC;
using namespace NL3D;
//We create an MDriver instance here because fonctions displayCube and main will need it.
MDriver *Driver = MDriver::createDriver();
//Create and render the cube
void displayCube()
{
//Material needed by the fonction of render triangles
CMaterial mat;
mat.initUnlit();
mat.setSrcBlend(CMaterial::srcalpha);
mat.setDstBlend(CMaterial::invsrcalpha);
mat.setColor(CRGBA(50,255,255,150)); //Set a color to the material
CVertexBuffer vb;
//Must determinate the format for vertex
//Later we'll see that we could add other informations as the color for exemple
vb.setVertexFormat (CVertexBuffer::PositionFlag);
vb.setNumVertices (8);
{
CVertexBufferReadWrite vba;
vb.lock(vba);
vba.setVertexCoord (0, CVector (0.0, 0.0, 0.0));
vba.setVertexCoord (1, CVector (0.2, 0.00, 0.0));
vba.setVertexCoord (2, CVector (0.2, 0.00, 0.2));
vba.setVertexCoord (3, CVector (0, 0.0, 0.2));
vba.setVertexCoord (4, CVector (0.0, 0.2, 0));
vba.setVertexCoord (5, CVector (0.20, 0.2, 0.0));
vba.setVertexCoord (6, CVector (0.2, 0.2, 0.20));
vba.setVertexCoord (7, CVector (0, 0.2, 0.20));
}
//Now we can set to active our vertex buffer
Driver->activeVertexBuffer(vb);
CIndexBuffer pbQuad1;
pbQuad1.setNumIndexes (36);
{
CIndexBufferReadWrite iba1;
pbQuad1.lock(iba1);
//With vertex we can now make some triangles for cube
iba1.setTri (0, 0, 1, 2); //front
iba1.setTri (3, 2, 3, 0); //front
iba1.setTri (6, 2, 1, 5); //right
iba1.setTri (9, 5, 6, 2); //right
iba1.setTri (12, 2, 7, 3); //top
iba1.setTri (15, 2, 6, 7); //top
iba1.setTri (18, 0, 4, 1); //bottom
iba1.setTri (21, 1, 4, 5); //bottom
iba1.setTri (24, 3, 4, 0); //left
iba1.setTri (27, 3, 7, 4); //left
iba1.setTri (30, 6, 5, 4); //behind
iba1.setTri (33, 4, 7, 6); //behind
}
//Active index buffer
Driver->activeIndexBuffer(pbQuad1);
//Render of all triangles of the cube
Driver->renderTriangles(mat, 0, pbQuad1.getNumIndexes()/3);
}
sint main(int argc, char **argv)
{
try
{
if (!Driver) throw 2;
// create a window in 800x600
Driver->setDisplay(NL3D::UDriver::CMode(800, 600, 32, true),true, false);
// set the title
Driver->setWindowTitle(ucstring("NeL shape viewer"));
// can use both dds and tga textures for shapes
CPath::remapExtension ("dds", "tga", true);
// Create a scene
NL3D::UScene *Scene = Driver->createScene(true);
if (!Scene) throw 4;
// create the camera
UCamera Camera = Scene->getCam();
if (Camera.empty()) throw 5;
Camera.setTransformMode (UTransformable::DirectMatrix);
Camera.setPerspective ((float)Pi/2.f, 1.33f, 0.1f, 1000);
// camera will look at entities
Camera.lookAt (CVector(0, -10.f, 0.f), CVector(0.f, 0.f, 0.f));
// main loop
while (Driver->isActive())
{
Driver->EventServer.pump();
// the background is black
Driver->clearBuffers(CRGBA(0, 0, 0));
//Display our cube
displayCube();
// show the scene
Driver->swapBuffers();
// escape will leave the program
if (Driver->AsyncListener.isKeyPushed(KeyESCAPE))
{
break;
}
// F3 will change the render mode
else if (Driver->AsyncListener.isKeyPushed(KeyF3))
{
NL3D::UDriver::TPolygonMode p = Driver->getPolygonMode();
p = NL3D::UDriver::TPolygonMode(((int)p+1)%3);
Driver->setPolygonMode(p);
}
}
// we are leaving the program
// delete the scene
Driver->deleteScene(Scene);
// release all textures and others elements
Driver->release();
// delete the driver
delete Driver;
}
catch(int a)
{
return a;
}
catch(...)
{
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
In this part you learn how to move the object and change the color of vertex.
You have create a cube you only see a rectangle because the cube don't move and it have no color to distinc face.
So we going to set up this.
For moving an object you need to modify it, to do this you can use matrix. When you have a matrix you can move, rotate and scale an 3d object.
You can create a matrix alone but if you want see modification of four object the driver must manage matrix too. So we'll add news functions to MDriver :
setupViewMatrix (const CMatrix &mtx) and setupModelMatrix(const CMatrix &mtx).
Add this to m_driver.h :
virtual void setupViewMatrix (const CMatrix &mtx);
virtual void setupModelMatrix(const CMatrix &mtx);
And this to m_driver.cpp :
void MDriver::setupViewMatrix (const CMatrix &mtx)
{
_Driver->setupViewMatrix (mtx);
}
void MDriver::setupModelMatrix(const CMatrix &mtx)
{
_Driver->setupModelMatrix(mtx);
}
Now you can add to your fonction displayCube :
CMatrix mtx;
mtx.identity();
Driver->setupViewMatrix (mtx);
Driver->setupModelMatrix (mtx);
But if you compile and run, nothing apend because you have not set mofication for matrix.
Try to add this between Driver->setupViewMatrix (mtx); and Driver->setupModelMatrix (mtx); :
mtx.translate(CVector(0.5,0.5,0.5));
_RotX +=0.005;
mtx.rotateX(_RotX );
mtx.rotateY(_RotY );
and this after MDriver *Driver = MDriver::createDriver(); :
float _RotX = 0;
float _RotY = 0;
Compile and run to see the result
The result need some color...
so modifify that :
vb.setVertexFormat (CVertexBuffer::PositionFlag);
vb.setNumVertices (8);
{
CVertexBufferReadWrite vba;
vb.lock(vba);
vba.setVertexCoord (0, CVector (0.0, 0.0, 0.0));
vba.setVertexCoord (1, CVector (0.2, 0.00, 0.0));
vba.setVertexCoord (2, CVector (0.2, 0.00, 0.2));
vba.setVertexCoord (3, CVector (0, 0.0, 0.2));
vba.setVertexCoord (4, CVector (0.0, 0.2, 0));
vba.setVertexCoord (5, CVector (0.20, 0.2, 0.0));
vba.setVertexCoord (6, CVector (0.2, 0.2, 0.20));
vba.setVertexCoord (7, CVector (0, 0.2, 0.20));
}
by that :
vb.setVertexFormat (CVertexBuffer::PositionFlag |CVertexBuffer::PrimaryColorFlag);
vb.setNumVertices (8);
{
CVertexBufferReadWrite vba;
vb.lock(vba);
vba.setVertexCoord (0, CVector (0.0, 0.0, 0.0));
vba.setColor(0, NLMISC::CRGBA (255,0,0));
vba.setVertexCoord (1, CVector (0.2, 0.00, 0.0));
vba.setColor(1, NLMISC::CRGBA (255,0,0));
vba.setVertexCoord (2, CVector (0.2, 0.00, 0.2));
vba.setColor(2, NLMISC::CRGBA (255,0,0));
vba.setVertexCoord (3, CVector (0, 0.0, 0.2));
vba.setColor(3, NLMISC::CRGBA (255,0,0));
vba.setVertexCoord (4, CVector (0.0, 0.2, 0));
vba.setColor(4, NLMISC::CRGBA (0,255,0));
vba.setVertexCoord (5, CVector (0.20, 0.2, 0.0));
vba.setColor(5, NLMISC::CRGBA (0,255,0));
vba.setVertexCoord (6, CVector (0.2, 0.2, 0.20));
vba.setColor(6, NLMISC::CRGBA (0,255,0));
vba.setVertexCoord (7, CVector (0, 0.2, 0.20));
vba.setColor(7,NLMISC::CRGBA (0,255,0));
}
It's ok now, but i think you would like to modify object with your keyboard now. So add this after the "else if" for KeyF3 :
else if (Driver->AsyncListener.isKeyPushed(KeyUP))
{
_RotX+=0.05;
}
else if (Driver->AsyncListener.isKeyPushed(KeyDOWN))
{
_RotX-=0.05;
}
else if (Driver->AsyncListener.isKeyPushed(KeyLEFT))
{
_RotY-=0.05;
}
else if (Driver->AsyncListener.isKeyPushed(KeyRIGHT))
{
_RotY+=0.05;
}
Add all key/transmormation that you want
all code for main.cpp
#include <nel/misc/path.h>
#include <nel/misc/file.h>
#include <nel/misc/common.h>
#include <nel/3d/u_scene.h>
#include <nel/3d/texture.h>
#include <nel/3d/texture_mem.h>
#include <nel/3d/u_light.h>
#include <nel/3d/u_camera.h>
#include <nel/3d/u_driver.h>
#include <nel/3d/u_instance.h>
#include "../include/m_driver.h"
using namespace NLMISC;
using namespace NL3D;
MDriver *Driver = MDriver::createDriver();
float _RotZ = 0;
float _RotY = 0;
float _RotX = 0;
void displayCube()
{
CMaterial mat;
mat.initUnlit();
mat.setSrcBlend(CMaterial::srcalpha);
mat.setDstBlend(CMaterial::invsrcalpha);
CVertexBuffer vb;
vb.setVertexFormat (CVertexBuffer::PositionFlag |CVertexBuffer::PrimaryColorFlag);
vb.setNumVertices (8);
{
CVertexBufferReadWrite vba;
vb.lock(vba);
// tri
vba.setVertexCoord (0, CVector (0.0, 0.0, 0.0));
vba.setColor(0, NLMISC::CRGBA (255,0,0));
vba.setVertexCoord (1, CVector (0.2, 0.00, 0.0));
vba.setColor(1, NLMISC::CRGBA (255,0,0));
vba.setVertexCoord (2, CVector (0.2, 0.00, 0.2));
vba.setColor(2, NLMISC::CRGBA (255,0,0));
vba.setVertexCoord (3, CVector (0, 0.0, 0.2));
vba.setColor(3, NLMISC::CRGBA (255,0,0));
vba.setVertexCoord (4, CVector (0.0, 0.2, 0));
vba.setColor(4, NLMISC::CRGBA (0,255,0));
vba.setVertexCoord (5, CVector (0.20, 0.2, 0.0));
vba.setColor(5, NLMISC::CRGBA (0,255,0));
vba.setVertexCoord (6, CVector (0.2, 0.2, 0.20));
vba.setColor(6, NLMISC::CRGBA (0,255,0));
vba.setVertexCoord (7, CVector (0, 0.2, 0.20));
vba.setColor(7,NLMISC::CRGBA (0,255,0));
}
Driver->activeVertexBuffer(vb);
CIndexBuffer pbQuad1;
pbQuad1.setNumIndexes (36);
{
CIndexBufferReadWrite iba1;
pbQuad1.lock(iba1);
iba1.setTri (0, 0, 1, 2); //front
iba1.setTri (3, 2, 3, 0); //front
iba1.setTri (6, 2, 1, 5); //right
iba1.setTri (9, 5, 6, 2); //right
iba1.setTri (12, 2, 7, 3); //top
iba1.setTri (15, 2, 6, 7); //top
iba1.setTri (18, 0, 4, 1); //bottom
iba1.setTri (21, 1, 4, 5); //bottom
iba1.setTri (24, 3, 4, 0); //left
iba1.setTri (27, 3, 7, 4); //left
iba1.setTri (30, 6, 5, 4); //behind
iba1.setTri (33, 4, 7, 6); //behind
}
CMatrix mtx;
mtx.identity();
Driver->setupViewMatrix (mtx);
mat.setColor(CRGBA(50,255,255,150));
mtx.translate(CVector(0.5,0.5,0.5));
mtx.rotateX(_RotX );
mtx.rotateY(_RotY );
Driver->setupModelMatrix (mtx);
Driver->activeIndexBuffer(pbQuad1);
Driver->renderTriangles(mat, 0, pbQuad1.getNumIndexes()/3);
}
sint main(int argc, char **argv)
{
try
{
// create OpenGL driver
//MDriver *Driver = MDriver::createDriver();
if (!Driver) throw 2;
// create a window in 800x600
Driver->setDisplay(NL3D::UDriver::CMode(800, 600, 32, true),true, false);
// set the title
Driver->setWindowTitle(ucstring("NeL shape viewer"));
// can use both dds and tga textures for shapes
CPath::remapExtension ("dds", "tga", true);
// Create a scene
NL3D::UScene *Scene = Driver->createScene(true);
if (!Scene) throw 4;
// create the camera
UCamera Camera = Scene->getCam();
if (Camera.empty()) throw 5;
Camera.setTransformMode (UTransformable::DirectMatrix);
Camera.setPerspective ((float)Pi/2.f, 1.33f, 0.1f, 1000);
// camera will look at entities
Camera.lookAt (CVector(0, -10.f, 0.f), CVector(0.f, 0.f, 0.f));
// main loop
while (Driver->isActive())
{
Driver->EventServer.pump();
// the background is black
Driver->clearBuffers(CRGBA(0, 0, 0));
displayCube();
// show the scene
Driver->swapBuffers();
// escape will leave the program
if (Driver->AsyncListener.isKeyPushed(KeyESCAPE))
{
break;
}
// F3 will change the render mode
else if (Driver->AsyncListener.isKeyPushed(KeyF3))
{
NL3D::UDriver::TPolygonMode p = Driver->getPolygonMode();
p = NL3D::UDriver::TPolygonMode(((int)p+1)%3);
Driver->setPolygonMode(p);
}
else if (Driver->AsyncListener.isKeyPushed(KeyUP))
{
_RotX+=0.05;
}
else if (Driver->AsyncListener.isKeyPushed(KeyDOWN))
{
_RotX-=0.05;
}
else if (Driver->AsyncListener.isKeyPushed(KeyLEFT))
{
_RotY-=0.05;
}
else if (Driver->AsyncListener.isKeyPushed(KeyRIGHT))
{
_RotY+=0.05;
}
}
// we are leaving the program
// delete the scene
Driver->deleteScene(Scene);
// release all textures and others elements
Driver->release();
// delete the driver
delete Driver;
}
catch(int a)
{
return a;
}
catch(...)
{
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}