跟着cherno手搓游戏引擎【25】封装2DRenderer,封装shader传参,自定义Texture

封装2DRenderer:

Renderer.h:

#include"ytpch.h"
#include"Renderer.h"
#include <Platform/OpenGL/OpenGLShader.h>
#include"Renderer2D.h"
namespace YOTO {
	Renderer::SceneData* Renderer::m_SceneData = new	Renderer::SceneData;
	void Renderer::Init()
	{
		RenderCommand::Init();
		Renderer2D::Init();
	}
	void Renderer::OnWindowResize(uint32_t width, uint32_t height)
	{
		RenderCommand::SetViewport(0, 0, width, height);
	}
	void Renderer::BeginScene(OrthographicCamera& camera)
	{
		m_SceneData->ViewProjectionMatrix = camera.GetViewProjectionMatrix();
	}
	void Renderer::EndScene()
	{
	}
	void Renderer::Submit(const Ref<Shader>& shader, const Ref<VertexArray>& vertexArray, const glm::mat4& transform)
	{
		shader->Bind();
		std::dynamic_pointer_cast<OpenGLShader>(shader)->UploadUniformMat4("u_ViewProjection", m_SceneData->ViewProjectionMatrix);
		std::dynamic_pointer_cast<OpenGLShader>(shader)->UploadUniformMat4("u_Transform", transform);
	/*	mi.Bind();*/

		vertexArray->Bind();
		RenderCommand::DrawIndexed(vertexArray);
	}
}

Renderer2D.h:专门渲染2D的类,负责“画什么”的问题

#pragma once
#include "OrthographicCamera.h"
#include"Texture.h"
namespace YOTO {
	class Renderer2D
	{
	public:
		//为什么渲染器是静态的:
		static void Init();
		static void ShutDown();
		static void BeginScene(const OrthographicCamera& camera);
		static void EndScene();
		static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color);
		static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color);
		static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref<Texture2D> texture);
		static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref<Texture2D> texture);
	private:
	private:

	};
}


 Renderer2D.cpp:

#include "ytpch.h"
#include "Renderer2D.h"
#include"VertexArray.h"
#include"Shader.h"
//#include "Platform/OpenGL/OpenGLShader.h"
#include <glm/gtc/matrix_transform.hpp>
#include "RenderCommand.h"
namespace YOTO {
	struct  Renderer2DStorage {
		Ref<VertexArray> QuadVertexArray;
		//Ref<Shader> FlatColorShader;
		Ref<Shader> TextureShader;
		Ref<Texture2D> WhiteTexture;
	};
	static Renderer2DStorage* s_Data;
	void Renderer2D::Init()
	{
		s_Data = new  Renderer2DStorage();
		s_Data->QuadVertexArray = VertexArray::Create();

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

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

		s_Data->QuadVertexArray->AddIndexBuffer(squareIB);

		s_Data->WhiteTexture = Texture2D::Create(1, 1);
		uint32_t whiteTextureData = 0xffffffff;
		s_Data->WhiteTexture->SetData(&whiteTextureData,sizeof(uint32_t));

		//s_Data->FlatColorShader =Shader::Create("assets/shaders/FlatColor.glsl");
		s_Data->TextureShader= Shader::Create("assets/shaders/Texture.glsl");
		s_Data->TextureShader->Bind();
		s_Data->TextureShader->SetInt("u_Texture", 0);

	}
	void Renderer2D::ShutDown()
	{
		delete s_Data;
	}
	void Renderer2D::BeginScene(const OrthographicCamera& camera)
	{
		/*s_Data->FlatColorShader->Bind();
		s_Data->FlatColorShader->SetMat4("u_ViewProjection",camera.GetViewProjectionMatrix());*/
		s_Data->TextureShader->Bind();
		s_Data->TextureShader->SetMat4("u_ViewProjection", camera.GetViewProjectionMatrix());
	
	}
	void Renderer2D::EndScene()
	{
	}
	void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color)
	{
		DrawQuad({ position.x,position.y,0.0f }, size, color);
	}
	void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color)
	{
		//s_Data->FlatColorShader->Bind();
		//s_Data->FlatColorShader->SetFloat4("u_Color", color);
		//s_Data->TextureShader->Bind();
		s_Data->TextureShader->SetFloat4("u_Color", color);
		s_Data->WhiteTexture->Bind();

		glm::mat4 transform = glm::translate(glm::mat4(1.0f), position) /**rotation*/ * glm::scale(glm::mat4(1.0f), {size.x,size.y,1.0f});
		s_Data->TextureShader->SetMat4("u_Transform", transform);
		s_Data->QuadVertexArray->Bind();
		RenderCommand::DrawIndexed(s_Data->QuadVertexArray);
	}
	void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref<Texture2D> texture)
	{
		DrawQuad({ position.x,position.y,0.0f }, size, texture);
	}
	void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref<Texture2D> texture)
	{
		//s_Data->TextureShader->Bind();
		s_Data->TextureShader->SetFloat4("u_Color", {0.2f,0.3f,0.8f,0.5f});
		texture->Bind();


		glm::mat4 transform = glm::translate(glm::mat4(1.0f), position) /**rotation*/ * glm::scale(glm::mat4(1.0f), { size.x,size.y,1.0f });
		s_Data->TextureShader->SetMat4("u_Transform", transform);

		s_Data->QuadVertexArray->Bind();
		RenderCommand::DrawIndexed(s_Data->QuadVertexArray);
		
	}
}

