Irrlicht 1.9.0: Opengl emulated vs Burnings video

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
Noiecity
Posts: 383
Joined: Wed Aug 23, 2023 7:22 pm
Contact:

Irrlicht 1.9.0: Opengl emulated vs Burnings video

Post by Noiecity »

One of the features that the irrlicht 1.9.0 version included is shadow volume with intervals, you could leave the shadow static or update it at intervals, or render it every frame by default.

In irrlicht 1.8.5 this does not exist, this is a great implementation considering how expensive shadow volumes are.

Using only the CPU, at resolutions like 800x600, you can have a stable number of fps, even on 20-year-old computers (although the operating system will continue to render the screen pixels with the GPU).

Burningsvideo runs very well, I think it only uses a single thread of the processor, however directly emulating OpenGL with the cpu with the help of some .dll offers us about 10 more fps.

OpenGL CPU emulation(opengl32.dll emulated):
Image

Burningsvideo:
Image

Code: Select all

#include <irrlicht.h>
#include <vector>

#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

int main()
{
    IrrlichtDevice* device = createDevice(
        EDT_BURNINGSVIDEO,
        dimension2d<u32>(800,600),
        16, false, true, false, 0);

    if (!device) return 1;

    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
    IGUIEnvironment* gui = device->getGUIEnvironment();
    ITimer* timer = device->getTimer();

    driver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);

    // Check RTT support (required)
    if (!driver->queryFeature(EVDF_RENDER_TO_TARGET))
    {
        device->drop();
        return 1;
    }
	IAnimatedMesh* mesh = smgr->getMesh("../../media/dwarf.x");
    //IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
    if (!mesh)
    {
        device->drop();
        return 1;
    }

    std::vector<IShadowVolumeSceneNode*> shadowNodes;

    // Main character
    IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
    if (node)
    {
        node->setMaterialFlag(EMF_LIGHTING, true);
        node->setMaterialFlag(EMF_BILINEAR_FILTER, false);
        node->setMaterialFlag(EMF_NORMALIZE_NORMALS, true);
        node->setMD2Animation(scene::EMAT_STAND);
		node->setPosition(vector3df(0,-9,0));

        //node->setMaterialTexture(0, driver->getTexture("../../media/sydney.bmp"));
        //node->setPosition(vector3df(0,15,0));
        
        IShadowVolumeSceneNode* shadow = node->addShadowVolumeSceneNode();
        if (shadow)
        {
            shadow->setFreeze(ESF_FREEZE);          // start frozen
            shadowNodes.push_back(shadow);
        }
    }

    // Extra characters in a circle
    for (int i = 0; i < 3; ++i)
    {
        IAnimatedMeshSceneNode* newNode = smgr->addAnimatedMeshSceneNode(mesh);
        if (newNode)
        {
            newNode->setMaterialFlag(EMF_LIGHTING, true);
            newNode->setMaterialFlag(EMF_BILINEAR_FILTER, false);
            newNode->setMaterialFlag(EMF_NORMALIZE_NORMALS, true);
            //newNode->setMD2Animation(scene::EMAT_STAND);
            //newNode->setMaterialTexture(0, driver->getTexture("../../media/sydney.bmp"));

            f32 angle = i * (2 * PI / 8);
            f32 radius = 60.0f;
            f32 x = radius * cos(angle);
            f32 z = radius * sin(angle);

			 newNode->setPosition(vector3df(x, -9, z));

           // newNode->setPosition(vector3df(x, 15, z));

            IShadowVolumeSceneNode* shadow = newNode->addShadowVolumeSceneNode();
            if (shadow)
            {
                shadow->setFreeze(ESF_FREEZE);
                shadowNodes.push_back(shadow);
            }
        }
    }

    smgr->setShadowColor(video::SColor(230,0,0,0));

    // Light (must be present for shadows)
    ILightSceneNode* sun = smgr->addLightSceneNode(0,
        vector3df(0,150,0), SColorf(1.0f,1.0f,1.0f), 700.0f);

    // Floor
    IMeshSceneNode* floor = smgr->addCubeSceneNode(1.0f);
    if (floor)
    {
        floor->setScale(vector3df(200,1,200));
        floor->setPosition(vector3df(0,-10,0));
        floor->setMaterialFlag(EMF_LIGHTING, true);
		floor->setMaterialFlag(EMF_NORMALIZE_NORMALS, true);
        floor->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg"));
    }

    // Camera
    ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
    camera->setPosition(vector3df(0,20,-40));
    camera->setTarget(vector3df(0,5,0));
    device->getCursorControl()->setVisible(false);

    // --- RTT setup ---
    ITexture* rtt = driver->addRenderTargetTexture(dimension2d<u32>(128,128), "RTT_Scene");
    if (!rtt)
    {
        device->drop();
        return 1;
    }

    // Full‑screen quad vertices (for drawing the RTT texture)
    S3DVertex vertices[4];
    vertices[0] = S3DVertex(-1, 1,0, 0,0,1, SColor(255,255,255,255), 0,0);
    vertices[1] = S3DVertex( 1, 1,0, 0,0,1, SColor(255,255,255,255), 1,0);
    vertices[2] = S3DVertex( 1,-1,0, 0,0,1, SColor(255,255,255,255), 1,1);
    vertices[3] = S3DVertex(-1,-1,0, 0,0,1, SColor(255,255,255,255), 0,1);
    u16 indices[6] = {0,1,2, 0,2,3};

    SMaterial quadMaterial;
    quadMaterial.Lighting = false;
    quadMaterial.ZBuffer = false;
    quadMaterial.ZWriteEnable = EZW_OFF;
    quadMaterial.setTexture(0, rtt);
    quadMaterial.setFlag(EMF_TRILINEAR_FILTER, true);

    // --- Shadow update timing ---
    u32 lastShadowUpdate = timer->getRealTime();
    const u32 shadowInterval = 1000 / 8;   // 8 shadows volume FPS

    // Force an initial shadow update (unfreeze, update, refreeze)
    for (size_t i = 0; i < shadowNodes.size(); ++i)
    {
        IShadowVolumeSceneNode* shadow = shadowNodes[i];
        if (shadow)
        {
            shadow->setFreeze(ESF_RUN);
            shadow->updateShadowVolumes();
            shadow->setFreeze(ESF_FREEZE);
        }
    }

    int lastFPS = -1;

    while (device->run())
    {
        if (!device->isWindowActive()) continue;

        // 1. Update shadows at 8 FPS (temporary unfreeze)
        u32 now = timer->getRealTime();
        if (now - lastShadowUpdate >= shadowInterval)
        {
            for (size_t i = 0; i < shadowNodes.size(); ++i)
            {
                IShadowVolumeSceneNode* shadow = shadowNodes[i];
                if (shadow)
                {
                    shadow->setFreeze(ESF_RUN);
                    shadow->updateShadowVolumes();
                    shadow->setFreeze(ESF_FREEZE);
                }
            }
            lastShadowUpdate = now;
        }

        // 2. Render the scene into the RTT
        driver->setRenderTarget(rtt, ECBF_COLOR | ECBF_DEPTH, SColor(0,0,0,255));
        smgr->drawAll();

        // 3. Switch back to the back buffer and clear (setRenderTarget already cleared)
        driver->setRenderTarget(0, ECBF_COLOR | ECBF_DEPTH, SColor(0,100,100,100));
        driver->beginScene(false, false, SColor(0,0,0,0));

        // 4. Draw the full‑screen quad with the RTT texture
        driver->setMaterial(quadMaterial);
        driver->setTransform(ETS_WORLD, IdentityMatrix);
        driver->setTransform(ETS_VIEW, IdentityMatrix);
        driver->setTransform(ETS_PROJECTION, IdentityMatrix);
        driver->drawIndexedTriangleList(vertices, 4, indices, 2);

        driver->endScene();
		
		//device->sleep(16);
        // 5. Update window title with FPS
        int fps = driver->getFPS();
        if (fps != lastFPS)
        {
            stringw str = L"RTT + Shadows  8 FPS - FPS: ";
            str += fps;
            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
    }

    device->drop();
    return 0;
}
Dll used:
https://github.com/JHRobotics/mesa9x

https://github.com/JHRobotics/mesa9x/releases/

https://github.com/JHRobotics/mesa9x/re ... vmpipe.zip

For use, only opengl32.dll is copied into the executable file.




Rendering by CPU is very useful when you have a computer that you have not changed the thermal paste, and it turns off for safety when it detects that the temperatures rise too high lmao, I had two computers with that problem (they turned off when I used the GPU a lot, before it didn't happen but after several years it happened).
Irrlicht is love, Irrlicht is life, long live to Irrlicht
Post Reply