本节先把代码粘上,后续会慢慢把注释都给加上,先看代码了解个大概(待更新)
前置:
RendererAPI.h:
cpp
#pragma once
namespace YOTO {
enum class RendererAPI {
None = 0,
OpenGL=1
};
class Renderer {
public:
inline static RendererAPI GetAPI() {
return s_RendererAPI;
}
static RendererAPI s_RendererAPI;
};
}
RendererAPI.cpp:
cpp
#include"ytpch.h"
#include"Renderer.h"
namespace YOTO {
RendererAPI Renderer::s_RendererAPI = RendererAPI::OpenGL;
}
抽象:
buffer.h:
cpp
#pragma once
#include <YOTO/Log.h>
namespace YOTO {
enum class ShaderDataType{
None=0,
Float,Float2,Float3,Float4,
Mat3,Mat4,
Int,Int2,Int3,Int4,
Bool,
};
static uint32_t ShaderDataTypeSize(ShaderDataType type) {
switch (type)
{
case YOTO::ShaderDataType::Float:
return 4;
break;
case YOTO::ShaderDataType::Float2:
return 4*2;
break;
case YOTO::ShaderDataType::Float3:
return 4*3;
break;
case YOTO::ShaderDataType::Float4:
return 4*4;
break;
case YOTO::ShaderDataType::Mat3:
return 4*3*3;
break;
case YOTO::ShaderDataType::Mat4:
return 4*4*4;
break;
case YOTO::ShaderDataType::Int:
return 4;
break;
case YOTO::ShaderDataType::Int2:
return 4*2;
break;
case YOTO::ShaderDataType::Int3:
return 4*3;
break;
case YOTO::ShaderDataType::Int4:
return 4*4;
break;
case YOTO::ShaderDataType::Bool:
return 1;
break;
}
YT_CORE_ASSERT(false, "未知的ShaderDataType!");
return 0;
}
struct BufferElement {
std::string Name;
ShaderDataType Type;
uint32_t Size;
uint32_t Offset;
bool Normalized;
BufferElement(){}
BufferElement(ShaderDataType type, const std::string& name,bool normalized=false)
:Name(name), Type(type), Size(ShaderDataTypeSize(type)), Offset(0), Normalized(normalized){}
uint32_t GetComponentCount() const{
switch (Type)
{
case YOTO::ShaderDataType::Float:
return 1;
break;
case YOTO::ShaderDataType::Float2:
return 2;
break;
case YOTO::ShaderDataType::Float3:
return 3;
break;
case YOTO::ShaderDataType::Float4:
return 4;
break;
case YOTO::ShaderDataType::Mat3:
return 3*3;
break;
case YOTO::ShaderDataType::Mat4:
return 4*4;
break;
case YOTO::ShaderDataType::Int:
return 1;
break;
case YOTO::ShaderDataType::Int2:
return 2;
break;
case YOTO::ShaderDataType::Int3:
return 3;
break;
case YOTO::ShaderDataType::Int4:
return 4;
break;
case YOTO::ShaderDataType::Bool:
return 1;
break;
default:
break;
}
YT_CORE_ASSERT(false, "未知的ShaderDataType!");
return 0;
}
};
class BufferLayout {
public:
BufferLayout(){}
BufferLayout(const std::initializer_list<BufferElement>elements)
:m_Elements(elements)
{
CalculateOffsetAndStride();
}
inline uint32_t GetStride()const { return m_Stride; }
inline const std::vector<BufferElement>& GetElements()const {
return m_Elements;
}
std::vector<BufferElement>::iterator begin() { return m_Elements.begin(); }
std::vector<BufferElement>::iterator end() { return m_Elements.end(); }
std::vector<BufferElement>::const_iterator begin() const { return m_Elements.begin(); }
std::vector<BufferElement>::const_iterator end() const { return m_Elements.end(); }
private:
void CalculateOffsetAndStride() {
uint32_t offset = 0;
m_Stride = 0;
for (auto& element : m_Elements) {
element.Offset = offset;
offset += element.Size;
m_Stride += element.Size;
}
}
private:
std::vector<BufferElement> m_Elements;
uint32_t m_Stride = 0;
};
class VertexBuffer {
public:
virtual~VertexBuffer() {}
virtual void Bind() const = 0;
virtual void UnBind() const = 0;
virtual void SetLayout(const BufferLayout& layout) = 0;
virtual const BufferLayout& GetLayout()const = 0;
static VertexBuffer* Create(float* vertices, uint32_t size);
};
class IndexBuffer {
public:
virtual~IndexBuffer(){}
virtual void Bind() const = 0;
virtual void UnBind() const = 0;
virtual uint32_t GetCount() const = 0;
static IndexBuffer* Create(uint32_t* indices, uint32_t size);
};
}
buffer.cpp:
cpp
#include"ytpch.h"
#include"Buffer.h"
#include "Renderer.h"
#include "Platform/OpenGL/OpenGLBuffer.h"
namespace YOTO {
VertexBuffer* VertexBuffer::Create(float* vertices, uint32_t size)
{
switch (Renderer::GetAPI())
{
case RendererAPI::None:
YT_CORE_ASSERT(false,"Buffer:API为None不支持");
return nullptr;
case RendererAPI::OpenGL:
return new OpenGLVertexBuffer(vertices,size);
}
YT_CORE_ASSERT(false,"Buffer:未知API");
return nullptr;
}
IndexBuffer* IndexBuffer::Create(uint32_t* indices, uint32_t size)
{
switch (Renderer::GetAPI())
{
case RendererAPI::None:
YT_CORE_ASSERT(false, "Buffer:API为None不支持");
return nullptr;
case RendererAPI::OpenGL:
return new OpenGLIndexBuffer(indices, size);
}
YT_CORE_ASSERT(false, "Buffer:未知API");
return nullptr;
}
}
VertexArray.h:
cpp
#pragma once
#include"YOTO/Renderer/Buffer.h"
namespace YOTO {
class VertexArray {
public:
virtual~VertexArray() {}
virtual void Bind() const = 0;
virtual void UnBind() const = 0;
virtual void AddVertexBuffer(const std::shared_ptr<VertexBuffer>&vertexBuffer) = 0;
virtual void AddIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer) = 0;
virtual const std::vector<std::shared_ptr<VertexBuffer>>& GetVertexBuffers()const = 0;
virtual const std::shared_ptr<IndexBuffer>& GetIndexBuffer()const = 0;
static VertexArray* Create();
};
}
VertexArray.cpp:
cpp
#include "ytpch.h"
#include "VertexArray.h"
#include"Renderer.h"
#include "Platform/OpenGL/OpenGLVertexArray.h"
namespace YOTO {
VertexArray* VertexArray::Create()
{
switch (Renderer::GetAPI())
{
case RendererAPI::None:
YT_CORE_ASSERT(false, "Buffer:API为None不支持");
return nullptr;
case RendererAPI::OpenGL:
return new OpenGLVertexArray();
}
YT_CORE_ASSERT(false, "Buffer:未知API");
return nullptr;
}
}
实现:
OpenGLBuffer.h:
cpp
#pragma once
#include "YOTO/Renderer/Buffer.h"
namespace YOTO {
class OpenGLVertexBuffer : public VertexBuffer {
public:
OpenGLVertexBuffer(float* vertices, uint32_t size);
virtual~OpenGLVertexBuffer();
virtual void Bind()const override;
virtual void UnBind()const override;
virtual void SetLayout(const BufferLayout& layout) override {
m_Layout = layout;
}
virtual const BufferLayout& GetLayout()const override {
return m_Layout;
}
private:
uint32_t m_RendererID;
BufferLayout m_Layout;
};
class OpenGLIndexBuffer : public IndexBuffer {
public:
OpenGLIndexBuffer(uint32_t* indices, uint32_t count);
virtual~OpenGLIndexBuffer();
virtual void Bind()const;
virtual void UnBind()const;
virtual uint32_t GetCount() const {
return m_Count;
};
private:
uint32_t m_RendererID;
uint32_t m_Count;
};
}
OpenGLBuffer.cpp:
cpp
#include"ytpch.h"
#include"OpenGLBuffer.h"
#include <glad/glad.h>
namespace YOTO {
// VertexBuffer
OpenGLVertexBuffer::OpenGLVertexBuffer(float* vertices, uint32_t size)
{
glCreateBuffers(1, &m_RendererID);
glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
}
OpenGLVertexBuffer::~OpenGLVertexBuffer()
{
glDeleteBuffers(1, &m_RendererID);
}
void OpenGLVertexBuffer::Bind() const
{
glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
}
void OpenGLVertexBuffer::UnBind() const
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// IndexBuffer /
OpenGLIndexBuffer::OpenGLIndexBuffer(uint32_t* indices, uint32_t count)
:m_Count(count)
{
glCreateBuffers(1, &m_RendererID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, count*sizeof(uint32_t), indices, GL_STATIC_DRAW);
}
OpenGLIndexBuffer::~OpenGLIndexBuffer()
{
glDeleteBuffers(1, &m_RendererID);
}
void OpenGLIndexBuffer::Bind() const
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
}
void OpenGLIndexBuffer::UnBind() const
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
}
OpenGLVertexArray.h:
cpp
#pragma once
#include"YOTO/Renderer/VertexArray.h"
namespace YOTO {
class OpenGLVertexArray:public VertexArray
{
public :
OpenGLVertexArray();
virtual ~OpenGLVertexArray();
virtual void Bind() const override;
virtual void UnBind() const override;
virtual void AddVertexBuffer(const std::shared_ptr<VertexBuffer>& vertexBuffer)override;
virtual void AddIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer)override;
virtual const std::vector<std::shared_ptr<VertexBuffer>>& GetVertexBuffers()const {
return m_VertexBuffers;
}
virtual const std::shared_ptr<IndexBuffer>& GetIndexBuffer()const {
return m_IndexBuffers;
}
private:
uint32_t m_RendererID;
std::vector<std::shared_ptr<VertexBuffer>> m_VertexBuffers;
std::shared_ptr<IndexBuffer> m_IndexBuffers;
};
}
OpenGLVertexArray.cpp:
cpp
#include "ytpch.h"
#include "OpenGLVertexArray.h"
#include <glad/glad.h>
namespace YOTO {
static GLenum ShaderDataTypeToOpenGLBaseType(ShaderDataType type) {
switch (type)
{
case YOTO::ShaderDataType::Float:
return GL_FLOAT;
case YOTO::ShaderDataType::Float2:
return GL_FLOAT;
case YOTO::ShaderDataType::Float3:
return GL_FLOAT;
case YOTO::ShaderDataType::Float4:
return GL_FLOAT;
case YOTO::ShaderDataType::Mat3:
return GL_FLOAT;
case YOTO::ShaderDataType::Mat4:
return GL_FLOAT;
case YOTO::ShaderDataType::Int:
return GL_INT;
case YOTO::ShaderDataType::Int2:
return GL_INT;
case YOTO::ShaderDataType::Int3:
return GL_INT;
case YOTO::ShaderDataType::Int4:
return GL_INT;
case YOTO::ShaderDataType::Bool:
return GL_BOOL;
}
return 0;
}
OpenGLVertexArray::OpenGLVertexArray()
{
glCreateVertexArrays(1, &m_RendererID);
}
OpenGLVertexArray::~OpenGLVertexArray()
{
glDeleteVertexArrays(1, &m_RendererID);
}
void OpenGLVertexArray::Bind() const
{
glBindVertexArray(m_RendererID);
}
void OpenGLVertexArray::UnBind() const
{
glBindVertexArray(0);
}
void OpenGLVertexArray::AddVertexBuffer(const std::shared_ptr<VertexBuffer>& vertexBuffer)
{
YT_CORE_ASSERT(vertexBuffer->GetLayout().GetElements().size(), "OpenGLVertexArray:VertexBuffer没有布局(Layout)")
glBindVertexArray(m_RendererID);
vertexBuffer->Bind();
uint32_t index = 0;
const auto& layout = vertexBuffer->GetLayout();
for (const auto& element : layout) {
glEnableVertexAttribArray(index);
//设置缓冲区数据格式:缓冲区序号、顶点属性的大小、什么数据类型、会不会被归一化、
glVertexAttribPointer(index,
element.GetComponentCount(),
ShaderDataTypeToOpenGLBaseType(element.Type),
element.Normalized ? GL_TRUE : GL_FALSE,
layout.GetStride(),
(const void*)element.Offset);
index++;
}
m_VertexBuffers.push_back(vertexBuffer);
}
void OpenGLVertexArray::AddIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer)
{
glBindVertexArray(m_RendererID);
indexBuffer->Bind();
m_IndexBuffers = indexBuffer;
}
}
调用:
Application.h:
cpp
#pragma once
#include"Core.h"
#include"Event/Event.h"
#include"Event/ApplicationEvent.h"
#include "YOTO/Window.h"
#include"YOTO/LayerStack.h"
#include"YOTO/ImGui/ImGuiLayer.h"
#include <YOTO/Renderer/Shader.h>
#include <YOTO/Renderer/Buffer.h>
#include <YOTO/Renderer/VertexArray.h>
namespace YOTO {
class YOTO_API Application
{
public:
Application();
virtual ~Application();
void Run();
void OnEvent(Event &e);
void PushLayer(Layer* layer);
void PushOverlay(Layer* layer);
inline static Application& Get() {return * s_Instance;}
inline Window& GetWindow() { return *m_Window; }
private:
bool OnWindowClosed(WindowCloseEvent& e);
std::unique_ptr<Window> m_Window;
ImGuiLayer * m_ImGuiLayer;
bool m_Running = true;
LayerStack m_LayerStack;
//unsigned int m_VertexArray;
std::shared_ptr<Shader> m_Shader;
std::shared_ptr<VertexArray> m_VertexArray;
std::shared_ptr<Shader> m_BlueShader;
std::shared_ptr<VertexArray> m_SquareVA;
static Application* s_Instance;
};
//在客户端定义
Application* CreateApplication();
}
Application.cpp:
cpp
#include"ytpch.h"
#include "Application.h"
#include"Log.h"
#include<glad/glad.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());
//顶点数组:
//glGenVertexArrays(1, &m_VertexArray);
//glBindVertexArray(m_VertexArray);
//顶点缓冲区
//glGenBuffers(1, &m_VertexBuffer);
//glBindBuffer(GL_ARRAY_BUFFER,m_VertexBuffer);
//把数据传送给gpu,GL_STATIC_DRAW不断的用新数据刷新数组。告诉opengl这个缓冲区的数据布局
//glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
std::shared_ptr<VertexBuffer> m_VertexBuffer;
m_VertexBuffer.reset(VertexBuffer::Create(vertices, sizeof(vertices)));
//启用数据的索引0
//glEnableVertexAttribArray(0);
//设置缓冲区数据格式:缓冲区序号、顶点属性的大小、什么数据类型、会不会被归一化、
//glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),nullptr);
{
BufferLayout setlayout = {
{ShaderDataType::Float3,"a_Position"},
{ShaderDataType::Float4,"a_Color"}
};
m_VertexBuffer->SetLayout(setlayout);
}
//uint32_t index = 0;
//const auto& layout = m_VertexBuffer->GetLayout();
//for (const auto& element : layout) {
// glEnableVertexAttribArray(index);
// //设置缓冲区数据格式:缓冲区序号、顶点属性的大小、什么数据类型、会不会被归一化、
// glVertexAttribPointer(index,
// element.GetComponentCount(),
// ShaderDataTypeToOpenGLBaseType(element.Type),
// element.Normalized?GL_TRUE:GL_FALSE,
// layout.GetStride() ,
// (const void *)element.Offset);
// index++;
//}
m_VertexArray->AddVertexBuffer(m_VertexBuffer);
//创建索引缓冲区
//glGenBuffers(1, &m_IndexBuffer);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IndexBuffer);
//设置缓冲区格式
//glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
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));
//shader
}
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);
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();
}
}
测试:
shader就不改了,随便一测试画出来个矩形就对了