封装Shader传参:

Shader.h:添加SetInt、SetFloat3...等等Set方法

#pragma once
#include <string>
#include<glm/glm.hpp>
namespace YOTO {

	class Shader {

	public:
		virtual~Shader()=default;
		virtual void Bind()const=0;
		virtual void UnBind()const=0;

		virtual void SetInt(const std::string& name,int value) = 0;
		virtual void SetFloat3(const std::string& name, const glm::vec3& value) = 0;
		virtual void SetFloat4(const std::string& name, const glm::vec4& value) = 0;
		virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0;

		virtual const std::string& GetName()const = 0;

		static Ref<Shader> Create(const std::string& filepath);
		static Ref<Shader> Create(const std::string&name, const std::string& vertexSrc, const std::string& fragmentSrc);

	};
	class ShaderLibrary {
	public:
		void Add(const Ref<Shader>& shader);
		void Add(const std::string &name,const Ref<Shader>& shader);
		Ref<Shader> Load(const std::string filepath);
		Ref<Shader> Load(const std::string &name,const std::string filepath);
		Ref<Shader> Get(const std::string& name);
		bool Exists(const std::string& name);
	private:
		std::unordered_map<std::string,Ref<Shader>> m_Shaders;

	};
}

OpenGLShader.h:同Shader.h

#pragma once
#include <string>
#include "YOTO/Renderer/Shader.h"
#include <glm/glm.hpp>
typedef unsigned int GLenum;
namespace YOTO {

	class OpenGLShader:public Shader {

	public:
		OpenGLShader(const std::string& filepath);
		OpenGLShader(const std::string &name,const std::string& vertexSrc, const std::string& fragmentSrc);
		~OpenGLShader();
		void Bind()const override;
		void UnBind()const override;

		virtual void SetInt(const std::string& name, int value) override;
		virtual void SetFloat3(const std::string& name, const glm::vec3& value) override;
		virtual void SetFloat4(const std::string& name, const glm::vec4& value)override;
		virtual void SetMat4(const std::string& name, const glm::mat4& value) override;

		virtual const std::string& GetName()const override { return m_Name; }
		void UploadUniformMat4(const std::string& name, const glm::mat4& matrix);
		void UploadUniformMat3(const std::string& name, const glm::mat3& matrix);

		void UploadUniformFloat4(const std::string& name, const glm::vec4& values);
		void UploadUniformFloat3(const std::string& name, const glm::vec3& values);
		void UploadUniformFloat2(const std::string& name, const glm::vec2& values);
		void UploadUniformFloat(const std::string& name, float values);

		void UploadUniformInt(const std::string& name, int values);
	private:
		std::string ReadFile(const std::string filepath);
		std::unordered_map<GLenum,std::string> PreProcess(const std::string& source);
		void Compile(const std::unordered_map<GLenum, std::string>& shaderSources);
	private:
		uint32_t m_RendererID;
		std::string m_Name;
	}
	;
} 

OpenGLShader.cpp: 

#include "ytpch.h"
#include "OpenGLShader.h"

#include <glad/glad.h>
#include<glm/gtc/type_ptr.hpp>
namespace YOTO {
	static GLenum ShaderTypeFromString(const std::string& type) {
		if (type == "vertex") {
			return GL_VERTEX_SHADER;
		}
		if (type == "fragment" || type == "pixel") {
			return GL_FRAGMENT_SHADER;
		}
		YT_CORE_ASSERT(false, "不知道的shader类型");
		return 0;
	}
	
