跟着cherno手搓游戏引擎【15】DrawCall的封装

目标:

 Application.cpp:把渲染循环里的glad代码封装成自己的类:

#include"ytpch.h"
#include "Application.h"

#include"Log.h"
#include "YOTO/Renderer/Renderer.h"
#include"Input.h"


namespace YOTO {
#define BIND_EVENT_FN(x) std::bind(&x, this, std::placeholders::_1)

	 Application* Application::s_Instance = nullptr;

	Application::Application() {

		YT_CORE_ASSERT(!s_Instance, "Application需要为空!")
		s_Instance = this;
		//智能指针
		m_Window = std::unique_ptr<Window>(Window::Creat());
		//设置回调函数
		m_Window->SetEventCallback(BIND_EVENT_FN(Application::OnEvent));
		//new一个Layer,放在最后层进行渲染
		m_ImGuiLayer = new ImGuiLayer();
		PushOverlay(m_ImGuiLayer);  
		//unsigned int id;
		//glGenBuffers(1, &id);

		uint32_t indices[3] = { 0,1,2 };
		float vertices[3 * 7] = {
			-0.5f,-0.5f,0.0f, 0.8f,0.2f,0.8f,1.0f,
			0.5f,-0.5f,0.0f,  0.2f,0.3f,0.8f,1.0f,
			0.0f,0.5f,0.0f,   0.8f,0.8f,0.2f,1.0f,
		};

		m_VertexArray.reset(VertexArray::Create());


		std::shared_ptr<VertexBuffer> m_VertexBuffer;
		m_VertexBuffer.reset(VertexBuffer::Create(vertices, sizeof(vertices)));

		{
			BufferLayout setlayout = {

	{ShaderDataType::Float3,"a_Position"},
		{ShaderDataType::Float4,"a_Color"}
			};
			m_VertexBuffer->SetLayout(setlayout);

		}

		m_VertexArray->AddVertexBuffer(m_VertexBuffer);
		
		 
		std::shared_ptr<IndexBuffer>m_IndexBuffer;
		m_IndexBuffer.reset(IndexBuffer::Create(indices, sizeof(indices)/sizeof(uint32_t)));

		m_VertexArray->AddIndexBuffer(m_IndexBuffer);

		std::string vertexSource = R"(
		#version 330 core
		layout(location = 0) in vec3 a_Position;
		layout(location = 1) in vec4 a_Color;
		out vec3 v_Position;
		out vec4 v_Color;
		void main(){
		v_Position=a_Position;
		v_Color=a_Color;
		gl_Position =vec4( a_Position+0.5,1.0);
		}
		)";
		//绘制颜色
		std::string fragmentSource = R"(
		#version 330 core
		layout(location = 0) out vec4 color;
		in vec3 v_Position;
		in vec4 v_Color;
		void main(){
		color=vec4(v_Color);
		}
		)";
		m_Shader.reset(new Shader(vertexSource, fragmentSource));

		///测试/

		m_SquareVA.reset(VertexArray::Create());

		float squareVertices[3 * 4] = {
			-0.5f,-0.5f,0.0f,
			0.5f,-0.5f,0.0f, 
			0.5f,0.5f,0.0f,
			-0.5f,0.5f,0.0f
		};
		std::shared_ptr<VertexBuffer> squareVB;
		squareVB.reset(VertexBuffer::Create(squareVertices, sizeof(squareVertices)));
		squareVB->SetLayout({
			{ShaderDataType::Float3,"a_Position"}
		});
		m_SquareVA->AddVertexBuffer(squareVB);
		uint32_t squareIndices[6] = { 0,1,2,2,3,0 };
		std::shared_ptr<IndexBuffer> squareIB; 

		squareIB.reset((IndexBuffer::Create(squareIndices, sizeof(squareIndices) / sizeof(uint32_t))));

		m_SquareVA->AddIndexBuffer(squareIB);
		
		//测试:
		std::string BlueShaderVertexSource = R"(
		#version 330 core
		layout(location = 0) in vec3 a_Position;
		out vec3 v_Position;
		void main(){
		v_Position=a_Position;
		gl_Position =vec4( a_Position,1.0);
		}
		)";
		//绘制颜色
		std::string BlueShaderFragmentSource = R"(
		#version 330 core
		layout(location = 0) out vec4 color;
		in vec3 v_Position;
		void main(){
		color=vec4(0.2,0.3,0.8,1.0);
		}
		)";
		m_BlueShader.reset(new Shader(BlueShaderVertexSource, BlueShaderFragmentSource));
	}
	Application::~Application() {

	}
	/// <summary>
	/// 所有的Window事件都会在这触发,作为参数e
	/// </summary>
	/// <param name="e"></param>
	void Application::OnEvent(Event& e) {
		//根据事件类型绑定对应事件
		EventDispatcher dispatcher(e);
		dispatcher.Dispatch<WindowCloseEvent>(BIND_EVENT_FN(Application::OnWindowClosed));
		//输出事件信息
		YT_CORE_INFO("Application:{0}",e);
		for (auto it = m_LayerStack.end(); it != m_LayerStack.begin();) {
			(*--it)->OnEvent(e);
			if (e.m_Handled)
				break;
		}
	}

	bool Application::OnWindowClosed(WindowCloseEvent& e) {
		m_Running = false;
		return true;
	}
	void Application::Run() {
		WindowResizeEvent e(1280, 720);
		if (e.IsInCategory(EventCategoryApplication)) {
			YT_CORE_TRACE(e);
		}
		if (e.IsInCategory(EventCategoryInput)) {
			YT_CORE_ERROR(e);
		}

		while (m_Running)
		{
			/*	glClearColor(0.2f, 0.2f, 0.2f,1);
				glClear(GL_COLOR_BUFFER_BIT);*/
			RenderCommand::SetClearColor({0.2f, 0.2f, 0.2f, 1.0f});
			RenderCommand::Clear();

			Renderer::BeginScene();
			{
				m_BlueShader->Bind();
				Renderer::Submit(m_SquareVA);
				m_Shader->Bind();
				Renderer::Submit(m_VertexArray);
				Renderer::EndScene();
			}

	

			//m_BlueShader->Bind();
			//m_SquareVA->Bind();
			//glDrawElements(GL_TRIANGLES, m_SquareVA->GetIndexBuffer()->GetCount(), GL_UNSIGNED_INT, nullptr);
			glBindVertexArray(m_VertexArray);
			//m_Shader->Bind();
			//m_VertexArray->Bind();
			//glDrawElements(GL_TRIANGLES,m_VertexArray->GetIndexBuffer()->GetCount(),GL_UNSIGNED_INT,nullptr); 

			for (Layer* layer : m_LayerStack) {
				layer->OnUpdate();
			}
			//将ImGui的刷新放到APP中,与Update分开
			m_ImGuiLayer->Begin();
			
			for (Layer* layer : m_LayerStack) {
				layer->OnImGuiRender();
			}
			m_ImGuiLayer->End();
			m_Window->OnUpdate();
		}
	}
	void Application::PushLayer(Layer* layer) {
		m_LayerStack.PushLayer(layer);
		layer->OnAttach();
	}
	void Application::PushOverlay(Layer* layer) {
		m_LayerStack.PushOverlay(layer);
		layer->OnAttach();
	}
}

