However irrlicht is very slow to scale the render, you should get 3000 fps or more in 128x128 with burning video.
ddraw example:
https://drive.google.com/file/d/1bzO6fn ... sp=sharing
Code: Select all
/** Example 014 Win32 Window
This example only runs under MS Windows and demonstrates that Irrlicht can
render inside a win32 window. MFC and .NET Windows.Forms windows are possible,
too.
In the beginning, we create a windows window using the windows API. I'm not
going to explain this code, because it is windows specific. See the MSDN or a
windows book for details.
*/
#include <irrlicht.h>
#ifndef _IRR_WINDOWS_
#error Windows only example
#else
#include <windows.h> // this example only runs with windows
#include <iostream>
#include <cstdio> // for snprintf
#include "driverChoice.h"
using namespace irr;
#pragma comment(lib, "irrlicht.lib")
HWND hOKButton;
HWND hFpsText; // Handle FPS text
HWND hWnd;
static LRESULT CALLBACK CustomWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
HWND hwndCtl = (HWND)lParam;
int code = HIWORD(wParam);
if (hwndCtl == hOKButton)
{
DestroyWindow(hWnd);
PostQuitMessage(0);
return 0;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
/*
Now ask for the driver and create the Windows specific window.
*/
int main()
{
// ask user for driver
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
if (driverType==video::EDT_COUNT)
return 1;
printf("Select the render window (some dead window may exist too):\n"\
" (a) Window with button (via CreationParam)\n"\
" (b) Window with button (via beginScene)\n"\
" (c) Own Irrlicht window (default behavior)\n"\
" (otherKey) exit\n\n");
char key;
std::cin >> key;
if (key != 'a' && key != 'b' && key != 'c')
return 1;
HINSTANCE hInstance = 0;
// create dialog
const char* Win32ClassName = "CIrrlichtWindowsTestDialog";
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)CustomWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = DLGWINDOWEXTRA;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wcex.lpszMenuName = 0;
wcex.lpszClassName = Win32ClassName;
wcex.hIconSm = 0;
RegisterClassEx(&wcex);
DWORD style = WS_SYSMENU | WS_BORDER | WS_CAPTION |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX;
int windowWidth = 440;
int windowHeight = 380;
hWnd = CreateWindow( Win32ClassName, "Irrlicht Win32 window example",
style, 100, 100, windowWidth, windowHeight,
NULL, NULL, hInstance, NULL);
RECT clientRect;
GetClientRect(hWnd, &clientRect);
windowWidth = clientRect.right;
windowHeight = clientRect.bottom;
// create ok button
hOKButton = CreateWindow("BUTTON", "OK - Close", WS_CHILD | WS_VISIBLE | BS_TEXT,
windowWidth - 160, windowHeight - 40, 150, 30, hWnd, NULL, hInstance, NULL);
// create some text
CreateWindow("STATIC", "This is Irrlicht running inside a standard Win32 window.\n"\
"Also mixing with MFC and .NET Windows.Forms is possible.",
WS_CHILD | WS_VISIBLE, 20, 20, 400, 40, hWnd, NULL, hInstance, NULL);
// fps text
hFpsText = CreateWindow("STATIC", "FPS: 0", WS_CHILD | WS_VISIBLE,
windowWidth - 160, windowHeight - 70, 150, 20, hWnd, NULL, hInstance, NULL);
// create window to put irrlicht in
HWND hIrrlichtWindow = CreateWindow("BUTTON", "",
WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
50, 80, 128, 128, hWnd, NULL, hInstance, NULL);
video::SExposedVideoData videodata((key=='b')?hIrrlichtWindow:0);
/*
So now that we have some window, we can create an Irrlicht device
inside of it. We use Irrlicht createEx() function for this. We only
need the handle (HWND) to that window, set it as windowsID parameter
and start up the engine as usual. That's it.
*/
// create irrlicht device in the button window
irr::SIrrlichtCreationParameters param;
param.DriverType = driverType;
if (key=='a')
param.WindowId = reinterpret_cast<void*>(hIrrlichtWindow);
irr::IrrlichtDevice* device = irr::createDeviceEx(param);
if (!device)
return 1;
// setup a simple 3d scene
irr::scene::ISceneManager* smgr = device->getSceneManager();
video::IVideoDriver* driver = device->getVideoDriver();
if (driverType==video::EDT_OPENGL)
{
HDC HDc=GetDC(hIrrlichtWindow);
PIXELFORMATDESCRIPTOR pfd={0};
pfd.nSize=sizeof(PIXELFORMATDESCRIPTOR);
int pf = GetPixelFormat(HDc);
DescribePixelFormat(HDc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.cDepthBits=16;
pf = ChoosePixelFormat(HDc, &pfd);
SetPixelFormat(HDc, pf, &pfd);
videodata.OpenGLWin32.HDc = HDc;
videodata.OpenGLWin32.HRc=wglCreateContext(HDc);
wglShareLists((HGLRC)driver->getExposedVideoData().OpenGLWin32.HRc, (HGLRC)videodata.OpenGLWin32.HRc);
}
scene::ICameraSceneNode* cam = smgr->addCameraSceneNode();
cam->setTarget(core::vector3df(0,0,0));
scene::ISceneNodeAnimator* anim =
smgr->createFlyCircleAnimator(core::vector3df(0,15,0), 30.0f);
cam->addAnimator(anim);
anim->drop();
scene::ISceneNode* cube = smgr->addCubeSceneNode(20);
cube->setMaterialFlag( video::EMF_LIGHTING, false );
/*
cube->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
cube->setMaterialTexture(1, driver->getTexture("../../media/water.jpg"));
cube->setMaterialFlag( video::EMF_LIGHTING, false );
cube->setMaterialType( video::EMT_REFLECTION_2_LAYER );
smgr->addSkyBoxSceneNode(
driver->getTexture("../../media/irrlicht2_up.jpg"),
driver->getTexture("../../media/irrlicht2_dn.jpg"),
driver->getTexture("../../media/irrlicht2_lf.jpg"),
driver->getTexture("../../media/irrlicht2_rt.jpg"),
driver->getTexture("../../media/irrlicht2_ft.jpg"),
driver->getTexture("../../media/irrlicht2_bk.jpg"));
// show and execute dialog*/
ShowWindow(hWnd , SW_SHOW);
UpdateWindow(hWnd);
// do message queue
/*
Now the only thing missing is the drawing loop using
IrrlichtDevice::run(). We do this as usual. But instead of this, there
is another possibility: You can also simply use your own message loop
using GetMessage, DispatchMessage and whatever. Calling
Device->run() will cause Irrlicht to dispatch messages internally too.
You need not call Device->run() if you want to do your own message
dispatcher loop, but Irrlicht will not be able to fetch user input
then and you have to do it on your own using the window messages,
DirectInput, or whatever.
*/
while (device->run())
{
driver->beginScene(true, true, 0, videodata);
smgr->drawAll();
driver->endScene();
// Update FPS every second
static u32 lastFpsUpdate = 0;
u32 now = device->getTimer()->getTime();
if (now - lastFpsUpdate > 1000)
{
lastFpsUpdate = now;
s32 fps = driver->getFPS();
char fpsStr[64];
snprintf(fpsStr, sizeof(fpsStr), "FPS: %d", fps);
SetWindowTextA(hFpsText, fpsStr);
}
}
/*
The alternative, own message dispatching loop without Device->run()
would look like this:
*/
/*MSG msg;
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
}
// advance virtual time
device->getTimer()->tick();
// draw engine picture
driver->beginScene(true, true, 0, (key=='c')?hIrrlichtWindow:0);
smgr->drawAll();
driver->endScene();
}*/
device->closeDevice();
device->drop();
return 0;
}
#endif // if windows
/*
That's it, Irrlicht now runs in your own windows window.
**/Code: Select all
#include <irrlicht.h>
using namespace irr;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
// Window settings
const u32 WINDOW_WIDTH = 640;
const u32 WINDOW_HEIGHT = 480;
// Render texture settings (virtual resolution)
const u32 RENDER_WIDTH = 128; // Width of the render target texture
const u32 RENDER_HEIGHT = 128; // Height of the render target texture
/**
* Manages a render-to-texture (RTT) system.
* Handles creating the render target, rendering to it, and then drawing the
* resulting texture onto the screen with proper aspect ratio and centering.
*/
class RenderTextureManager {
private:
IrrlichtDevice* device;
video::IVideoDriver* driver;
video::ITexture* renderTexture; // The off-screen render target
u32 renderWidth;
u32 renderHeight;
f32 aspectRatio; // Calculated as width/height
public:
/**
* Constructor.
* @param dev Pointer to the Irrlicht device.
* @param width Desired width of the render texture.
* @param height Desired height of the render texture.
*/
RenderTextureManager(IrrlichtDevice* dev, u32 width, u32 height)
: device(dev), renderWidth(width), renderHeight(height) {
driver = device->getVideoDriver();
// Compute aspect ratio for later scaling
aspectRatio = (f32)renderWidth / (f32)renderHeight;
// Create a render target texture with the specified dimensions
renderTexture = driver->addRenderTargetTexture(
core::dimension2d<u32>(renderWidth, renderHeight), "RTT");
}
/**
* Destructor. Cleans up the render target texture.
*/
~RenderTextureManager() {
if (renderTexture) {
driver->removeTexture(renderTexture);
}
}
/**
* Sets the render target to the internal texture and clears it.
* Also forces the viewport to exactly match the render texture size.
* @param clearColor Background color used when clearing the texture.
*/
void beginRenderToTexture(const video::SColor& clearColor = video::SColor(255, 100, 101, 140)) {
driver->setRenderTarget(renderTexture, true, true, clearColor);
// CRITICAL: the viewport must be set to the exact dimensions of the render target.
driver->setViewPort(core::rect<s32>(0, 0, renderWidth, renderHeight));
}
/**
* Restores the render target to the primary screen (backbuffer).
* Also resets the viewport to cover the whole window.
*/
void endRenderToTexture() {
driver->setRenderTarget(0); // Switch back to main screen
// Restore full screen viewport
core::dimension2d<u32> screenSize = driver->getScreenSize();
driver->setViewPort(core::rect<s32>(0, 0, screenSize.Width, screenSize.Height));
}
/**
* Draws the render texture onto the screen.
* The image is scaled to fit the screen while preserving its aspect ratio.
*/
void drawToScreen() {
core::dimension2d<u32> screenSize = driver->getScreenSize();
// Compute destination size that maintains the original aspect ratio
u32 destHeight = screenSize.Height;
u32 destWidth = (u32)(destHeight * aspectRatio);
// If the computed width exceeds the screen width, recalculate using width as base
if (destWidth > screenSize.Width) {
destWidth = screenSize.Width;
destHeight = (u32)(destWidth / aspectRatio);
}
// Center the image on screen
s32 destX = (screenSize.Width - destWidth) / 2;
s32 destY = (screenSize.Height - destHeight) / 2;
// Draw the rendered texture onto the screen, scaled and centered
driver->draw2DImage(renderTexture,
core::rect<s32>(destX, destY, destX + destWidth, destY + destHeight),
core::rect<s32>(0, 0, renderWidth, renderHeight),
0, 0, true);
}
// Getters
u32 getRenderWidth() const { return renderWidth; }
u32 getRenderHeight() const { return renderHeight; }
f32 getAspectRatio() const { return aspectRatio; }
video::ITexture* getRenderTexture() const { return renderTexture; }
void setRenderSize(u32 width, u32 height) {
if (renderTexture) {
driver->removeTexture(renderTexture);
}
renderWidth = width;
renderHeight = height;
aspectRatio = (f32)width / (f32)height;
renderTexture = driver->addRenderTargetTexture(
core::dimension2d<u32>(width, height), "RTT");
}
};
int main() {
// Create Irrlicht Device
IrrlichtDevice* device = createDevice(video::EDT_DIRECT3D9,
core::dimension2d<u32>(WINDOW_WIDTH, WINDOW_HEIGHT),
16, false, false, false, 0);
if (!device) return 1;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* guienv = device->getGUIEnvironment();
// Extra scope to control RenderTextureManager's lifetime
{
RenderTextureManager rtManager(device, RENDER_WIDTH, RENDER_HEIGHT);
// Setup FPS Camera
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
camera->setPosition(core::vector3df(0, 0, -80));
camera->setAspectRatio(rtManager.getAspectRatio());
camera->setFOV(53.4f * core::DEGTORAD);
// Simple Scene: A cube
scene::ISceneNode* cube1 = smgr->addCubeSceneNode(15);
if (cube1) {
cube1->setPosition(core::vector3df(0, 0, 0));
cube1->setMaterialFlag(video::EMF_LIGHTING, false);
}
gui::IGUIFont* font = guienv->getBuiltInFont();
core::stringw infoText;
device->setWindowCaption(L"Configurable Render to Texture - FPS Counter");
s32 lastFPS = -1;
// Main rendering loop
while (device->run()) {
if (device->isWindowActive()) {
camera->setAspectRatio(rtManager.getAspectRatio());
// 1. Render scene to the small texture
rtManager.beginRenderToTexture();
smgr->drawAll();
rtManager.endRenderToTexture();
// 2. Render the texture and UI to the screen
driver->beginScene(true, true, video::SColor(255, 0, 0, 0));
rtManager.drawToScreen();
// Get current FPS
s32 fps = driver->getFPS();
driver->endScene();
// Update window title only when FPS changes (optional)
if (lastFPS != fps) {
core::stringw title = L"Irrlicht RTT - FPS: ";
title += fps;
device->setWindowCaption(title.c_str());
lastFPS = fps;
}
}
}
} // rtManager destructor is called here, driver is still valid
device->drop(); // Safe to release device
return 0;
}And it's not that irrlicht is slower, in fact it is faster, it just slows down when scaling the render.
I really want to use burningvideo, render at 128x128, scale with a trilinear filter, but this stops me completely, if I get 4000 or 5000 fps at 128x128, I would expect about 800 or 900 fps when scaling at almost any resolution






