Jump to content
  • Advertisement
Sign in to follow this  
TBurnett

Gldrawpixels To Stencil Buffer

This topic is 782 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm creating a image using OpenCV which I would like to use as a stencil.  However, when I upload the image using glDrawPixels and then read it back using glReadPixels,  I only get a fraction of the image.   It is not obvious to me what is the problem since the alignment appears correct.  Help would be appreciated.  The code and images are below.

 

  

 
//---------------------------------------------------------------------
// createStencilBuffer
//---------------------------------------------------------------------
void RenderRadiance::createStencilBuffer(void)
{
cv::Mat stencilImg(_radDim.y,_radDim.x,CV_8UC1);
 
  stencilImg.setTo(0); 
 
  for (size_t i = 0;i < _hPntLst.size();i++)
  {
  HPnt  hPnt = _hPntLst;
 
    cv::circle(stencilImg,cv::Point(hPnt._hCen.x,hPnt._hCen.y),(int)_hogelDiameter/2,cv::Scalar(255),-1);
  }
  
  glPixelStorei(GL_UNPACK_ALIGNMENT,1);
  glPixelStorei(GL_UNPACK_ROW_LENGTH,_radDim.x);
  glPixelStorei(GL_UNPACK_SKIP_ROWS,0);
  glPixelStorei(GL_UNPACK_SKIP_PIXELS,0);
 
  glPixelStorei(GL_PACK_ALIGNMENT,1);
  glPixelStorei(GL_PACK_ROW_LENGTH,_radDim.x);
  glPixelStorei(GL_PACK_SKIP_ROWS,0);
  glPixelStorei(GL_PACK_SKIP_PIXELS,0);
 
  glGenRenderbuffers(1,&_renderStencilBuffer);
  glBindRenderbuffer(GL_RENDERBUFFER,_renderStencilBuffer);
  glRenderbufferStorage(GL_RENDERBUFFER,GL_STENCIL_INDEX,_radDim.x,_radDim.y);
 
  glDrawPixels(_radDim.x,_radDim.y,GL_STENCIL_INDEX,GL_UNSIGNED_BYTE,stencilImg.data);
 
  if (1)
  {
  cv::Mat stencilImgRead(_radDim.y,_radDim.x,CV_8UC1);
 
    glReadPixels(0,0,_radDim.x,_radDim.y,GL_STENCIL_INDEX,GL_UNSIGNED_BYTE,stencilImgRead.data);
 
    cv::imwrite("Stencil.png",stencilImg);
    cv::imwrite("StencilGPU.png",stencilImgRead);
  }
}
 

Share this post


Link to post
Share on other sites
Advertisement

I am not familiar with OpenCV, but I am more familiar with OpenGL.  At a glance, I could not see anything wrong with the gl calls you provided, so I set up a dummy project to prove it.  Under OpenGL 4.5, using glew-2.0.0 and glfw-3.2 as a wrapper, I was successful in this proof.  My test loads the first image you provided as Stencil.bmp, writes it to a bound buffer, reads it back frm that buffer, and writes the result to disk.  I set up a few dummy objects in order to prove I could use your gl code exactly as-is, without modifications.  I have included my source (I was not allowed to attach a .cpp file, so I included it just as a code-block below), which produces the expected output as StencilGPU.bmp

 

These results indicate that your problem lies somewhere in the OpenCV object, not in your OpenGL calls.  Perhaps the mat is storing the image in something akin to compression blocks (which are not sequential), and thus you end up writing a bunch of nonsense to the GPU after the end of the first block?  You might consider spending some time validating that the buffer you are reading from is both sequential, and also starts from the first scanline (positive stride).  You would also need to validate that the buffer you are writing to is both sequential, and also starts from the first scanline (positive stride).  It is also possible that just removing OpenCV altogether from the equation in this section of your code would be simpler.

 

Good luck!

//Include GLEW  
#include <GL/glew.h>  

//Include GLFW  
#include <GLFW/glfw3.h>  

//Include the standard C++ headers  
#include <stdio.h>  
#include <stdlib.h>  
#include <Windows.h>
#include <assert.h>
#include <gdiplus.h>

using namespace Gdiplus;

typedef struct RadDim_Dummy_t
{
	int x, y;
} RadDim_Dummy;

typedef struct Mat_Dummy_t
{
	void* data;
} Mat_Dummy;

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
	UINT  num = 0;          // number of image encoders
	UINT  size = 0;         // size of the image encoder array in bytes

	ImageCodecInfo* pImageCodecInfo = NULL;

	GetImageEncodersSize(&num, &size);
	if(size == 0)
		return -1;  // Failure

	pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
	if(pImageCodecInfo == NULL)
		return -1;  // Failure

	GetImageEncoders(num, size, pImageCodecInfo);

	for(UINT j = 0; j < num; ++j)
	{
		if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			free(pImageCodecInfo);
			return j;  // Success
		}
	}
	free(pImageCodecInfo);
	return -1;  // Failure
}

