reading data from a buffer and display a texture

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Locked
Yohanna
Posts: 25
Joined: Sat Dec 11, 2010 2:12 am

reading data from a buffer and display a texture

Post by Yohanna »

Hello everyone

I am trying to get the data of the image that is displayed on the PC screen by Irrlicht example 1.
The image is static, the driver is OpenGL. Using the library GLUT, I am trying to read the RGB data from the buffer (supposed to be GL_BACK or GL_FRONT), apply some changes on these data, then save them in an array, and finally display this array of RGB data as a texture to be displayed on the PC screen instead of the original Irrlicht image.

No build errors but when debug Irrlicht image appears then the computer crashes and gives the message: unhandled exception at ….Access violation reading location…., the other message says: No symbols are loaded for any call stack frame. The source code cannot be displayed.

Call stack has an arrow signalling to the line : glut32.dll !0006e35
I put the functions that are needed to read the buffer and display the texture inside the while loop in the example 1 of Irrlicht : while(device->run()){ ……driver->endScene ()….here}

The questions are: can anyone sugest about the reason of this problem? What is the buffer that holds the RGB data of the image displayed on the screen? Is there an alternative function in Irrlicht to do what I need to do with GLUT? Any function for screenshot ?

Any help would be very appreciated
Many thanks for your time
Radikalizm
Posts: 1215
Joined: Tue Jan 09, 2007 7:03 pm
Location: Leuven, Belgium

Post by Radikalizm »

The IVideoDriver class has a function called createScreenShot() which will export the last rendered frame to an IImage, which you can then display

Also, some advice: Irrlicht is designed to abstract away low-level APIs like OpenGL and on top of that GLUT, it's pretty absurd to not use irrlicht functions and to go back to a (harder) more low-level approach for getting something done

Creating an array with a color element for every pixel is also a very bad idea, a 1024x768 texture would contain a total of 786432 pixels, which at a 32-bits per pixel format (eg. R8G8B8A8) would give 3Mb of data to process which is a pretty large overhead, and it would only get worse at higher resolutions
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yeah, screenshot would work in most cases. Sometimes it's better to use a render target texture (example 13) which does almost the same, but comes up with a texture instead of an IImage.
Pixel arrays are called IImage in Irrlicht (at least as long as they are on the CPU, on GPU they are called ITexture). So if you want to deal with the content of textures manually, you should check out the API for things possible with IImage.
Yohanna
Posts: 25
Joined: Sat Dec 11, 2010 2:12 am

Post by Yohanna »

Hi Radikalism, and hybrid

many thanks for the useful information you provided.
I used the function createScreenShot in the same example but when I tried to use it in another example did not work. I will try again and see what is the problem. I will get rid of my old way and rely on Irrlicht only, it is much better. I am caused to use this way because I am applying changes on the pixels and render them again, the speed and the size are ok at this stage. Also, I used example 13, it is very good for this task and for other tasks I am going to do. I accessed the pixels with the functions getPixel() and setPixel() from IImage.

I am going to use a FOR loop inside the example 1, each time the size of the displayed image is changed, and other parameters must be changed such as the texture file to be loaded etc.., but the problem is that I cannot do that automatically, I need to change all these parameters, build the project, and debug for each case. the question is: how can I do this loop automatically so that the parameters are changed and the images are displayed in sequence at once? when I do such a loop, each time the image rendered is the first one, and the new changes are not applied
any suggestion will be helpful. thanks in advance
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

I did not get the full flow you described here. Maybe you can show some code or a diagram? But it sounds as if you lock the texture and don't unlock, or don't generate/disable mipmaps. This can lead to not updated parts of the textures.
Yohanna
Posts: 25
Joined: Sat Dec 11, 2010 2:12 am

Post by Yohanna »

Thanks again Hybrid

I am trying to load a .dae model and take a series of images of the model from 8 different locations of the camera (the variable xx_camera is increamented by 0.2 each time and assigned to the camera x coordinate). the screenshot function must work one time only for each image so that 8 images are saved for the 8 views of the model. the loop should change the parameters of the camera each time and take a screenshot of the resulting image. I converted the screenshot function that works on an event (pressing F9) to a fucntion that works only one time when it is called from the loop to get one image. the variable ssss must be =1 to take an image, but it is set to 0 inside the function so that only one image is taken.
the problems are: 1) many images are taken each time. 2) the loop doesn't work and the parameters of the camera are not changed.
I wonder if I need to load the model each time I change the parameters.
even when take one image the files saved are many and the parameters can not be changed unless I change them manually and debug again and again

I will be waiting for your suggestions

many thanks

Code: Select all

#include <iostream>
#include <stdlib.h>
#include <GL/glut.h>
#include "stdafx.h"
#include <windows.h>
#include <irrlicht.h>
#include "driverChoice.h"

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


#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif

extern int ssss=2;
extern int hhhh=0;

extern float xx_camera = -0.7f;


const char* mapname=0;
ISceneNode* node1=0;


	class CScreenShotFactory : public IEventReceiver
{
public:

