(二)C++嵌入opengl

render.h

#pragma once
#include <windows.h>
class GLRenderer
{
// 窗口句柄  的作用是什么??
public:
	GLRenderer(HWND hwnd, int width, int height);
	~GLRenderer();

	void Renderer();
	//拖动的时候改变大小
	void Resize(int width, int height);
private:
	bool CreateGLContext();

private:
	HDC dc;//设备上下文
	HGLRC rc;//opengl上下文  也是渲染上下文
	HWND hwnd;
};

render.cpp:

#include "GLRenderer.h"
#include <assert.h>
//#define GLEW_STATIC
#include <GL/glew.h>
#pragma comment(lib, "glew32.lib")
//#pragma comment(lib, "glew32s.lib")//静态库 需要顶一个宏 #define GLEW_STATIC
//引入opengl库
#pragma comment(lib, "opengl32.lib")
GLRenderer::GLRenderer(HWND hwnd, int width, int height)
{
	this->hwnd = hwnd;
	CreateGLContext();
	//把创建的opengl上下文 置为当前的opengl上下文
	wglMakeCurrent(dc, rc);
	//初始化glew
	assert(glewInit() == GLEW_OK);

	Resize(width, height);
}

GLRenderer::~GLRenderer()
{  
	//opengl上下文置为null
	wglMakeCurrent(NULL, NULL);
	if (rc)
		//删除渲染上下文
		wglDeleteContext(rc);
	if (dc)
		//释放设备上下文
		ReleaseDC(hwnd, dc);
}

void GLRenderer::Renderer()
{
	glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
	//清理颜色缓冲区  深度缓冲区
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//交换一下上缓冲区
	SwapBuffers(dc);
}

void GLRenderer::Resize(int width, int height)
{
	//窗口大小改变 的时候 改变下glew的视口大小
	glViewport(0, 0, width, height);
}

bool GLRenderer::CreateGLContext()
{
	//获取设备上下文
	dc = GetDC(hwnd);

	//概念:深度缓冲  模板缓冲区位深
	PIXELFORMATDESCRIPTOR pfd;//???结构体
	ZeroMemory(&pfd, sizeof(pfd));
	pfd.nSize = sizeof(pfd);
	//指定结构体版本号,设置为1
	pfd.nVersion = 1;
	//rgba 4个字节
	pfd.cColorBits = 32;
	//设置深度缓冲 空间物体 对于眼睛有距离  记录这些点的层次
	pfd.cDepthBits = 24;
	//设置模板缓冲区位深  :屏幕上的像素点保留一个无符号的整形
	pfd.cStencilBits = 8;
	//设置像素类型
	pfd.iPixelType = PFD_TYPE_RGBA;
	//可以绘制到窗口   
	// 第三个参数设置双缓冲  机制   有两张图 一个前一个后  前面显示,后面绘画 绘画完了 放在前面  显示放在后面 开始绘画 绘画完了 放在前面 两者交替循环
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;

	int format = 0;
	format = ChoosePixelFormat(dc, &pfd);
	if (!format)
	{
		throw;//实际开发不是这么做
	}
	SetPixelFormat(dc, format, &pfd);
	//openfl上下文
	rc = wglCreateContext(dc);
	return true;
}

运行结果:

有些不明白 的是 渲染前有断时间为空档期 需要等候几秒 ,这个 是渲染的第一次 是这样的吗 

如果是渲染几个不一样的 都要等待的话 是不是 性能有些浪费 ,是不是 哪里会有 初始化的问题 的补助 才导致 第一张 有点 缓冲等待 呢 ?

补充代码 main.cpp:

#include <iostream>
using namespace std;

#include"Engine.h"
 
//APIENTRY  :和C约定的入口
//HINSTANCE  :
//LPWSTR:命令行参数
//int nCmdShow  :窗口显示模式

//量类型 HINSTANCE HINSTANCE 是Windows里的一中数据类型
// ,其实就是一个无符号的长整形,是32位的,是用于标示(记录)一个程序的实例

