opengl 显示BMP图像

本想系统的学习一下OPENGL,最近几天跟蓝皮书的接触效果不太好,索性还是按照自己的想法来。

先显示一张图片吧,已经调试过的代码如下:

#include <GLTools.h>	// OpenGL toolkit
#include <GLShaderManager.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>



// settings
const int SCR_WIDTH = 320, SCR_HEIGHT = 240;
GLuint base_prog;
GLuint quad_vbo;
GLuint tex;
unsigned char* image;

//----------------------------------------------------------------------------
void glAttachShaderSource(GLuint prog, GLenum type, const char * source)
{
	GLuint sh;

	sh = glCreateShader(type);
	glShaderSource(sh, 1, &source, NULL);
	glCompileShader(sh);
	char buffer[4096];
	glGetShaderInfoLog(sh, sizeof(buffer), NULL, buffer);
	glAttachShader(prog, sh);
	glDeleteShader(sh);
}

//----------------------------------------------------------------------------
void Init()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glEnable(GL_DEBUG_OUTPUT);

	base_prog = glCreateProgram();

	static const char quad_shader_vs[] =
		"#version 330 core\n"
		"\n"
		"layout (location = 0) in vec2 in_position;\n"
		"layout (location = 1) in vec2 in_tex_coord;\n"
		"\n"
		"out vec2 tex_coord;\n"
		"\n"
		"void main(void)\n"
		"{\n"
		"    gl_Position = vec4(in_position, 0.0, 1.0);\n"
		"    tex_coord = in_tex_coord;\n"
		"}\n"
		;

	static const char quad_shader_fs[] =
		"#version 330 core\n"
		"\n"
		"in vec2 tex_coord;\n"
		"\n"
		"layout (location = 0) out vec4 color;\n"
		"\n"
		"uniform sampler2D tex;\n"
		"\n"
		"void main(void)\n"
		"{\n"
		"    color = texture(tex,tex_coord);\n"
		"}\n"
		;
	glAttachShaderSource(base_prog, GL_VERTEX_SHADER, quad_shader_vs);
	glAttachShaderSource(base_prog, GL_FRAGMENT_SHADER, quad_shader_fs);
	glLinkProgram(base_prog);

	static const GLfloat quad_data[] =
	{
		-1.0f, -1.0f,
		1.0f, -1.0f,
		-1.0f, 1.0f,
		1.0f, 1.0f,
		/*
		
		0.0f, 1.0f,
		1.0f, 1.0f,
		0.0f, 0.0f,
		1.0f, 0.0f,
		*/

		0.0f, 0.0f,
		1.0f, 0.0f,
		0.0f, 1.0f,
		1.0f, 1.0f,
	};


	glGenBuffers(1, &quad_vbo);
	glBindBuffer(GL_ARRAY_BUFFER, quad_vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)(8 * sizeof(float)));
	glEnableVertexAttribArray(1);


	char buf[1024];
	glGetProgramInfoLog(base_prog, 1024, NULL, buf);
	printf("Program Info Log = %s\n", buf);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
	/*
	void glPixelStorei(GLenum pname,GLint param);
	它含有两个参数:
		pname:指定所要被设置参数的符号名。这里,参数的符号名有两种
				一种是GL_PACK_ALIGNMENT,它影响将像素数据写回到主存的打包形式,对glReadPixels的调用产生影响;
				还有一种是GL_UNPACK_ALIGNMENT,它影响从主存读到的像素数据的解包形式,对glTexImage2D以及glTexSubImage2D产生影响。

		param:指定相应的pname设置为什么值。这个数值一般是1、2、4或8,用于指定存储器中每个像素行有多少个字节对齐。对齐的字节数越高,系统就越能优化。
		在实际代码中,我们看到的是glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
		实际上,我们可以这里可以用4(默认值)。因为checkImage能够保证是4字节对齐的。当然,我们可以通过对checkImage的修改使其保证是8字节对齐:
	*/

	// texture
	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	//如果你想加载视频帧,或图片序列,你需要将以下的glTexImage2D()代码放到display()函数中,并且加上计时函数以便更新画面,如果从摄像机读的帧数据直接贴也是可以的
	int width, height;
	FILE *fp = fopen("D:\\vmshare\\Penguins.bmp", "rb");
	if (!fp) {
		printf("read file error\n");
		return;
	}

	unsigned char buff[4] = { 0 };
	fseek(fp, 18, SEEK_SET);
	fread(buff, 1, 4, fp);
	width = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];
	memset(buff, 0, sizeof(buff));
	fread(buff, 1, 4, fp);
	height = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];

	int line_stride = (width * 3 + 3) / 4 * 4;

	image = (unsigned char *)calloc(1, height * line_stride);
	fseek(fp, 54, SEEK_SET);
	fread(image, 1, height * line_stride, fp);
	fclose(fp);

	if (image)
	{
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, image);
	}
	else
	{
		printf("Failed to load texture");
	}

	if (image) {
		free(image);
		image = NULL;
	}
	glBindTexture(GL_TEXTURE_2D, 0);

}
//----------------------------------------------------------------------------