抽象:

RendererAPI.h:渲染API的抽象,包括API实现的功能都封装一下:

#pragma once
#include<glm/glm.hpp>
#include "VertexArray.h"
namespace YOTO {
	class RendererAPI
	{
	public:
		enum class API {
			None = 0,
			OpenGL = 1
		};
	public:
		virtual void SetClearColor(const glm::vec4& color)=0;
		virtual void Clear() = 0;
		virtual void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray)=0;	

		inline static API GetAPI() { return s_API; }
	private:
		static API s_API;
	};
}


 RendererAPI.cpp:给当前API赋值:

#include "ytpch.h"
#include "RendererAPI.h"
namespace YOTO {
	RendererAPI::API RendererAPI::s_API = RendererAPI::API::OpenGL;
}

 实现:

OpenGLRendererAPI.h:实现接口,制定重写方法,在cpp中封账glad代码:

#pragma once
#include"YOTO/Renderer/RendererAPI.h"
namespace YOTO {
	class OpenGLRendererAPI:public RendererAPI
	{
	public:
		virtual void SetClearColor(const glm::vec4& color)override;
		virtual void Clear()override;
		virtual void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray) override;
	};
}


 OpenGLRendererAPI.cpp:

#include "ytpch.h"
#include "OpenGLRendererAPI.h"
#include <glad/glad.h>
namespace YOTO {
	void OpenGLRendererAPI::SetClearColor(const glm::vec4& color)
	{
		glClearColor(color.r, color.g, color.b, color.a);
	}
	void OpenGLRendererAPI::Clear()
	{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	}
	void OpenGLRendererAPI::DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray)
	{
		glDrawElements(GL_TRIANGLES, vertexArray->GetIndexBuffer()->GetCount(), GL_UNSIGNED_INT, nullptr);
	}
}

调用:

RenderCommand.h:根据当前API调用API的一些通用方法:

#pragma once
#include"RendererAPI.h"
namespace YOTO {
	class RenderCommand
	{
	public:
		inline static void SetClearColor(const glm::vec4& color) {
			s_RendererAPI->SetClearColor(color);
		}
		inline static void Clear() {
			s_RendererAPI->Clear();
		}
		inline static void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray) {
			s_RendererAPI->DrawIndexed(vertexArray);
		}
	private:
		static RendererAPI* s_RendererAPI;

	};

}

 RenderCommand.cpp:(个人觉得应该在new的时候再给API的枚举赋值,在 RendererAPI

.cpp中导致可以new 其他API枚举选另一个API)(不知道后面会不会改)

#include "ytpch.h"
#include "RenderCommand.h"
#include"Platform/OpenGL/OpenGLRendererAPI.h"
namespace YOTO {
	RendererAPI* RenderCommand::s_RendererAPI = new OpenGLRendererAPI;
}

Renderer.h: 对command的一些方法进行进一步封装,并拓展出Begin和End方法:

#pragma once
#include"RenderCommand.h"
namespace YOTO {
	
	class Renderer {
	public:
		static void BeginScene();
		static void EndScene();
		static void Submit(const std::shared_ptr<VertexArray>& vertexArray);
		inline static RendererAPI::API GetAPI() {
			return RendererAPI::GetAPI();
		}
	};

}

Renderer.cpp: 

#include"ytpch.h"
#include"Renderer.h"
namespace YOTO {
	void Renderer::BeginScene()
	{
	}
	void Renderer::EndScene()
	{
	}
	void Renderer::Submit(const std::shared_ptr<VertexArray>& vertexArray)
	{
		vertexArray->Bind();
		RenderCommand::DrawIndexed(vertexArray);
	}
}

修改:

所有switch的枚举都改成这样(会报错,报了再改也行)

RendererAPI::API::OpenGL:

测试:

 原汁原味儿~能跑出来就对了!