	OpenGLShader::OpenGLShader(const std::string& filepath)
	{
		std::string source = ReadFile(filepath);
		YT_CORE_ASSERT(source.size(), "GLSL读取的字符串为空");
		auto shaderSources = PreProcess(source);
		Compile(shaderSources);


		auto lastSlash = filepath.find_last_of("/\\");
		lastSlash = lastSlash == std::string::npos ? 0 : lastSlash + 1;
		auto lastDot = filepath.rfind('.');
		auto count = lastDot == std::string::npos ? filepath.size() - lastSlash : lastDot - lastSlash;
		m_Name=filepath.substr(lastSlash, count);
	}
	OpenGLShader::OpenGLShader(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc)
	:m_Name(name){
		std::unordered_map<GLenum, std::string >sources;
		sources[GL_VERTEX_SHADER] = vertexSrc;
		sources[GL_FRAGMENT_SHADER] = fragmentSrc;
		Compile(sources);
	}
	OpenGLShader::~OpenGLShader()
	{
		glDeleteProgram(m_RendererID);
	}

	std::string OpenGLShader::ReadFile(const std::string filepath)
	{
		std::string result;
		std::ifstream in(filepath, std::ios::in | std::ios::binary);
		if (in) {
			in.seekg(0, std::ios::end);			// 将指针放在最后面
			result.resize(in.tellg());			// 初始化string的大小, in.tellg()返回位置
			in.seekg(0, std::ios::beg);			// in指回头部
			in.read(&result[0], result.size());	// in读入放在result指向的内存中
		}
		else {
			YT_CORE_ERROR("不能打开文件:{0}", filepath);
		}
		return result;
	}
	std::unordered_map<GLenum, std::string> OpenGLShader::PreProcess(const std::string& source)
	{
		std::unordered_map<GLenum, std::string> shaderSources;

		std::string typeToken = "#type";
		size_t typeTokenLen = typeToken.size();
		size_t findCurPos = source.find(typeToken, 0);
		size_t findNextPos = findCurPos;
		while (findNextPos != std::string::npos) {
			size_t curlineEndPos = source.find_first_of("\r\n", findCurPos);///r/n写错为/r/n
			YT_CORE_ASSERT(curlineEndPos != std::string::npos, "解析shader失败");
			size_t begin = findCurPos + typeTokenLen + 1;

			std::string type = source.substr(begin, curlineEndPos - begin);// 获取到是vertex还是fragment
			YT_CORE_ASSERT(ShaderTypeFromString(type), "无效的shader的类型	");

			size_t nextLinePos = source.find_first_not_of("\r\n", curlineEndPos);
			findNextPos = source.find(typeToken, nextLinePos);
			// 获取到具体的shader代码
			shaderSources[ShaderTypeFromString(type)] = source.substr(nextLinePos, findNextPos - (nextLinePos == std::string::npos ? source.size() - 1 : nextLinePos));

			findCurPos = findNextPos;
		}
		return shaderSources;
		/*
			用find,而不是find_firtst_of,因为
			find返回完全匹配的字符串的的位置;
			find_first_of返回被查匹配字符串中某个字符的第一次出现位置。

			std::string::npos是一个非常大的数
			source.substr(0, source.size() + 10000)截取到从头到末尾,不会报错
		*/
	}