void SetupStencilBuffer()
{
	// load the file copied from gamedev into a gdi+ bitmap
	HBITMAP hBitmap = (HBITMAP)LoadImage( NULL, L"Stencil.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );
	BITMAP bmp;
	GetObject(hBitmap, sizeof(BITMAP), &bmp);
	Bitmap *image = new Bitmap(hBitmap, NULL);
	assert(image);
	assert(image->GetPixelFormat() == PixelFormat8bppIndexed);
	assert(GetPixelFormatSize(image->GetPixelFormat()) == 8);
	const int width = image->GetWidth(), height = image->GetHeight(), size = width * height;

	// grab the buffer itself from the gdi+ bitmap
	BitmapData data;
	Rect rect = Rect(0, 0, width, height);
	Status result = image->LockBits(&rect, ImageLockModeRead | ImageLockModeWrite, image->GetPixelFormat(), &data);
	assert(result == Ok);

	// flip the buffer if the scanlines are inverted.
	if (data.Stride < 0)
	{
		image->UnlockBits(&data);
		image->RotateFlip(RotateNoneFlipY);
		Status result = image->LockBits(&rect, ImageLockModeRead | ImageLockModeWrite, image->GetPixelFormat(), &data);
		assert(result == Ok);
	}
	assert(data.Stride > 0);

	// allocate and initialize a buffer to copy into from glReadPixels
	UINT8* buffer = new UINT8[size];
	memset(buffer, 0, size);

	// setup some dummy variables so i can copy-paste code without any modifications from gamedev
	GLuint _renderStencilBuffer;
	RadDim_Dummy _radDim = { width, height };
	Mat_Dummy stencilImg = { data.Scan0 };
	Mat_Dummy stencilImgRead = { buffer };

	// start sample code from gamedev
	{
		glPixelStorei(GL_UNPACK_ALIGNMENT,1);
		glPixelStorei(GL_UNPACK_ROW_LENGTH,_radDim.x);
		glPixelStorei(GL_UNPACK_SKIP_ROWS,0);
		glPixelStorei(GL_UNPACK_SKIP_PIXELS,0);

		glPixelStorei(GL_PACK_ALIGNMENT,1);
		glPixelStorei(GL_PACK_ROW_LENGTH,_radDim.x);
		glPixelStorei(GL_PACK_SKIP_ROWS,0);
		glPixelStorei(GL_PACK_SKIP_PIXELS,0);

		glGenRenderbuffers(1,&_renderStencilBuffer);
		glBindRenderbuffer(GL_RENDERBUFFER,_renderStencilBuffer);
		glRenderbufferStorage(GL_RENDERBUFFER,GL_STENCIL_INDEX,_radDim.x,_radDim.y);

		glDrawPixels(_radDim.x,_radDim.y,GL_STENCIL_INDEX,GL_UNSIGNED_BYTE,stencilImg.data);

		// ...

		glReadPixels(0,0,_radDim.x,_radDim.y,GL_STENCIL_INDEX,GL_UNSIGNED_BYTE,stencilImgRead.data);
	}
	// end sample code from gamedev

		// copy the buffer back into the Bitmap, and then use the Bitmap to write it back to disk.
	memcpy(data.Scan0, buffer, size);
	image->UnlockBits(&data);

	CLSID clsId;
	int retVal = GetEncoderClsid(L"image/bmp", &clsId);
	image->Save(L"StencilGPU.bmp", &clsId, NULL);
	delete image;
	delete buffer;
}

//Define an error callback  
static void error_callback(int error, const char* description)  
{  
	fputs(description, stderr);  
	_fgetchar();  
}  

//Define the key input callback  
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)  
{  
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)  
		glfwSetWindowShouldClose(window, GL_TRUE);  
}  

int main( void )  
{  
	//Set the error callback  
	glfwSetErrorCallback(error_callback);  

	//Initialize GLFW  
	if (!glfwInit())  
	{  
		exit(EXIT_FAILURE);  
	}  

	//Set the GLFW window creation hints - these are optional  
	//glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //Request a specific OpenGL version  
	//glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //Request a specific OpenGL version  
	//glfwWindowHint(GLFW_SAMPLES, 4); //Request 4x antialiasing  
	//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  

	//Declare a window object  
	GLFWwindow* window;  

	//Create a window and create its OpenGL context  
	window = glfwCreateWindow(640, 480, "Test Window", NULL, NULL);  

	//If the window couldn't be created  
	if (!window)  
	{  
		fprintf( stderr, "Failed to open GLFW window.\n" );  
		glfwTerminate();  
		exit(EXIT_FAILURE);  
	}  

	//This function makes the context of the specified window current on the calling thread.   
	glfwMakeContextCurrent(window);  

	//Sets the key callback  
	glfwSetKeyCallback(window, key_callback);  

	//Initialize GLEW  
	GLenum err = glewInit();  

	//If GLEW hasn't initialized  
	if (err != GLEW_OK)   
	{  
		fprintf(stderr, "Error: %s\n", glewGetErrorString(err));  
		return -1;  
	}  

	//Set a background color  
	glClearColor(0.0f, 0.0f, 1.0f, 0.0f);  

	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	TrapError();
	SetupStencilBuffer();

	//Main Loop  
	do  
	{  
		//Clear color buffer  
		glClear(GL_COLOR_BUFFER_BIT);  

		//Swap buffers  
		glfwSwapBuffers(window);  
		//Get and organize events, like keyboard and mouse input, window resizing, etc...  
		glfwPollEvents();  

	} //Check if the ESC key had been pressed or if the window had been closed  
	while (!glfwWindowShouldClose(window));  

	//Close OpenGL window and terminate GLFW  
	glfwDestroyWindow(window);  
	//Finalize and clean up GLFW  
	glfwTerminate();  

	GdiplusShutdown(gdiplusToken);

	exit(EXIT_SUCCESS);  
}  

Share this post


Link to post
Share on other sites

Thank you very much for you help.  I'll download your example and test it.   I'm not sure why OpenCV would be a problem but I'll take your advice and look into it further.  Thank you.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!