tutorial_nel_1 - ryzom/ryzomcore GitHub Wiki


title: Tutorial NeL Part 1 description: published: true date: 2023-03-20T19:15:03.525Z tags: editor: markdown dateCreated: 2023-03-18T01:59:31.723Z

In this tutorial, we will guide you through setting up a personal NeL project, creating an initial main.cpp file, configuring CMake, and initializing the NeL driver to open up a blank window with a basic game loop.

Get the Ryzom Core Repository

First, clone the Ryzom Core repository from GitHub:

git clone https://github.com/ryzom/ryzomcore.git

Create Your Personal Project

Inside the personal folder, create a new file named main.cpp. This file will serve as the entry point for your project.

#include <nel/misc/types_nl.h>
#include <nel/misc/app_context.h>
#include <nel/misc/debug.h>

using namespace std;
using namespace NLMISC;

// Main game class
class CMyGame
{
public:
	CMyGame();
	~CMyGame();
	void run();

private:
	// ...
};

// Initialize game resources
CMyGame::CMyGame()
{
	// Initialize the NeL driver, and other required components here
	// ...
}

// Release game resources
CMyGame::~CMyGame()
{
	// Release resources here
	// ...
}

// Main loop
void CMyGame::run()
{
	// Implement the main loop here
	// ...
}

// Main function
int main(int argc, char *argv[])
{
	// Create the application context
	CApplicationContext applicationContext;

	// Run the game
	CMyGame myGame;
	myGame.run();

	return EXIT_SUCCESS;
}

Add a CMakeLists.txt file with the following contents.

FILE(GLOB SRCS *.cpp)
FILE(GLOB HDRS *.h)
FILE(GLOB RECS *.rc)

SOURCE_GROUP("" FILES ${SRCS} ${HDRS} ${RECS})
ADD_EXECUTABLE(my_game ${SRCS} ${HDRS} ${RECS})

TARGET_LINK_LIBRARIES(my_game nelmisc nel3d nelsound)
NL_DEFAULT_PROPS(my_game "My Game")
NL_ADD_RUNTIME_FLAGS(my_game)

INSTALL(TARGETS my_game RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT personal)

Configure CMake

To configure CMake, create a build directory under the ryzomcore repository folder.

mkdir build
cd build

Run CMake with the project folder, tools, samples, and Assimp set to ON, and MFC, Qt, Ryzom, NeLNS, and Snowballs set to OFF.

Windows

The CMAKE_PREFIX_PATH option should point to your externals package on Windows. With the following command, we'll generate a Visual Studio 2022 project.

cmake -G "Visual Studio 17 2022" -DWITH_PERSONAL=ON -DWITH_NEL_TOOLS=ON -DWITH_NEL_SAMPLES=ON -DWITH_ASSIMP=ON -DWITH_NEL_TESTS=OFF -DWITH_MFC=OFF -DWITH_QT=OFF -DWITH_RYZOM=OFF -DWITH_NELNS=OFF -DWITH_SNOWBALLS=OFF -DWITH_EXTERNAL=OFF -DWITH_STATIC_LIBXML2=OFF "-DCMAKE_PREFIX_PATH=C:\2022q2_external_v143_x64\zlib;C:\2022q2_external_v143_x64\openssl;C:\2022q2_external_v143_x64\curl;C:\2022q2_external_v143_x64\libjpeg;C:\2022q2_external_v143_x64\libpng;C:\2022q2_external_v143_x64\libxml2;C:\2022q2_external_v143_x64\freetype;C:\2022q2_external_v143_x64\squish;C:\2022q2_external_v143_x64\ogg;C:\2022q2_external_v143_x64\vorbis;C:\2022q2_external_v143_x64\ffmpeg;C:\2022q2_external_v143_x64\openal-soft;C:\2022q2_external_v143_x64\lua;C:\2022q2_external_v143_x64\luabind;C:\2022q2_external_v143_x64\ffmpeg;C:\2022q2_external_v143_x64\mariadb-connector-c;C:\2022q2_external_v143_x64\assimp;C:\2022q2_external_v143_x64\qt5;C:\2022q2_external_v143_x64\boost" ..