	void OpenGLShader::Compile(const std::unordered_map<GLenum, std::string>& shaderSources)
	{
		GLuint program = glCreateProgram();
		YT_CORE_ASSERT(shaderSources.size()<=2,"OpenGLShader:shader只支持两种!")
		std::array<GLenum,2>glShaderIDs;
		int glShaderIDIndex=0;
		for (auto& kv : shaderSources) {
			GLenum type = kv.first;
			const std::string& source = kv.second;
			// Create an empty vertex shader handle
			GLuint shader = glCreateShader(type);
			// Send the vertex shader source code to GL
			// Note that std::string's .c_str is NULL character terminated.
			const GLchar* sourceCStr = source.c_str();
			glShaderSource(shader, 1, &sourceCStr, 0);
			// Compile the vertex shader
			glCompileShader(shader);
			GLint isCompiled = 0;
			glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
			if (isCompiled == GL_FALSE)
			{
				GLint maxLength = 0;
				glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
				// The maxLength includes the NULL character
				std::vector<GLchar> infoLog(maxLength);
				glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]);
				// We don't need the shader anymore.
				glDeleteShader(shader);
				// Use the infoLog as you see fit.
				// In this simple program, we'll just leave
				YT_CORE_ERROR("{0} ", infoLog.data());
				YT_CORE_ASSERT(false, "shader 编译失败!");
				break;
			}
			// Attach our shaders to our program
			glAttachShader(program, shader);
			glShaderIDs[glShaderIDIndex++]=shader;
		}

		// Link our program
		glLinkProgram(program);
		// Note the different functions here: glGetProgram* instead of glGetShader*.
		GLint isLinked = 0;
		glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked);
		if (isLinked == GL_FALSE)
		{
			GLint maxLength = 0;
			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
			// The maxLength includes the NULL character
			std::vector<GLchar> infoLog(maxLength);
			glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
			// We don't need the program anymore.
			glDeleteProgram(program);
			// Don't leak shaders either.
			for (auto id : glShaderIDs) {
				glDeleteShader(id);
			}
			// Use the infoLog as you see fit.
			// In this simple program, we'll just leave
			YT_CORE_ERROR("{0} ", infoLog.data());
			YT_CORE_ASSERT(false, "shader link failure!");
			return;
		}
		// Always detach shaders after a successful link.
		for (auto id : glShaderIDs) {
			glDetachShader(program, id);
		}
		m_RendererID = program;

	}

	void OpenGLShader::Bind() const
	{
		glUseProgram(m_RendererID);
	}
	void OpenGLShader::UnBind() const
	{
		glUseProgram(0);
	}
	void OpenGLShader::SetInt(const std::string& name, int value)
	{
		UploadUniformInt(name, value);
	}
	void OpenGLShader::SetFloat3(const std::string& name, const glm::vec3& value)
	{
		UploadUniformFloat3(name, value);
	}
	void OpenGLShader::SetFloat4(const std::string& name, const glm::vec4& value)
	{
		UploadUniformFloat4(name, value);
	}
	void OpenGLShader::SetMat4(const std::string& name, const glm::mat4& value)
	{
		UploadUniformMat4(name, value);
	}
	void OpenGLShader::UploadUniformMat4(const std::string& name, const glm::mat4& matrix)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniformMatrix4fv(loacation, 1, GL_FALSE, glm::value_ptr(matrix));

	}
	void OpenGLShader::UploadUniformMat3(const std::string& name, const glm::mat3& matrix)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniformMatrix3fv(loacation, 1, GL_FALSE, glm::value_ptr(matrix)); 
	}
	void OpenGLShader::UploadUniformFloat4(const std::string& name, const glm::vec4& values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform4f(loacation, values.x, values.y, values.z, values.w);

	}
	void OpenGLShader::UploadUniformFloat3(const std::string& name, const glm::vec3& values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform3f(loacation, values.x, values.y, values.z);
	}
	void OpenGLShader::UploadUniformFloat2(const std::string& name, const glm::vec2& values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform2f(loacation, values.x, values.y);
	}
	void OpenGLShader::UploadUniformFloat(const std::string& name, float values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform1f(loacation, values);
	}
	void OpenGLShader::UploadUniformInt(const std::string& name, int values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform1i(loacation, values);
	}
	
}

添加自定义Texture方法:

Texture.h:添加新的Create方法:根据宽高添加

#pragma once
namespace YOTO {
	class Texture
	{
	public:
		virtual ~Texture() = default;
		virtual uint32_t GetWidth()const = 0;
		virtual uint32_t GetHeight()const = 0;
		virtual void SetData(void* data, uint32_t size) = 0;
		virtual void Bind(uint32_t slot=0)const = 0;

	};
	class Texture2D :public Texture 
	{
	public:
		static Ref<Texture2D>Create(uint32_t width,uint32_t height);
		static Ref<Texture2D>Create(const std::string& path);
	};
}


Texture.cpp: 

#include "ytpch.h"
#include "Texture.h"
#include"Renderer.h"
#include "Platform/OpenGL/OpenGLTexture.h"
namespace YOTO {
	Ref<Texture2D> Texture2D::Create(uint32_t width, uint32_t height)
	{
		switch (Renderer::GetAPI())
		{
		case RendererAPI::API::None:
			YT_CORE_ASSERT(false, "Texture2D:API为None不支持");
			return nullptr;
		case RendererAPI::API::OpenGL:
			return  CreateRef<OpenGLTexture2D>(width,height);
		}
		YT_CORE_ASSERT(false, "Buffer:未知API");
		return nullptr;
	}
	Ref<Texture2D> Texture2D::Create(const std::string& path)
	{
		switch (Renderer::GetAPI())
		{
		case RendererAPI::API::None:
			YT_CORE_ASSERT(false, "Texture2D:API为None不支持");
			return nullptr;
		case RendererAPI::API::OpenGL:
			return  CreateRef<OpenGLTexture2D>(path);
		}
		YT_CORE_ASSERT(false, "Buffer:未知API");
		return nullptr;
	}
}