int APIENTRY wWinMain(_In_  HINSTANCE hIntance, _In_opt_  HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    Engine engine(hIntance, "window_class");
    engine.initialze("window title", 800, 600, nCmdShow);

    int time = 0;
    while (engine.ProcessMessage())
    {
        Sleep(10);
        if (time++ > 200)
        {
            //测试过200秒后就退出  close消息测试
           //engine.Close();
            engine.Render();
       }
    }
    return 0;
}

 
 

engine.h:

#pragma once
#include<Windows.h>
#include<string>

class GLRenderer;
//这里没有引入render.h文件 而是声明 这样做的的优势是什么
class Engine
{

public:

	Engine(HINSTANCE hInstance, std::string window_class);
	~Engine();
	bool initialze(std::string wind_title, int width, int height, int nCmdShow);

	//注册窗口类
	bool RegisterWindowsClass();

	//处理消息的方法
	bool ProcessMessage();


	void Close();

	void  Render();

private:
	HWND handle;//窗口句柄
	HINSTANCE hInstance;//实例句柄

	std::string wind_title;//窗口标题
	std::wstring wind_title_wide;//宽字符标题  用于unicode

	std::string window_class;//窗口类 ??
    std::wstring window_class_wide;

	//窗口 宽高
	int width;
	int height;

	GLRenderer* renderer = nullptr;

private:
	//窗口句柄  消息类型  CALLBACK标准性约定
	static LRESULT CALLBACK HandleMessageSetup(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	//重定向的方法
	static LRESULT HandleMessageRedict(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	//重定向到这个方法
    LRESULT winProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);


	//创建 和销魂
	void OnStart();
	void OnClose();
};

engin,cpp:

#include "Engine.h"

#include"GLRenderer.h"
Engine::Engine(HINSTANCE hInstance, std::string window_class)
{
	this->hInstance = hInstance;
	this->window_class = window_class;
	this->window_class_wide = std::wstring(window_class.begin(), window_class.end());

	RegisterWindowsClass();
}


bool Engine::initialze(std::string wind_title, int width, int height, int nCmdShow)
{
	
	this->wind_title = wind_title;
	this->wind_title_wide = std::wstring(wind_title.begin(), wind_title.end());
	this->width = width;
	this->height = height;
	
	int nWindMertricsX = GetSystemMetrics(SM_CXSCREEN);
	int nWindMertricsY = GetSystemMetrics(SM_CYSCREEN);
	RECT wr;
	wr.left = (nWindMertricsX - width) / 2;
	wr.top = (nWindMertricsY - height) / 2;
	wr.right = wr.left+width;
	wr.bottom= wr.top+height;//上下左右 有其他的可以
	//WS_OVERLAPPEDWINDOW 样式  False不包含菜单
	AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);

	handle=CreateWindowEx(0,//扩展风格

#ifdef UNICODE
		this->window_class_wide.c_str(),
		this->wind_title_wide.c_str(),
#else
		this->window_class.c_str(),
		this->wind_title.c_str(),
#endif // 
		 
		
		WS_OVERLAPPEDWINDOW,//风格
		wr.left,
		wr.top,
		wr.right - wr.left,
		wr.bottom - wr.top,//屏幕上下左右
		NULL,
		NULL,
		hInstance,
		this);

	if (!handle)//窗口句柄
	{
		throw;
		return false;
	}

	OnStart();



	ShowWindow(handle, nCmdShow);//最大化最小化 nCmdshow 显示模式
	UpdateWindow(handle);//更新窗口
	
	SetForegroundWindow(handle);//把窗口激活到前列线程,能接受键盘 鼠标事件
	SetFocus(handle);
	
	 
	return true;
}


