抽象:
Renderer.h:
cpp
#pragma once
#include"RenderCommand.h"
#include "OrthographicCamera.h"
#include"Shader.h"
namespace YOTO {
class Renderer {
public:
static void Init();
static void BeginScene(OrthographicCamera& camera);
static void EndScene();
static void Submit(const Ref<Shader>& shader, const Ref<VertexArray>& vertexArray,const glm::mat4&transform = glm::mat4(1.0f));
inline static RendererAPI::API GetAPI() {
return RendererAPI::GetAPI();
}
private:
struct SceneData {
glm::mat4 ViewProjectionMatrix;
};
static SceneData* m_SceneData;
};
}
Renderer.cpp:
cpp
#include"ytpch.h"
#include"Renderer.h"
#include <Platform/OpenGL/OpenGLShader.h>
namespace YOTO {
Renderer::SceneData* Renderer::m_SceneData = new Renderer::SceneData;
void Renderer::Init()
{
RenderCommand::Init();
}
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);
}
}
RenderCommand.h:
cpp
#pragma once
#include"RendererAPI.h"
namespace YOTO {
class RenderCommand
{
public:
inline static void Init() {
s_RendererAPI->Init();
}
inline static void SetClearColor(const glm::vec4& color) {
s_RendererAPI->SetClearColor(color);
}
inline static void Clear() {
s_RendererAPI->Clear();
}
inline static void DrawIndexed(const Ref<VertexArray>& vertexArray) {
s_RendererAPI->DrawIndexed(vertexArray);
}
private:
static RendererAPI* s_RendererAPI;
};
}
RendererAPI.h:
cpp
#pragma once
#include<glm/glm.hpp>
#include "VertexArray.h"
namespace YOTO {
class RendererAPI
{
public:
enum class API {
None = 0,
OpenGL = 1
};
public:
virtual void Init() = 0;
virtual void SetClearColor(const glm::vec4& color)=0;
virtual void Clear() = 0;
virtual void DrawIndexed(const Ref<VertexArray>& vertexArray)=0;
inline static API GetAPI() { return s_API; }
private:
static API s_API;
};
}
实现:
OpenGLRendererAPI.h
cpp
#pragma once
#include"YOTO/Renderer/RendererAPI.h"
namespace YOTO {
class OpenGLRendererAPI:public RendererAPI
{
public:
virtual void Init()override;
virtual void SetClearColor(const glm::vec4& color)override;
virtual void Clear()override;
virtual void DrawIndexed(const Ref<VertexArray>& vertexArray) override;
};
}
OpenGLRendererAPI.h
cpp
#include "ytpch.h"
#include "OpenGLTexture.h"
#include<glad/glad.h>
#include"stb_image.h"
namespace YOTO {
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;
}
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);
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::Bind(uint32_t slot) const
{
glBindTextureUnit(slot, m_RendererID);
}
}
OpenGLRendererAPI.cpp
cpp
#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);
}
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);
}
}
调用:
Application.cpp:
cpp
#include"ytpch.h"
#include "Application.h"
#include"Log.h"
#include "YOTO/Renderer/Renderer.h"
#include"Input.h"
#include <GLFW/glfw3.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));
m_Window->SetVSync(false);
Renderer::Init();
//new一个Layer,放在最后层进行渲染
m_ImGuiLayer = new ImGuiLayer();
PushOverlay(m_ImGuiLayer);
}
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)
{
float time = (float)glfwGetTime();//window平台
Timestep timestep = time - m_LastFrameTime;
m_LastFrameTime = time;
for (Layer* layer : m_LayerStack) {
layer->OnUpdate(timestep);
}
//将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();
}
}
SandboxApp.cpp:
cpp
#include<YOTO.h>
#include "imgui/imgui.h"
#include<stdio.h>
#include <glm/gtc/matrix_transform.hpp>
#include <Platform/OpenGL/OpenGLShader.h>
#include <glm/gtc/type_ptr.hpp>
class ExampleLayer:public YOTO::Layer
{
public:
ExampleLayer()
:Layer("Example"), m_Camera(-2.0f, 2.0f, -2.0f, 2.0f), m_CameraPosition(0){
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(YOTO::VertexArray::Create());
YOTO::Ref<YOTO::VertexBuffer> m_VertexBuffer;
m_VertexBuffer.reset(YOTO::VertexBuffer::Create(vertices, sizeof(vertices)));
{
YOTO::BufferLayout setlayout = {
{YOTO::ShaderDataType::Float3,"a_Position"},
{YOTO::ShaderDataType::Float4,"a_Color"}
};
m_VertexBuffer->SetLayout(setlayout);
}
m_VertexArray->AddVertexBuffer(m_VertexBuffer);
YOTO::Ref<YOTO::IndexBuffer>m_IndexBuffer;
m_IndexBuffer.reset(YOTO::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;
uniform mat4 u_ViewProjection;
uniform mat4 u_Transform;
out vec3 v_Position;
out vec4 v_Color;
void main(){
v_Position=a_Position;
v_Color=a_Color;
gl_Position =u_ViewProjection *u_Transform* vec4( a_Position,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(YOTO::Shader::Create(vertexSource, fragmentSource));
///测试/
m_SquareVA.reset(YOTO::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,
};
YOTO::Ref<YOTO::VertexBuffer> squareVB;
squareVB.reset(YOTO::VertexBuffer::Create(squareVertices, sizeof(squareVertices)));
squareVB->SetLayout({
{YOTO::ShaderDataType::Float3,"a_Position"},
{YOTO::ShaderDataType::Float2,"a_TexCoord"}
});
m_SquareVA->AddVertexBuffer(squareVB);
uint32_t squareIndices[6] = { 0,1,2,2,3,0 };
YOTO::Ref<YOTO::IndexBuffer> squareIB;
squareIB.reset((YOTO::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;
uniform mat4 u_ViewProjection;
uniform mat4 u_Transform;
out vec3 v_Position;
void main(){
v_Position=a_Position;
gl_Position =u_ViewProjection*u_Transform*vec4( a_Position,1.0);
}
)";
//绘制颜色
std::string BlueShaderFragmentSource = R"(
#version 330 core
layout(location = 0) out vec4 color;
in vec3 v_Position;
uniform vec3 u_Color;
void main(){
color=vec4(u_Color,1.0);
}
)";
m_BlueShader.reset(YOTO::Shader::Create(BlueShaderVertexSource, BlueShaderFragmentSource));
std::string textureVertexSource = R"(
#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);
}
)";
//绘制颜色
std::string textureFragmentSource = R"(
#version 330 core
layout(location = 0) out vec4 color;
in vec3 v_Position;
in vec2 v_TexCoord;
uniform sampler2D u_Texture ;
void main(){
color = texture(u_Texture, v_TexCoord);
// color = vec4(v_TexCoord, 0.0f, 1.0f);
}
)";
m_TextureShader.reset(YOTO::Shader::Create(textureVertexSource, textureFragmentSource));
m_Texture=YOTO::Texture2D::Create("assets/textures/Checkerboard.png");
m_ChernoLogo= YOTO::Texture2D::Create("assets/textures/ChernoLogo.png");
std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_TextureShader)->Bind();
std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_TextureShader)->UploadUniformInt("u_Texture", 0);
}
void OnImGuiRender() override {
ImGui::Begin("设置");
ImGui::ColorEdit3("正方形颜色", glm::value_ptr(m_SquareColor));
ImGui::End();
}
void OnUpdate(YOTO::Timestep ts)override {
//YT_CLIENT_TRACE("delta time {0}s ({1}ms)", ts.GetSeconds(), ts.GetMilliseconds());
if (YOTO::Input::IsKeyPressed(YT_KEY_LEFT)) {
m_CameraPosition.x -= m_CameraMoveSpeed* ts;
}
else if (YOTO::Input::IsKeyPressed(YT_KEY_RIGHT)) {
m_CameraPosition.x += m_CameraMoveSpeed * ts;
}
if (YOTO::Input::IsKeyPressed(YT_KEY_DOWN)) {
m_CameraPosition.y -= m_CameraMoveSpeed * ts;
}
else if (YOTO::Input::IsKeyPressed(YT_KEY_UP)) {
m_CameraPosition.y += m_CameraMoveSpeed * ts;
}
if (YOTO::Input::IsKeyPressed(YT_KEY_A)) {
m_CameraRotation += m_CameraRotationSpeed * ts;
}else if (YOTO::Input::IsKeyPressed(YT_KEY_D)) {
m_CameraRotation -= m_CameraRotationSpeed * ts;
}
YOTO::RenderCommand::SetClearColor({ 0.2f, 0.2f, 0.2f, 1.0f });
YOTO::RenderCommand::Clear();
m_Camera.SetPosition(m_CameraPosition);
m_Camera.SetRotation(m_CameraRotation);
YOTO::Renderer::BeginScene(m_Camera);
{
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);
/* YOTO::MaterialRef material = new YOTO::MaterialRef(m_FlatColorShader);
YOTO::MaterialInstaceRef mi = new YOTO::MaterialInstaceRef(material);
mi.setValue("u_Color",redColor);
mi.setTexture("u_AlbedoMap", texture);
squreMesh->SetMaterial(mi);*/
std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_BlueShader)->Bind();
std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_BlueShader)->UploadUniformFloat3("u_Color",m_SquareColor);
for (int y = 0; y < 20; y++) {
for (int x = 0; x <20; x++)
{
glm::vec3 pos(x * 0.105f,y* 0.105f, 0.0);
glm::mat4 transform = glm::translate(glm::mat4(1.0f), pos) * scale;
/*if (x % 2 == 0) {
m_BlueShader->UploadUniformFloat4("u_Color", redColor);
}
else {
m_BlueShader->UploadUniformFloat4("u_Color", blueColor);
}*/
YOTO::Renderer::Submit(m_BlueShader, m_SquareVA, transform);
}
}
m_Texture->Bind();
YOTO::Renderer::Submit(m_TextureShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));
m_ChernoLogo->Bind();
YOTO::Renderer::Submit(m_TextureShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));
//YOTO::Renderer::Submit(m_Shader, m_VertexArray);
YOTO::Renderer::EndScene();
}
}
void OnEvent(YOTO::Event& event)override {
/*if (event.GetEventType() == YOTO::EventType::KeyPressed) {
YOTO:: KeyPressedEvent& e = (YOTO::KeyPressedEvent&)event;
YT_CLIENT_TRACE("ExampleLayer:{0}",(char)e.GetKeyCode());
if (e.GetKeyCode()==YT_KEY_TAB) {
YT_CLIENT_INFO("ExampleLayerOnEvent:TAB按下了");
}}*/
//YT_CLIENT_TRACE("SandBoxApp:测试event{0}", event);
}
private:
YOTO::Ref<YOTO::Shader> m_Shader;
YOTO::Ref<YOTO::VertexArray> m_VertexArray;
YOTO::Ref<YOTO::Shader> m_BlueShader,m_TextureShader;
YOTO::Ref<YOTO::VertexArray> m_SquareVA;
YOTO::Ref<YOTO::Texture2D> m_Texture,m_ChernoLogo;
YOTO::OrthographicCamera m_Camera;
glm::vec3 m_CameraPosition;
float m_CameraMoveSpeed = 5.0f;
float m_CameraRotation = 0;
float m_CameraRotationSpeed = 180.0f;
glm::vec3 m_SquareColor = { 0.2f,0.3f,0.7f };
};
class Sandbox:public YOTO::Application
{
public:
Sandbox(){
PushLayer(new ExampleLayer());
//PushLayer(new YOTO::ImGuiLayer());
}
~Sandbox() {
}
private:
};
YOTO::Application* YOTO::CreateApplication() {
printf("helloworld");
return new Sandbox();
}
加了个init涉及了好几个类,小改动,为了方便观察,我把整个类都复制下来了。