OpenGL de プログラミング - PBO::まとめコード2
現在地 >> メニュー >> 基本編10 >> PixelBufferObject >> PBO::まとめコード2 (PACKの例)

問題


PBOを使った以下の操作を行え。
  1. 2つのPBOを作成
  2. 背景がまっ白なウィンドウを作り、glReadPixelsで1つ目のPBOにコピー
  3. 2つ目のPBOをマッピングしてデータを操作
  4. glDrawPixelsで描画する

※以下のコードはダブルバッファでアニメーションさせ、PBO::まとめコード1のような結果になる。

答え

#include <iostream>
#include <GL/glew.h>
#include <GL/glut.h>

//-------- 各種外部変数 ----------//
struct _ImageData
{
	int width;
	int height;
	int nChannels;
};
_ImageData Screen = {256,256,4};



//PBO用ID
GLuint PboId[2];
unsigned char *ColorData;  //表示用カラーバッファ(glDrawPixels用)

//----------- 関数プロトタイプ ----------------//
void display();
void reshape(int w, int h);
void timer(int value);
void BuildPBO();


//----------- OpenGLの初期設定 ---------------//
void GLUT_INIT()
{
	glutInitDisplayMode(GLUT_RGBA| GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowSize(Screen.width, Screen.height);
	glutCreateWindow("PBO");
}

void GLUT_CALL_FUNC()
{
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutTimerFunc(0,timer,17);
}


void MY_INIT()
{
	glClearColor(1.0, 1.0, 1.0, 1.0);

	int DataSize = Screen.height * Screen.width * Screen.nChannels;

	//メモリ確保と初期化
	ColorData = new unsigned char[DataSize];
	memset(ColorData,0,DataSize);
}

//---------  glewの初期設定  ------------//
bool GLEW_INIT()
{
	GLenum err;
	err = glewInit();
	if (err != GLEW_OK){
		std::cerr << glewGetErrorString(err) << "\n";
		return false;
	}
	return true;
}


//---------- メイン関数 ---------------//
int main(int argc, char **argv)
{
	glutInit(&argc,argv);
	GLUT_INIT();
	GLUT_CALL_FUNC();
	MY_INIT();

	if ( GLEW_INIT() == false){
		return -1;
	}


	BuildPBO(); //PBO作成

	glutMainLoop();

	return 0;
}

//------------- ここから各種コールバック ------------------//
void display()
{
	static int index = 0;
	int nextIndex = 0;
	index = (index + 1) % 2;
	nextIndex = (index + 1) % 2;

	glReadBuffer(GL_FRONT);  //フレームバッファの表が対象


	//現在のフレームバッファからPBOにコピー
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, PboId[index]);
	glReadPixels(0, 0, Screen.width, Screen.height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
	

	//2つ目のPBOのバッファを操作
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, PboId[nextIndex]);
	unsigned char *color = (unsigned char*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
	if(color)
	{
		int *ptr = (int*)color;
		static int val=0;
		for(int y = 0; y < Screen.height ; ++y){
			for(int x = 0; x < Screen.width; ++x){
				*ptr = val;
				++ptr;
			}
			val+=260;
		}
		++val;

		memcpy(ColorData,color,Screen.height * Screen.width * Screen.nChannels); //描画用バッファにコピー
		glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);//マッピング解放
	}
	

	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);


	glDrawBuffer(GL_BACK); //後ろのバッファが対象


	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//-- ここに何か描画(今回は略) --//


	glWindowPos2i(0,0); //描画開始位置の指定(左下原点)
	glDrawPixels(Screen.width, Screen.height, GL_BGRA, GL_UNSIGNED_BYTE, ColorData);
	
	glutSwapBuffers();


}

void reshape(int w, int h)
{
	glViewport(0, 0, w, h);  //ビューポートの設定

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(30.0, (double)w / (double)h, 1.0, 100.0); //視野の設定
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //視点の設定
}

void timer(int t)
{
	glutPostRedisplay();
	glutTimerFunc(t,timer,17); //タイマー関数
}




void BuildPBO()
{
	int DataSize = Screen.height * Screen.width * Screen.nChannels;

	glGenBuffersARB(2, PboId);//PBOを2つ作成
	
	//1つめ
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, PboId[0]);
	glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DataSize, 0, GL_STREAM_READ_ARB);
	//2つめ
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, PboId[1]);
	glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DataSize, 0, GL_STREAM_READ_ARB);
	
	
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
	
}