bool Engine::RegisterWindowsClass()
{
	WNDCLASSEX wcex;
	//置零
	ZeroMemory(&wcex, sizeof(WNDCLASSEX));
	//WNDCLASSEX大小 
	wcex.cbSize = sizeof(WNDCLASSEX);
	//窗口风格
	wcex.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
	
	//创口处理函数
	 //wcex.lpfnWndProc = DefWindowProc;
	wcex.lpfnWndProc = HandleMessageSetup;


	//wcex.style = WS_OVERLAPPEDWINDOW;
	//wcex.lpfnWndProc = NULL;
	wcex.cbClsExtra = 0;//??
	wcex.cbWndExtra = 0;

	wcex.hInstance = hInstance;
	//默认图标
	wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	//默认光标
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	//画布的背景颜色
	wcex.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
	//设置菜单
	wcex.lpszMenuName = NULL;
	//小图标
	wcex.hIconSm = NULL;

	#ifdef UNICODE

	wcex.lpszClassName = this->window_class_wide.c_str();
	#else
		wcex.lpszClassName = this->window_class.c_str();
	#endif // !UNICODE

	if (!RegisterClassEx(&wcex))
	{
		int error = GetLastError();
		throw;//注意:实际开发中 不能这么做
		return false;
	}
	return true;
}

bool Engine::ProcessMessage()
{
	//定义msg 并且置0
	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));

	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		//转移这份消息
		TranslateMessage(&msg);
		//分发消息
		DispatchMessage(&msg);
	}
	if (msg.message == WM_NULL)
	{
		if (!IsWindow(handle))
			return false;
	}
	if (!handle)
	{
		return false;
	}
	return true;
}

LRESULT Engine::HandleMessageSetup(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

	switch (uMsg)
	{
	case WM_NCCREATE://NCCREATE的消息
	{
		const CREATESTRUCT* pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);

		Engine* engine = reinterpret_cast<Engine*>(pCreate->lpCreateParams);

		if (!engine)
		{
			throw;
		}

		//设置用户数据
		SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(engine));
		//窗口处理函数
		SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(HandleMessageRedict));

		return DefWindowProcW(hwnd, uMsg, wParam, lParam);
	}

	default:
		return DefWindowProcW(hwnd, uMsg, wParam, lParam);
	}
	return LRESULT();
}

LRESULT Engine::HandleMessageRedict(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	Engine* engine = reinterpret_cast<Engine*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
	//return LRESULT();
	return engine->winProc(hwnd, uMsg, wParam, lParam);
}
//窗口处理函数
LRESULT Engine::winProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

	//窗口的生命周期做好
	switch (uMsg)
	{
	case WM_CLOSE:
		 
		DestroyWindow(hwnd);
		this->handle = NULL;
		OnClose();
		return 0;
	case WM_DESTROY:
		//发出退出消息
		PostQuitMessage(0);
		return 0;
	case WM_SIZE:
		//拖动的时候改变大小
		//获取 客户区的大小
		RECT rect;
		GetClientRect(hwnd, &rect);
		if (renderer)
		{
			renderer->Resize(rect.right-rect.left, rect.bottom-rect.top);
		}
		return 0;
	default:
		return DefWindowProcW(hwnd, uMsg, wParam, lParam);
		break;
	}
	//return LRESULT();
	return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

void Engine::OnStart()
{
	if (renderer)
	{
		delete renderer;
	}
	renderer = NULL;//已经要置为空
	renderer = new GLRenderer(handle, width, height);
}

void Engine::OnClose()
{
	//SendMessage(handle, WM_CLOSE, 0, 0)
	delete renderer;;
	renderer = NULL;
}



Engine::~Engine()
{

	if (!UnregisterClass(

#ifdef UNICODE
		this->window_class_wide.c_str(),
#else
		this->window_class.c_str(),
#endif // 
		 hInstance))
	{
		throw;
	}
}

void Engine::Close()
{
	SendMessage(handle, WM_CLOSE, 0, 0);
}

void Engine::Render()
{
	if (renderer)
	{
		renderer->Renderer();
	}
	
}

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值