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

news2025/1/25 4:47:48

封装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! 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaWeb——005 -- 请求响应 分层解耦(Postman、三层架构、IOC、DI、注解)

目录 一、请求 1、Postman&#xff08;接口测试工具&#xff09; 1.1、介绍 ②、安装 2、简单参数 1.1、原始方式 1.2、SpringBoot方法 ③、小结 3、实体参数 3.1、简单实体对象 3.2、复杂实体对象 3.3、小结 4、数组集合参数 ①、数组​编辑 ②、集合 ③、小结…

15-55V输入自动升降压 光伏MPPT自动跟踪充电方案 大功率300瓦

1.MPPT原理--简介 MPPT&#xff0c;全称为Maximum Power Point Tracking&#xff0c;即最大功点跟踪&#xff0c;它是一种通过调节电气模块的工作状态&#xff0c;使光伏板能够输出更多电能的电气系统能够将太阳能电池板发出的直流电有效地贮存在蓄电池中&#xff0c;可有效地…

python + selenium/appnium

Selenium 的自动化原理: selenium 自动化流程: 自动化程序调用Selenium 客户端库函数&#xff08;比如点击按钮元素&#xff09;客户端库会发送Selenium 命令 给浏览器的驱动程序浏览器驱动程序接收到命令后 ,驱动浏览器去执行命令浏览器执行命令浏览器驱动程序获取命令执行的…

Linux 不同架构、不同系统的问题

文章目录 一、麒麟V10&#xff08;kylin&#xff09;操作系统中&#xff0c;sudo执行程序后&#xff0c;其环境变量依然为用户家目录。&#xff08;1&#xff09;背景&#xff08;2&#xff09;原因&#xff08;3&#xff09;解决办法 二、统信&#xff08;UOS&#xff09;操作…

标准库中的String类 String(C++)【1】

学习String的时候我是对照https://legacy.cplusplus.com/这个网站进行理解 标准库中的String类 string类的基础String的特点String常用的接口&#xff08;黑框标记的是常用接口&#xff09;构造函数string类对象的访问及遍历操作第一种 下标[ ]第二种 迭代器第三种 范围for st…

OpenAI的Sora深度解析

计算机视觉算法分享。问题或建议&#xff0c;请文章私信或者文章末尾扫码加微信留言。sora 具体介绍和使用方法&#xff1a;OpenAI Sora 下一代生产力&#xff1a;最新小白必看教程 | 解剖Sora的前世今生 | Sora核心源码目前 openai 官方还未开放 sora 灰度&#xff0c;不过根据…

客户端订阅服务端事件的机制

一、场景描述 产业大脑平台是一个典型的审核系统&#xff0c;用户发布到平台的信息需要经过审核员审核后生效。 用户发布信息->审核员审核信息->用户信息生效&#xff0c;这一流程可能发生在用户的同一次登录周期内。为了使客户端能实时响应信息的状态变化&#xff0c;…

QML小案例 使用QML简单实现翻牌版扫雷游戏(二)

使用QML实现扫雷功能案例&#xff0c;使用QML界面实现翻牌特效&#xff0c;以及随机的&#xff0c;从左到右&#xff0c;从中心向两边加载界面的特效实现&#xff0c;简单的示例NumberAnimation&#xff0c;PropertyAnimation&#xff0c;SequentialAnimation实现动画的效果,QM…

Python接口自动化之Token详解及应用

以下介绍Token原理及在自动化中的应用。 一、Token基本概念及原理 1.Token作用 为了验证用户登录情况以及减轻服务器的压力&#xff0c;减少频繁的查询数据库&#xff0c;使服务器更加健壮。 2.什么是Token Token是服务端生成的一串字符串&#xff0c;以作客户端进行请求的一…

49.仿简道云公式函数实战-文本函数-Ip

1. Ip函数 获取当前用户的ip地址 注意是Ipv4的地址 2. 函数用法 IP() 3. 函数示例 获取当前用户的ip地址IP() 4. 代码实战 首先我们在function包下创建text包&#xff0c;在text包下创建IpFunction类&#xff0c;代码如下&#xff1a; package com.ql.util.express.sel…