void display(void)
{
	glClearColor(0.0, 255, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	glUseProgram(base_prog);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, tex);
	glUniform1i(glGetUniformLocation(base_prog, "tex"), 0);

	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	glutSwapBuffers();
}

//----------------------------------------------------------------------------
void OnShutdown()
{
	glUseProgram(0);
	glDeleteProgram(base_prog);
	glDeleteTextures(1, &tex);
	glDeleteVertexArrays(1, &tex);
	//销毁vbo
	glDeleteBuffers(1, &quad_vbo);
	printf("Shutdown successfull");
}

int main(int argc, char **argv)
{
	glutInit(&argc, argv);

	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(SCR_WIDTH, SCR_HEIGHT);
	glutCreateWindow("GL_MultiThread_Video");
	printf("Version: %s\n", glGetString(GL_VERSION));

	if (glewInit() != GLEW_OK)
	{
		printf("Failed to initialize GLEW ... exiting");
		exit(EXIT_FAILURE);
	}

	Init();

	glutDisplayFunc(display);

	glutCloseFunc(OnShutdown);

	glutMainLoop();

	return 0;
}

既然能够显示单张图片,那么显示图片序列当然也没有什么问题了。这样不就相当于显示视频了吗?

借助 glutTimerFunc 启用一个Timer,周期性的调用显示函数即可。

#include "stdafx.h"

#include <GLTools.h>	// OpenGL toolkit
#include <GLShaderManager.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>


#include <Windows.h>

#include <iostream>
using namespace std;


// settings
const int SCR_WIDTH = 640, SCR_HEIGHT = 480;
GLuint base_prog;
GLuint quad_vbo;
GLuint tex;
unsigned char* image;

//----------------------------------------------------------------------------
void glAttachShaderSource(GLuint prog, GLenum type, const char * source)
{
	GLuint sh;

	sh = glCreateShader(type);
	glShaderSource(sh, 1, &source, NULL);
	glCompileShader(sh);
	char buffer[4096];
	glGetShaderInfoLog(sh, sizeof(buffer), NULL, buffer);
	glAttachShader(prog, sh);
	glDeleteShader(sh);
}

//----------------------------------------------------------------------------
void Init()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glEnable(GL_DEBUG_OUTPUT);
	//(1) 编写Vertex shader和 Fragment Shader
	static const char quad_shader_vs[] =
		"#version 330 core\n"
		"\n"
		"layout (location = 0) in vec2 in_position;\n"
		"layout (location = 1) in vec2 in_tex_coord;\n"
		"\n"
		"out vec2 tex_coord;\n"
		"\n"
		"void main(void)\n"
		"{\n"
		"    gl_Position = vec4(in_position, 0.0, 1.0);\n"
		"    tex_coord = in_tex_coord;\n"
		"}\n"
		;

	static const char quad_shader_fs[] =
		"#version 330 core\n"
		"\n"
		"in vec2 tex_coord;\n"
		"\n"
		"layout (location = 0) out vec4 color;\n"
		"\n"
		"uniform sampler2D tex;\n"
		"\n"
		"void main(void)\n"
		"{\n"
		"    color = texture(tex,tex_coord);\n"
		"}\n"
		;

	//(2) 创建两个Shader实例

	//创建Program对象
	base_prog = glCreateProgram();
	//绑定shader到program对象
	glAttachShaderSource(base_prog, GL_VERTEX_SHADER, quad_shader_vs);
	glAttachShaderSource(base_prog, GL_FRAGMENT_SHADER, quad_shader_fs);
	//链接program
	glLinkProgram(base_prog);


	//初始化Texture
	//定义定点数组
	static const GLfloat quad_data[] =
	{
		-1.0f, -1.0f,
		1.0f, -1.0f,
		-1.0f, 1.0f,
		1.0f, 1.0f,
		/*
		
		0.0f, 1.0f,
		1.0f, 1.0f,
		0.0f, 0.0f,
		1.0f, 0.0f,
		*/

		0.0f, 0.0f,
		1.0f, 0.0f,
		0.0f, 1.0f,
		1.0f, 1.0f,
	};


	glGenBuffers(1, &quad_vbo);
	glBindBuffer(GL_ARRAY_BUFFER, quad_vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)(8 * sizeof(float)));
	glEnableVertexAttribArray(1);


	char buf[1024];
	glGetProgramInfoLog(base_prog, 1024, NULL, buf);
	printf("Program Info Log = %s\n", buf);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
	/*
	void glPixelStorei(GLenum pname,GLint param);
	它含有两个参数:
		pname:指定所要被设置参数的符号名。这里,参数的符号名有两种
				一种是GL_PACK_ALIGNMENT,它影响将像素数据写回到主存的打包形式,对glReadPixels的调用产生影响;
				还有一种是GL_UNPACK_ALIGNMENT,它影响从主存读到的像素数据的解包形式,对glTexImage2D以及glTexSubImage2D产生影响。

		param:指定相应的pname设置为什么值。这个数值一般是1、2、4或8,用于指定存储器中每个像素行有多少个字节对齐。对齐的字节数越高,系统就越能优化。
		在实际代码中,我们看到的是glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
		实际上,我们可以这里可以用4(默认值)。因为checkImage能够保证是4字节对齐的。当然,我们可以通过对checkImage的修改使其保证是8字节对齐:
	*/

	// texture
	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	//如果你想加载视频帧,或图片序列,你需要将以下的glTexImage2D()代码放到display()函数中,并且加上计时函数以便更新画面,如果从摄像机读的帧数据直接贴也是可以的
	int width, height;
	FILE *fp = fopen("D:\\vmshare\\show_yuv422p\\show_yuv422p_on_screen_00000001.bmp", "rb");
	if (!fp) {
		printf("read file error\n");
		return;
	}

	unsigned char buff[4] = { 0 };
	fseek(fp, 18, SEEK_SET);
	fread(buff, 1, 4, fp);
	width = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];
	memset(buff, 0, sizeof(buff));
	fread(buff, 1, 4, fp);
	height = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];

	int line_stride = (width * 3 + 3) / 4 * 4;

	image = (unsigned char *)calloc(1, height * line_stride);
	fseek(fp, 54, SEEK_SET);
	fread(image, 1, height * line_stride, fp);
	fclose(fp);

	
	
	
	if (image)
	{
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, image);
	}
	else
	{
		printf("Failed to load texture");
	}


	glBindTexture(GL_TEXTURE_2D, 0);
	
	
}