	CScreenShotFactory( IrrlichtDevice *device, const c8 * templateName, ISceneNode* node1 )
		: Device(device), Number(0), FilenameTemplate(templateName), Node(node1)
	{
		FilenameTemplate.replace ( '/', '_' );
		FilenameTemplate.replace ( '\\', '_' );
	}

	bool OnEvent(const SEvent& event)
	{
		
		if ((ssss == 1)&&(hhhh <8))
		{
			
				video::IImage* image = Device->getVideoDriver()->createScreenShot();
				if (image)
				{
ssss = 0;
					


					c8 buf[256];
					snprintf(buf, 256, "%s_shot%04d.jpg",
							FilenameTemplate.c_str(),
							++Number);
					Device->getVideoDriver()->writeImageToFile(image, buf, 85 );
					
					
					image->drop();
					
				}
				
				}
		
			else
			
				{
				return false;
				}

		
		
		return false;
	}

private:
	IrrlichtDevice *Device;
	u32 Number;
	core::stringc FilenameTemplate;
	ISceneNode* Node;
};


int main()
{

	
	IrrlichtDevice *device =
		createDevice( video::EDT_OPENGL, dimension2d<u32>(800, 800), 32,
			false, false, false, 0);	


	if (!device)
		return 1;

	device->setWindowCaption(L"BRUNEL UNIVERSITY");	

	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();
	IGUIEnvironment* guienv = device->getGUIEnvironment();

	CScreenShotFactory screenshotFactory(device, mapname, node1);
	device->setEventReceiver(&screenshotFactory);


	IAnimatedMesh* mesh = smgr->getMesh("../../media/Seymour_anim2.dae");

	if (!mesh)
	{
		device->drop();
		return 1;
	}
	IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );

	
	if (node)
	{
		node->setMaterialFlag(EMF_LIGHTING, true);
		node->setMD2Animation(scene::EMAT_STAND);
		node->setMaterialTexture( 0, driver->getTexture("../../media/boy_10.bmp") );

	}

	



	
	smgr->addCameraSceneNode(0, vector3df(xx_camera ,7,9), vector3df(0,0,-20));	

	printf("  %f \n", xx_camera);



	scene::ISceneNode* light3 =
		smgr->addLightSceneNode(0, core::vector3df(-7,3,13),
		video::SColorf(1.0f, 0.9f, 0.9f, 0.9f), 800.0f);



	while(device->run())
	{
	for (int dddd=0;dddd<8;dddd++)
	{
		driver->beginScene(true, true, SColor(255,150,101,100));

		smgr->drawAll();
		guienv->drawAll();

ssss = 1;

if ((hhhh <8)&&(hhhh > 0)) {
xx_camera = xx_camera + 0.2;
hhhh = hhhh + 1;

printf("  %d \n", hhhh);
}

driver->endScene();


	}
	
}
	
	device->drop();

	
	return 0;

}
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

I really don't know where to start... Did you already code something else than VisualBasic's hello world?
So
1) You don't need an event receiver for taking screenshots
2) your variable handling and naming is nonsense
3) if you want to change something of the camera, you need to call methods of the camera
4) you must call the screenshot function after endScene

Well, this at first, many other things might be necessary as well.
Yohanna
Posts: 25
Joined: Sat Dec 11, 2010 2:12 am

Post by Yohanna »

Thank you

I used your comments and solved all these problems.

thanks for help
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Congratualtions, I really didn't expect this after going through the code. Feel free to ask for more help. It really seems to work out with you :D
Yohanna
Posts: 25
Joined: Sat Dec 11, 2010 2:12 am

Post by Yohanna »

Many thanks Hybrid for your kindness, I appreciate it

with the following code an image made of 8 images taken by 8 different cameras is produced and saved in a file. that is exactly what I need but when I increased the number of cameras (or camera positions) to be 17 cameras instead of 8, the program crushed and gave me the following message: SISGL warning: Can't Create a New Surface Out of Video memory. This program will exit (ok).
it looks that the problem is related to the size of the video card memory (mine is 64 Mb), if the image height was 400 instead of 768 it works good and the image is produced. 18 windows are open while running. what I am after now is to do something to make it work for a height of 768 and 17 cameras.
I wonder if I can do anything with the program, for example close the unnecessary windows to save memory because I need to read some data from each window, save these data in the array (pixels_index) and then close the window. here all the windows are open while I don't need them and they waste the memory. tried to use guienv->drop() did not work.

code

Code: Select all

#include <iostream>
#include <stdlib.h>
#include <GL/glut.h>
#include "stdafx.h"
#include <windows.h>
#include <irrlicht.h>
#include "driverChoice.h"

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


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

extern int image_index=0;
unsigned int *pixels_index = new unsigned int[3*1020*768];