OpenGLTexture.h:同Texture.h相同,且添加设置texture数据的方法SetData:

#pragma once
#include"YOTO/Renderer/Texture.h"
#include<glad/glad.h>
namespace YOTO {
	class OpenGLTexture2D:public Texture2D
	{
	public:
		OpenGLTexture2D(uint32_t width,uint32_t height);
		OpenGLTexture2D(const std::string path);
		virtual~OpenGLTexture2D();
		virtual uint32_t GetWidth()const override { return m_Width; }
		virtual uint32_t GetHeight()const override { return m_Height; }
	
		virtual void SetData(void* data, uint32_t size)override;

		virtual void Bind(uint32_t slot=0)const override;
	private:
		std::string m_Path;
		uint32_t m_Width, m_Height;
		uint32_t m_RendererID;
		GLenum m_InternalFormat, m_DataFormat;
	};
}


OpenGLTexture.cpp: 

#include "ytpch.h"
#include "OpenGLTexture.h"
#include<glad/glad.h>
#include"stb_image.h"
namespace YOTO {
	OpenGLTexture2D::OpenGLTexture2D(uint32_t width, uint32_t height)
		:m_Width(width),m_Height(height)
	{
		m_InternalFormat = GL_RGBA8;
		m_DataFormat = GL_RGBA;
		
	
			glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID);
		///告诉OpenGLm_RendererID的纹理存储的是rbg8位,宽高的缓冲区
		glTextureStorage2D(m_RendererID, 1, m_InternalFormat, m_Width, m_Height);
		//配置参数:纹理放大时用周围颜色的平均值过滤
		glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

		glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);

	
	}
	OpenGLTexture2D::OpenGLTexture2D(const std::string path)
		:m_Path(path)
	{
		int width, height, channels;
		stbi_set_flip_vertically_on_load(1);//翻转
		stbi_uc*data=stbi_load(path.c_str(),&width,&height,&channels,0);
		YT_CORE_ASSERT(data, "图片加载错误");
		m_Width = width;
		m_Height = height;

		GLenum internalFormat = 0,dataFormat=0;
		if (channels == 4) {
			internalFormat = GL_RGBA8;
			dataFormat = GL_RGBA;
		}
		else if (channels==3) {
			internalFormat = GL_RGB8;
			dataFormat = GL_RGB;
		}

		m_InternalFormat = internalFormat;
		m_DataFormat = dataFormat;

		YT_CORE_ASSERT(internalFormat& dataFormat,"OpenGLTexture2D:不支持的颜色格式")
		//创建纹理
		glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID);
		///告诉OpenGLm_RendererID的纹理存储的是rbg8位,宽高的缓冲区
		glTextureStorage2D(m_RendererID, 1, internalFormat,m_Width,m_Height);
		//配置参数:纹理放大时用周围颜色的平均值过滤
		glTextureParameteri(m_RendererID,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

		glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);

		glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, dataFormat,GL_UNSIGNED_BYTE,data);
		stbi_image_free(data);
	}
	OpenGLTexture2D::~OpenGLTexture2D()
	{
		glDeleteTextures(1,&m_RendererID);
	}
	void OpenGLTexture2D::SetData(void* data, uint32_t size)
	{
		uint32_t bpc = m_DataFormat == GL_RGBA ? 4 : 3;
		YT_CORE_ASSERT(size == m_Width * m_Height * bpc,"OpenGLTexture2D:数据必须是完整的!");
		glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height,m_DataFormat, GL_UNSIGNED_BYTE,data);
	}
	void OpenGLTexture2D::Bind(uint32_t slot) const
	{
		glBindTextureUnit(slot, m_RendererID);
	}
}

Sandbox2D.h:添加m_CheckerboardTexture

#pragma once
#include "YOTO.h"
class Sandbox2D :public YOTO::Layer
{public:
	Sandbox2D();
	virtual ~Sandbox2D() = default;
	virtual void OnAttach()override;
	virtual void OnDetach()override;

	void OnUpdate(YOTO::Timestep ts)override;
	virtual void OnImGuiRender() override;
	void OnEvent(YOTO::Event& e)override;
private:
	YOTO::OrthographicCameraController m_CameraController;

	YOTO::Ref<YOTO::Shader> m_FlatColorShader;
	YOTO::Ref<YOTO::VertexArray> m_SquareVA;
	YOTO::Ref<YOTO::Texture2D>m_CheckerboardTexture;
	glm::vec4 m_SquareColor = { 0.2f,0.3f,0.7f,1.0f };
};