python 基础知识点(蓝桥杯python科目个人复习计划51)

今日复习计划&#xff1a;做复习题 例题1&#xff1a;大石头的搬运工 问题描述&#xff1a; 在一款名为“大石头的搬运工”的游戏中&#xff0c;玩家需要 操作一排n堆石头&#xff0c;进行n - 1轮游戏。 每一轮&#xff0c;玩家可以选择一堆石头&#xff0c;并将其移动到任…

Doris——荔枝微课统一实时数仓建设实践

目录 一、业务介绍 二、早期架构及痛点 2.1 早期架构 2.2 架构痛点 三、技术选型 四、新的架构及方案 五、搭建经验 5.1 数据建模 5.2 数据开发 5.3 库表设计 5.4 数据管理 5.4.1 监控告警 5.4.2 数据备份与恢复 六、收益总结 七、未来规划 原文大佬这篇Doris腾…

科技创新引领零售商品部降本增效的未来

随着科技的不断发展和应用&#xff0c;零售行业也迎来了前所未有的变革。在这个竞争激烈的市场中&#xff0c;零售商品部如何利用科技手段降低成本、提高效率成为了企业关注的焦点。让我们一起探讨一下科技创新如何引领零售商品部降本增效的未来。 首先&#xff0c;利用大数据…

算法--动态规划(线性DP、区间DP)

这里写目录标题 tip数组下标从0开始还是从1开始 数学三角形介绍算法思想例题代码 最长上升子序列介绍算法思想例题代码 最长公共子序列介绍算法思想例题代码 tip 数组下标从0开始还是从1开始 如果代码中涉及到数组下标为i-1&#xff08;有时候哪怕不是同一个数组也符合情况&am…

sql-labs第46关 order by盲注

sql-labs第46关 order by盲注 来到了第46关进入关卡发现让我们输入的参数为sort&#xff0c;我们输入?sort1尝试&#xff1a; 输入?sort2,3,发现表格按照顺序进行排列输出&#xff0c;明显是使用了order by相关的函数。 我们将参数变成1进行尝试&#xff0c;就会报错&…

uni-app原生api的promise化以解决异步等待问题分析

相信各位在进行uni-app开发的时候会遇到各种关于异步回调问题&#xff0c;例如要传code给后端以换取session_key&#xff0c;在这之前需要先调用 uni.login&#xff0c;所以执行的顺序是必须同步等待的。在写这篇文章之前对于整体的流程概念需要做一个梳理&#xff0c;以便能更…

Laravel03 路由到控制器与连接数据库

Laravel03 路由到控制器与连接数据库 1. 路由到控制器2. 连接数据库 1. 路由到控制器 如下图一些简单的逻辑处理可以放在web.php中&#xff0c;也就是路由的闭包函数里面。但是大的项目&#xff0c;我们肯定不能这么写。 为什么保证业务清晰好管理&#xff0c;都应该吧业务逻辑…

ubuntu20.04安装和使用 Maldet (Linux Malware Detect)

1、下载 Maldet sudo wget http://www.rfxn.com/downloads/maldetect-current.tar.gz 2、解压Maldet sudo tar -xvf maldetect-current.tar.gz 3、进入到Maldet目录&#xff0c;然后运行安装脚本 sudo ./install.sh 4、安装ClamAV sudo apt-get update sudo apt-get in…

卡诺图之间的运算(拓展应用)

文章目录 1.卡诺图运算的基本规律⑴卡诺图之间的或运算⑵卡诺图之间的与运算⑶卡诺图之间的异或和同或运算 2.利用卡诺图进行运算&#xff08;并化简&#xff09;3.特殊卡诺图与卡诺图模块化⑴异或逻辑函数的卡诺图⑵同或逻辑函数的卡诺图⑶卡诺图的模块化 4.可能的题型&#x…

使用 JMeter 生成测试数据对 MySQL 进行压力测试

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…