int main()
{

	myloop1:
	IrrlichtDevice *device =
		createDevice( video::EDT_OPENGL, dimension2d<u32>(1020, 768), 32,
			false, false, false, 0);	

	if (!device)
		return 1;

	device->setWindowCaption(L"IRRLICHT_ENGINE LONDON_UNIVERSITY");	

	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();
	IGUIEnvironment* guienv = device->getGUIEnvironment();


	//____________________________


	IAnimatedMesh* mesh = smgr->getMesh("../../media/Seymour_anim2.dae");		
	

	if (!mesh)
	{
		device->drop();
		return 1;
	}
	IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );

	
	if (node)
	{
		node->setMaterialFlag(EMF_LIGHTING, true);
		node->setMD2Animation(scene::EMAT_STAND);
		node->setMaterialTexture( 0, driver->getTexture("../../media/boy_10.bmp") );
		
		
	}

	scene::IAnimatedMesh* mesh1 = smgr->getMesh("../../media/house.3ds");

	scene::ISceneNode* node1 = 0;

	node1 = smgr->addAnimatedMeshSceneNode(mesh1);
	node1->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg"));
	node1->getMaterial(0).SpecularColor.set(0,0,0,0);


float wwww = 0.8 - image_index*0.1;	
	
	smgr->addCameraSceneNode(0, vector3df(wwww,7,9), vector3df(0,0,-20));	
image_index = image_index+1;


	scene::ISceneNode* light3 =
		smgr->addLightSceneNode(0, core::vector3df(-7,3,13),
		video::SColorf(1.0f, 0.9f, 0.9f, 0.9f), 800.0f);

	//____________________________


			while(device->run())
			{

			driver->beginScene(true, true, SColor(255,150,101,100));


			smgr->drawAll();
			guienv->drawAll();
			driver->endScene();

			irr::video::SColor myobjectscolor;
	
			video::IImage* image = device->getVideoDriver()->createScreenShot();
				if (image)
				{
				for (u32 column_index = 0 ; column_index < 60; column_index++)
				{
					for (u32 y_pixel = 0 ; y_pixel < 768; y_pixel++)
						{
						u32 x_pixel = 17*column_index + image_index;	
		u32 pixel_ind = x_pixel*3 + 1020*y_pixel*3;

						myobjectscolor = image->getPixel(x_pixel, y_pixel);

						pixels_index[pixel_ind] = myobjectscolor.getRed();
						pixels_index[pixel_ind+1] = myobjectscolor.getGreen();
						pixels_index[pixel_ind+2] = myobjectscolor.getBlue();
						}
				}
				
				if (image_index<17){goto myloop1;}
				else {goto myloop2;}
			}



myloop2:

u32 Number=0;
core::stringc FilenameTemplate;




video::IImage* image = device->getVideoDriver()->createScreenShot();

if (image)
	{


		for (u32 column_ind = 0 ; column_ind< 1020; column_ind++)
			{
				for (u32 row_ind = 0 ; row_ind < 768; row_ind++)
					{
					u32 pixel_ind = column_ind*3 + 1020*row_ind*3;
					image->setPixel(column_ind, row_ind, video::SColor(255,pixels_index[pixel_ind],pixels_index[pixel_ind+1],pixels_index[pixel_ind+2]), false);
					
					}
			}							

										
					c8 buf[256];
					snprintf(buf, 256, "%s_shot%04d.jpg",
							FilenameTemplate.c_str(),
							++Number);
					device->getVideoDriver()->writeImageToFile(image, buf, 85 );
					
					image->drop();

	}
			
	device->drop();

	
	return 0;
delete [] pixels_index;
}
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

I don't know why you are always creating new devices. If you just want to have different scenes or views, just alter the main scene in the only device you use. Otherwise, and only if it really makes sense, you should create the device, get the data into your IImage (which is unrelated to any device, it's just part of your main app), close the device, drop it (closing the window and freeing all ressources) and start over at this point.
Yohanna
Posts: 25
Joined: Sat Dec 11, 2010 2:12 am

Post by Yohanna »

Yes, I understood now how meaningless my question was. The problem was solved just when I moved the start of loop (myloop1:) to be before the function getMesh immediately.

many thanks again
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

You might also want to improve your code and coding skills a litte more and get rid of goto completely...
Yohanna
Posts: 25
Joined: Sat Dec 11, 2010 2:12 am

Post by Yohanna »

Yes Hybrid I agree, I will give it a try later. but now I have a question for experts, I spent along time trying to solve it but in vain and now have no clue.
I will put it here and any idea about it from you will be really useful.

The problem is about the orthographic projection or parallel imagine of the scene. I need to have an orthogonal view of the scene rather than perspective view, or by other words project the 3D scene that is saved in a file (for example .3ds) on the screen. in this case the 3D scene will be seen as 2D image by an orthogonal camera and the image will be the same even if we changed the Z coordinate of the camera position (point x,y,z will be projected on x,y,0).
the question is: can irrlicht provide any possibility for such an image? orthogonal camera or orthogonal projection of the scene on the screen rather than perspective one?
I would be waiting for any idea from you.
my full appreciation in advance
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

This was already answered in your new thread.
Locked