化简Sandbox2D:

Sandbox2D.cpp:把传shader参数的代码注释掉 ,统一使用DrawQuad封装;负责“怎么画”的问题:

#include "Sandbox2D.h"
#include <imgui/imgui.h>
#include <glm/gtc/matrix_transform.hpp>
//#include <Platform/OpenGL/OpenGLShader.h>
#include <glm/gtc/type_ptr.hpp>
Sandbox2D::Sandbox2D()
:Layer("Sandbox2D"), m_CameraController(1280.0f / 720.0f, true) 
{
}
void Sandbox2D::OnAttach()
{
	m_CheckerboardTexture = YOTO::Texture2D::Create("assets/textures/Checkerboard.png");

}
void Sandbox2D::OnDetach()
{
}

void Sandbox2D::OnUpdate(YOTO::Timestep ts)
{	//update
	m_CameraController.OnUpdate(ts);

	//Render
	YOTO::RenderCommand::SetClearColor({ 0.2f, 0.2f, 0.2f, 1.0f });
	YOTO::RenderCommand::Clear();

	YOTO::Renderer2D::BeginScene(m_CameraController.GetCamera());
	{
		static glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(0.1f));
		glm::vec4  redColor(0.8f, 0.3f, 0.3f, 1.0f);
		glm::vec4  blueColor(0.2f, 0.3f, 0.8f, 1.0f);


		/*std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_FlatColorShader)->Bind();
		std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_FlatColorShader)->UploadUniformFloat4("u_Color", m_SquareColor);
		YOTO::Renderer::Submit(m_FlatColorShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));*/

		YOTO::Renderer2D::DrawQuad({ -1.0f,0.0f }, { 0.8f,0.8f }, {0.8f,0.2f,0.3f,1.0f});
		YOTO::Renderer2D::DrawQuad({ 0.5f,-0.5f }, { 0.5f,0.75f }, { 0.2f,0.3f,0.8f,1.0f });
		YOTO::Renderer2D::DrawQuad({ 0.0f,0.0f,-0.1f }, {10.0f,10.0f }, m_CheckerboardTexture);
		YOTO::Renderer2D::EndScene();
	}
}
void Sandbox2D::OnImGuiRender()
{
	ImGui::Begin("设置");
	ImGui::ColorEdit4("正方形颜色", glm::value_ptr(m_SquareColor));
	ImGui::End();
}

void Sandbox2D::OnEvent(YOTO::Event& e)
{
	m_CameraController.OnEvent(e);
}

小修改:

OpenGLRendererAPI.cpp:DrawIndexed中添加解绑Texture:

#include "ytpch.h"
#include "OpenGLRendererAPI.h"
#include <glad/glad.h>
namespace YOTO {
	void OpenGLRendererAPI::Init()
	{
		//启用混合
		glEnable(GL_BLEND);
		//设置混合函数
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		//深度测试
		glEnable(GL_DEPTH_TEST);
	}
	void OpenGLRendererAPI::SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
	{
		glViewport(x, y, width, height);
	}
	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 Ref<VertexArray>& vertexArray)
	{
		glDrawElements(GL_TRIANGLES, vertexArray->GetIndexBuffer()->GetCount(), GL_UNSIGNED_INT, nullptr);
		glBindTexture(GL_TEXTURE_2D, 0);
	}
}

flatColor.glsl:

		#type vertex
		#version 330 core
		layout(location = 0) in vec3 a_Position;

		uniform mat4 u_ViewProjection;
		uniform mat4 u_Transform;
		


		void main(){
		gl_Position =u_ViewProjection*u_Transform*vec4( a_Position,1.0);
		}

		#type fragment
		#version 330 core
		layout(location = 0) out vec4 color;
	
		uniform vec4 u_Color ;
		void main(){
		color =u_Color;	
		}
		

Texture.glsl:

		#type vertex
		#version 330 core
		layout(location = 0) in vec3 a_Position;
		layout(location = 1) in vec2 a_TexCoord;

		uniform mat4 u_ViewProjection;
		uniform mat4 u_Transform;
		
		out vec2 v_TexCoord;
		out vec3 v_Position;

		void main(){
		v_TexCoord=a_TexCoord;
		v_Position=a_Position;
		gl_Position =u_ViewProjection*u_Transform*vec4( a_Position,1.0);
		}

		#type fragment
		#version 330 core
		layout(location = 0) out vec4 color;
		in vec3 v_Position;
	
		in vec2 v_TexCoord;

		uniform vec4 u_Color ;
		uniform sampler2D u_Texture ;
		void main(){
		color = texture(u_Texture, v_TexCoord*10.0f)*u_Color;	
		}
		