Open the RyzomCore.sln file in the build folder. Right click on the "My Game" project, click on Set as Startup Project. Then right click again, and open the Properties panel. Under the Debugging header, open the <Edit> window for the Environment option, and fill in the directories containing the binaries from the externals package. Then push OK and save the project. This way the executable will find all the libraries without having to copy them manually.

PATH=C:\2022q2_external_v143_x64\zlib\bin;C:\2022q2_external_v143_x64\curl\bin;C:\2022q2_external_v143_x64\openssl\bin;C:\2022q2_external_v143_x64\libjpeg\bin;C:\2022q2_external_v143_x64\libpng\bin;C:\2022q2_external_v143_x64\libxml2\bin;C:\2022q2_external_v143_x64\freetype\bin;C:\2022q2_external_v143_x64\ogg\bin;C:\2022q2_external_v143_x64\vorbis\bin;C:\2022q2_external_v143_x64\openal-soft\bin;C:\2022q2_external_v143_x64\lua\bin;C:\2022q2_external_v143_x64\luabind\bin;C:\2022q2_external_v143_x64\mariadb-connector-c\bin;C:\2022q2_external_v143_x64\assimp\bin;C:\2022q2_external_v143_x64\ffmpeg\bin;C:\2022q2_external_v143_x64\gles\bin;C:\2022q2_external_v143_x64\msquic\bin;C:\2022q2_external_v143_x64\protobuf\bin;C:\2022q2_external_v143_x64\squish\bin;C:\2022q2_external_v143_x64\qt5\bin;C:\2022q2_external_v143_x64\qt5\plugins;%PATH%
QT_PLUGIN_PATH=C:\2022q2_external_v143_x64\qt5\plugins

Switch to the Debug build target, and hit the Build Solution button to build your project. This might take a while!

Linux

On Linux distributions, the externals are installed through the package manager, and the CMAKE_PREFIX_PATH should be omitted. Here we'll use Ninja to build the project.

cmake -G "Ninja" -DWITH_PERSONAL=ON -DWITH_NEL_TOOLS=ON -DWITH_NEL_SAMPLES=ON -DWITH_ASSIMP=ON -DWITH_NEL_TESTS=OFF -DWITH_MFC=OFF -DWITH_QT=OFF -DWITH_RYZOM=OFF -DWITH_NELNS=OFF -DWITH_SNOWBALLS=OFF -DWITH_EXTERNAL=OFF -DWITH_STATIC_LIBXML2=OFF ..

To build the project, simply run Ninja from the build folder using the following command line.

ninja

Set up the graphics driver

Open the main.cpp file in your project folder and include the necessary headers:

#include <nel/3d/u_driver.h>

Add a member variable for the NL3D driver to the game class.

// Main game class
class CMyGame
{
public:
	CMyGame();
	~CMyGame();
	void run();

private:
  // Graphics driver
  NL3D::UDriver *m_Driver;
};

In the constructor method, initialize the graphics driver and open a blank window.

To initialize the graphics driver, use the createDriver() method of the NL3D::UDriver class. If the driver cannot be created, display an error message using the nlerror() method.

Then initialize the window using the setDisplay() method of the driver. You can pass in a NL3D::UDriver::CMode object to specify the dimensions and color depth of the window. You can also set the window title using the setWindowTitle() method of the driver.

CMyGame::CMyGame()
{
	// Create the graphics driver
	m_Driver = NL3D::UDriver::createDriver();
	if (!m_Driver)
	{
		nlerror("Failed to create driver");
		return;
	}

	// Initialize the window
	m_Driver->setDisplay(NL3D::UDriver::CMode(800, 600, 32));

	// Set the window title
	m_Driver->setWindowTitle(ucstring("My Game"));
}

In the destructor, release any resources used.

CMyGame::~CMyGame()
{
	// Release resources and delete the driver
	m_Driver->release();
	delete m_Driver;
}

Implement a basic game loop in the run() method.

This loop should repeat until the window is closed or the application is exited. You must check the isActive() method of the graphics driver to verify if the window still exists. In order for the window to receive event messages, such as user input, from the window manager, the events will be received using the pump() method on the EventServer of the driver.