void load_frame(unsigned char *frame_rgb_buf, int *w, int *h)
{
	char tmp_buf[1024] = { 0 };
	static int index = 1;
	sprintf(tmp_buf, "D:\\vmshare\\show_yuv422p\\show_yuv422p_on_screen_%08d.bmp", index++);
	int width, height;
	FILE *fp = fopen(tmp_buf, "rb");
	if (!fp) {
		printf("read file error\n");
		return;
	}

	printf("read file %s\n", tmp_buf);
	unsigned char buff[4] = { 0 };
	fseek(fp, 18, SEEK_SET);
	fread(buff, 1, 4, fp);
	width = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];
	memset(buff, 0, sizeof(buff));
	fread(buff, 1, 4, fp);
	height = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];

	int line_stride = (width * 3 + 3) / 4 * 4;

	fseek(fp, 54, SEEK_SET);
	fread(frame_rgb_buf, 1, height * line_stride, fp);
	fclose(fp);

	*w = width;
	*h = height;
}
//----------------------------------------------------------------------------

void display(void)
{

	int width = 0;
	int height = 0;
	load_frame(image, &width, &height);
	
	
	if (image)
	{
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, image);
	}
	else
	{
		printf("Failed to load texture");
	}
	
	//glBindTexture(GL_TEXTURE_2D, 0);
	
	glClearColor(0.0, 255, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	glUseProgram(base_prog);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, tex);
	glUniform1i(glGetUniformLocation(base_prog, "tex"), 0);

	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	glutSwapBuffers();
}

//----------------------------------------------------------------------------
void OnShutdown()
{
	glUseProgram(0);
	glDeleteProgram(base_prog);
	glDeleteTextures(1, &tex);
	glDeleteVertexArrays(1, &tex);
	//销毁vbo
	glDeleteBuffers(1, &quad_vbo);
	printf("Shutdown successfull");

	if (image) {
		free(image);
		image = NULL;
	}
}


void timeFunc(int value){
	display();
	// Present frame every 40 ms
	glutTimerFunc(40, timeFunc, 0);
}

int main(int argc, char **argv)
{
	glutInit(&argc, argv);

	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(SCR_WIDTH, SCR_HEIGHT);
	glutCreateWindow("GL_MultiThread_Video");
	printf("Version: %s\n", glGetString(GL_VERSION));

	if (glewInit() != GLEW_OK)
	{
		printf("Failed to initialize GLEW ... exiting");
		exit(EXIT_FAILURE);
	}

	Init();

	glutDisplayFunc(display);
	glutTimerFunc(40, timeFunc, 0);
	glutCloseFunc(OnShutdown);

	glutMainLoop();

	return 0;
}

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值