YOTO.h:添加:

#include"YOTO/Renderer/Renderer2D.h"

Core.h:

#pragma once
#include<memory>
//用于dll的宏
#ifdef YT_PLATFORM_WINDOWS
#if YT_DYNAMIC_LINK
		#ifdef YT_BUILD_DLL
		#define YOTO_API __declspec(dllexport) 
		#else
		#define YOTO_API __declspec(dllimport) 

		#endif // DEBUG
#else
		#define YOTO_API
#endif
#else
#error YOTO_ONLY_SUPPORT_WINDOWS
#endif // YOTO_PLATFORM_WINDOWS

#ifdef YT_DEBUG
#define YT_ENABLE_ASSERTS
#endif

#ifdef YT_ENABLE_ASSERTS
#define YT_CLIENT_ASSERT(x,...) {if(!(x)){YT_CLIENT_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#define YT_CORE_ASSERT(x,...) {if(!(x)){YT_CORE_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#else
#define YT_CLIENT_ASSERT(x,...)
#define YT_CORE_ASSERT(x,...)

#endif // YT_ENABLE_ASSERTS



#define BIT(x)(1<<x)
//绑定事件定义
#define YT_BIND_EVENT_FN(fn) std::bind(&fn, this, std::placeholders::_1)

namespace YOTO {
	template<typename T>
	using  Scope = std::unique_ptr<T>;
	template<typename T>
	using  Ref = std::shared_ptr<T>;

	template<typename T,typename ...Args>
	constexpr Scope<T> CreateScope(Args&&...args) {
		return std::make_shared<T>(std::forward<Args>(args)...);
	}
	template<typename T, typename ...Args>
	constexpr Ref<T> CreateRef(Args&&...args) {
		return std::make_shared<T>(std::forward<Args>(args)...);
	}

}

测试:

cool! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/410376.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【计算机网络】应用层自定义协议

自定义协议 一、为什么需要自定义协议&#xff1f;二、网络版计算器1. 基本要求2. 序列化和反序列化3. 代码实现&#xff08;1&#xff09;封装 socket&#xff08;2&#xff09;定制协议和序列化反序列化&#xff08;3&#xff09;客户端&#xff08;4&#xff09;计算器服务端…

【星海随笔】存储硬盘基础信息科普

市场上的磁盘分类有&#xff1a;IDE磁盘&#xff08;多用于PC机&#xff09;、SATA磁盘、SAS磁盘、SSD磁盘等 IDE 易于使用与价格低廉&#xff0c;问世后成为最为普及的磁盘接口。 速度慢、速度慢、速度慢。 ATA-7是ATA接口的最后一个版本&#xff0c;也叫ATA133。ATA133接口支…

MyBatis使⽤PageHelper(MySQL)

MyBatis使⽤PageHelper&#xff08;MySQL&#xff09; 一、 limit分⻚二、PageHelper插件第⼀步&#xff1a;引⼊依赖第⼆步&#xff1a;在mybatis-config.xml⽂件中配置插件第三步&#xff1a;编写Java代码第四步&#xff1a;格式化结果查看 三、SpringBoot3 集成 PageHelper …

【人脸朝向识别与分类预测】基于PNN神经网络

课题名称&#xff1a;基于PNN神经网络的人脸朝向识别分类 版本日期&#xff1a;2024-02-20 运行方式&#xff1a;直接运行PNN0503.m文件 代码获取方式&#xff1a;私信博主或 QQ:491052175 模型描述&#xff1a; 采集到一组人脸朝向不同角度时的图像&#xff0c;图像来自不…

CAS5.3使用JPA实现动态注册服务

cas同时支持cas协议和OAuth2协议,官方默认是通过扫描json文件的形式注册客户端服务,但是此种方式需要重启服务才能生效,此次我们将使用JPA来完美实现动态注册服务,如果不知道cas如何部署,可以擦看之前的文章 cas-client基于CAS协议客户端搭建-CSDN博客 cas-server5.3自定义密…

CleanMyMac4苹果Mac电脑全面、高效的系统清理工具

CleanMyMac 4 for Mac是一款专为Mac用户设计的系统清理和优化工具。它具备多种功能&#xff0c;旨在帮助用户轻松管理和释放Mac上的磁盘空间&#xff0c;同时提升系统性能。 系统垃圾清理&#xff1a;CleanMyMac 4能够深入扫描Mac的每一个角落&#xff0c;智能识别并清除不需要…