Use the clearBuffers() method of the driver to clear the screen with a specified color, and swapBuffers() to display the updated screen.

void CMyGame::run()
{
	// Main game loop
	while (m_Driver->isActive())
	{
		// Update window messages
		m_Driver->EventServer.pump();

		// Clear the screen
		m_Driver->clearBuffers(NLMISC::CRGBA(0, 0, 128));
		m_Driver->swapBuffers();
	}
}

Now, compile and run your project. When running your project, you should see a blank window with the title "My Game". However, it will stay open when you try to close it.

Handle window events

To make the window close, you must register a listener for the relevant window event. Include the event listener header, and modify the game class to inherit from IEventListener. You'll also need a variable in your class to flag when the window is being closed. The release() call on the driver will actually close the window.

#include <nel/misc/event_listener.h>
class CMyGame : public IEventListener
{
public:
	CMyGame();
	~CMyGame();
	void run();

	virtual void operator()(const CEvent &event) NL_OVERRIDE;

private:
	// Graphics driver
	NL3D::UDriver *m_Driver;
	bool m_CloseWindow;
};

Implement the event handler for the window close message, and update the main loop to exit when the close event has been flagged.

// Handle events
void CMyGame::operator()(const CEvent &event)
{
	// Handle events
	if (event == EventCloseWindowId)
	{
		m_CloseWindow = true;
	}
}
void CMyGame::run()
{
	// Main game loop
	while (m_Driver->isActive() && !m_CloseWindow)
	{
		// ...
	}
}

Initialize the flag, and register the listener to handle the window close event.

CMyGame::CMyGame()
    : m_CloseWindow(false)
{
	// ...
 
	// Add event listeners
	m_Driver->EventServer.addListener(EventCloseWindowId, this);
 
	// ...
}

The window should now remain open until you close it manually.

Conclusion

By following this tutorial, you should have set up a personal NeL project, configured CMake, initialized the NeL 3D driver, opened a blank window, and implemented a basic game loop. You can now build upon this foundation to create more advanced functionality, such as rendering text and 3D shapes, in subsequent parts of the tutorial.

Here's the complete source of the tutorial project at this point.

#include <nel/misc/types_nl.h>
#include <nel/misc/app_context.h>
#include <nel/misc/event_listener.h>
#include <nel/misc/debug.h>
#include <nel/3d/u_driver.h>

using namespace std;
using namespace NLMISC;

// Main game class
class CMyGame : public IEventListener
{
public:
	CMyGame();
	~CMyGame();
	void run();

	virtual void operator()(const CEvent &event) NL_OVERRIDE;

private:
	// Graphics driver
	NL3D::UDriver *m_Driver;
	bool m_CloseWindow;
};

// Initialize game resources
CMyGame::CMyGame()
    : m_CloseWindow(false)
{
	// Create the graphics driver
	m_Driver = NL3D::UDriver::createDriver();
	if (!m_Driver)
	{
		nlerror("Failed to create driver");
		return;
	}

	// Add event listeners
	m_Driver->EventServer.addListener(EventCloseWindowId, this);

	// Initialize the window
	m_Driver->setDisplay(NL3D::UDriver::CMode(800, 600, 32));

	// Set the window title
	m_Driver->setWindowTitle(ucstring("My Game"));
}

// Release game resources
CMyGame::~CMyGame()
{
	// Release resources and delete the driver
	m_Driver->release();
	delete m_Driver;
}

// Main loop
void CMyGame::run()
{
	// Main game loop
	while (m_Driver->isActive() && !m_CloseWindow)
	{
		// Update window messages
		m_Driver->EventServer.pump();

		// Clear the screen
		m_Driver->clearBuffers(NLMISC::CRGBA(0, 0, 128));
		m_Driver->swapBuffers();
	}
}

// Handle events
void CMyGame::operator()(const CEvent &event)
{
	// Handle events
	if (event == EventCloseWindowId)
	{
		m_CloseWindow = true;
	}
}

// Main function
int main(int argc, char *argv[])
{
	// Create the application context
	CApplicationContext applicationContext;

	// Run the game
	CMyGame myGame;
	myGame.run();

	return EXIT_SUCCESS;
}
⚠️ **GitHub.com Fallback** ⚠️