Linux freezer机制

一、概述 系统进入suspended或进程被加入到cgroup冻结或解冻分组&#xff0c;用户进程和部分内核线程被冻结后&#xff0c;会剥夺执行cpu资源&#xff0c;解冻或唤醒后恢复正常。 二、进程冻结与解冻原理 2.1 进程冻结 用户进程和内核线程冻结的基本流程&#xff1a; 内核态…

JSP实现数据传递与保存(二)

一、session对象 session机制是一种服务器端的机制&#xff0c;在服务器端保存信息用于存储与用户相关的会话信息 1.1 session与窗口的关系 每个session对象都与一个浏览器窗口对应&#xff0c;重新开启一个浏览器窗口&#xff0c;可以重新创建一个session对象&#xff08;不…

IO进程线程复习:进程线程

1.进程的创建 #include<myhead.h>int main(int argc, const char *argv[]) {printf("hello world\n");//父进程执行的内容int num520;//在父进程中定义的变量pid_t pidfork();//创建子进程if(pid>0){while(1){printf("我是父进程&#xff0c;num%d\n&…

input输入框过滤非金额内容保留一个小数点和2位小数

这篇是输入框过滤非金额内容保留一个小数点和2位小数&#xff0c;金额的其他格式化可以看这篇文章常用的金额数字的格式化方法 js方法直接使用 该方式可以直接使用过滤内容&#xff0c;也可以到onInput或onblur等地方过滤&#xff0c;自行使用 /*** 非金额字符格式化处理* p…

有趣的CSS - 弹跳的圆

大家好&#xff0c;我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;今天分享的是用css写一个好玩的不停弹跳变形的圆。 《有趣的css》系列最新实例通过公众号「设计师工作日常」发布。 目录 整体效果核心代码html 代码css 部分代码 完整代码如下html 页面css 样式页…

解读2024生物发酵展览会-蓝帕控制阀门

参展企业介绍 感谢你正在或即将使用LAPAR系列产品&#xff0c;感谢你关注LAPAR&#xff01; LAPAR&#xff0c;流体控制领域的国际品牌之一&#xff0c;总部位于意大利米兰&#xff0c;成立多年以来&#xff0c;LAPAR凭借其完善的网络体系、优秀的产品质量、一体式的客户解决…

蓝桥杯-成绩分析

许久不敲代码&#xff0c;库名也忘了&#xff0c;精度设置还有求最大最小值都是常规题了。 #include <iostream> #include <iomanip> using namespace std; int main() { //一种不用开数组的方法 int n; cin>>n; int top0; int low100;//确定最大…

Uva 101: 木块问题(The Blocks Problem)

看着算法书看到了这一题&#xff0c;想着不能只看不做&#xff0c;就想着做了一下 算法书上的描述太抽象了&#xff0c;就网上找了其他的描述 当然去看英文描述是最准确的&#xff0c;算法书上说是哪一个oj网来着&#xff1f;我给忘了 STL还是很好用的 代码如下&#xff1a; …

【Vue3】学习watch监视:深入了解Vue3响应式系统的核心功能(下)

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

【Android12】Monkey压力测试源码执行流程分析

Monkey压力测试源码执行流程分析 Monkey是Android提供的用于应用程序自动化测试、压力测试的测试工具。 其源码路径(Android12)位于 /development/cmds/monkey/部署形式为Java Binary # development/cmds/monkey/Android.bp // Copyright 2008 The Android Open Source Proj…

Windows 安装Redis(图文详解)

一、Redis是什么数据库&#xff1f; Remote Dictionary Server(Redis) 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库&#xff0c;并提供多种语言的 API&#xff0c;是跨平台的非关系型数据库。 …

多线程和并发

线程 进程&#xff1a;在操作系统中运行的程序&#xff0c;一个进程可以包含多个线程 程序就是指令和数据的有序集合&#xff0c;静态概念 进程就是执行程序的一次执行过程&#xff0c;动态概念系统资源分配的单元 一个进程中包含多个线程&#xff0c;一个进程至少包含一个线…

图解KMP算法

目录 1.最长公共前后缀1.1前缀1.2后缀1.3最长公共前后缀 2、KMP算法过程2.1例子12.2例子22.3Python代码&#xff1a;2.4next数组的计算过程 1.最长公共前后缀 1.1前缀 前缀说的是一个字符串除了最后一个字符以外&#xff0c;所有的子串都算是前缀。 前缀字符串&#xff1a;A…

KubeSphere实战

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 知…