引入:
导入stb_image:
GitHub - nothings/stb: stb single-file public domain libraries for C/C++
下载复制stb_image.h的内容(8000多行),然后粘到如图位置
stb_image.cpp:
cpp
#include"ytpch.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
修改SRC下的premake.lua
Lua
workspace "YOTOEngine" -- sln文件名
architecture "x64"
configurations{
"Debug",
"Release",
"Dist"
}
startproject "Sandbox"
-- https://github.com/premake/premake-core/wiki/Tokens#value-tokens
-- 组成输出目录:Debug-windows-x86_64
outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}"
-- 包含相对解决方案的目录
IncludeDir={}
IncludeDir["GLFW"]="YOTOEngine/vendor/GLFW/include"
IncludeDir["Glad"]="YOTOEngine/vendor/Glad/include"
IncludeDir["ImGui"] ="YOTOEngine/vendor/imgui"
IncludeDir["glm"] ="YOTOEngine/vendor/glm"
IncludeDir["stb_image"] ="YOTOEngine/vendor/stb_image"
--项目中包含某包
include "YOTOEngine/vendor/GLFW"
include "YOTOEngine/vendor/Glad"
include "YOTOEngine/vendor/imgui"
project "YOTOEngine" --YOTOEngine项目
location "YOTOEngine"--在sln所属文件夹下的YOTOEngine文件夹
kind "StaticLib"--修改为lib静态库
language "C++"
targetdir ("bin/" .. outputdir .. "/%{prj.name}") -- 输出目录
objdir ("bin-int/" .. outputdir .. "/%{prj.name}")-- 中间目录
cppdialect "C++17"
staticruntime "on"--打开
pchheader "ytpch.h"
pchsource "YOTOEngine/src/ytpch.cpp"
-- 包含的所有h和cpp文件
files{
"%{prj.name}/src/**.h",
"%{prj.name}/src/**.cpp",
"%{prj.name}/vendor/stb_image/**.h",
"%{prj.name}/vendor/stb_image/**.cpp",
"%{prj.name}/vendor/glm/glm/**.hpp",
"%{prj.name}/vendor/glm/glm/**.inl"
}
defines{
"_CRT_SECURE_NO_WARNINGS"
}
-- 包含目录
includedirs{
"%{prj.name}/src",
"%{prj.name}/vendor/spdlog-1.x/include",
"%{IncludeDir.GLFW}",
"%{IncludeDir.Glad}",
"%{IncludeDir.ImGui}",
"%{IncludeDir.glm}",
"%{IncludeDir.stb_image}",
}
links{
"GLFW",-- GLFW.lib库链接到YOTOEngine项目中
"Glad",-- Glad.lib库链接到YOTOEngine项目中
"ImGui",-- ImGui.lib库链接到YOTOEngine项目中
"opengl32.lib"
}
-- 如果是window系统
filter "system:windows"
-- On:代码生成的运行库选项是MTD,静态链接MSVCRT.lib库;
-- Off:代码生成的运行库选项是MDD,动态链接MSVCRT.dll库;打包后的exe放到另一台电脑上若无这个dll会报错
systemversion "latest" -- windowSDK版本
-- 预处理器定义
defines{
"YT_PLATFORM_WINDOWS",
"YT_BUILD_DLL",
-- "YT_ENABLE_ASSERTS",
"GLFW_INCLUDE_NONE",-- 让GLFW不包含OpenGL
}
-- 编译好后移动Hazel.dll文件到Sandbox文件夹下
-- postbuildcommands{
-- ("{COPY} %{cfg.buildtarget.relpath} ../bin/" .. outputdir .. "/Sandbox")
-- }
-- 不同配置下的预定义不同
filter "configurations:Debug"
defines "YT_DEBUG"
runtime "Debug"
symbols "On"
filter "configurations:Release"
defines "YT_RELEASE"
runtime "Release"
optimize "On"
filter "configurations:Dist"
defines "YT_DIST"
runtime "Release"
optimize "On"
project "Sandbox"
location "Sandbox"
kind "ConsoleApp"
language "C++"
cppdialect "C++17"
staticruntime "on"
targetdir ("bin/" .. outputdir .. "/%{prj.name}")
objdir ("bin-int/" .. outputdir .. "/%{prj.name}")
files{
"%{prj.name}/src/**.h",
"%{prj.name}/src/**.cpp"
}
-- 同样包含spdlog头文件
includedirs{
"YOTOEngine/vendor/spdlog-1.x/include",
"YOTOEngine/src",
"YOTOEngine/vendor",
"%{IncludeDir.glm}"
}
-- 引用YOTOEngine
links{
"YOTOEngine",
"GLFW",
"opengl32.lib"
}
filter "system:windows"
systemversion "latest"
defines{
"YT_PLATFORM_WINDOWS"
}
filter "configurations:Debug"
defines "YT_DEBUG"
runtime "Debug"
symbols "On"
filter "configurations:Release"
defines "YT_RELEASE"
runtime "Release"
optimize "On"
filter "configurations:Dist"
defines "YT_DIST"
runtime "Release"
optimize "On"
抽象:
在Renderer文件夹下创建:
Texture.h:
cpp
#pragma once
#include"YOTO/Core.h"
namespace YOTO {
class Texture
{
public:
virtual ~Texture() = default;
virtual uint32_t GetWidth()const = 0;
virtual uint32_t GetHeight()const = 0;
virtual void Bind(uint32_t slot=0)const = 0;
};
class Texture2D :public Texture
{
public:
static Ref<Texture2D>Create(const std::string& path);
};
}
Texture.cpp:
cpp
#include "ytpch.h"
#include "Texture.h"
#include"Renderer.h"
#include "Platform/OpenGL/OpenGLTexture.h"
namespace YOTO {
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 std::make_shared<OpenGLTexture2D>(path);
}
YT_CORE_ASSERT(false, "Buffer:未知API");
return nullptr;
}
}
实现:
OpenGLTexture.h:
cpp
#pragma once
#include"YOTO/Renderer/Texture.h"
#include"YOTO/Log.h"
namespace YOTO {
class OpenGLTexture2D:public Texture2D
{
public:
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 Bind(uint32_t slot=0)const override;
private:
std::string m_Path;
uint32_t m_Width, m_Height;
uint32_t m_RendererID;
};
}
OpenGLTexture.cpp:
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;
//创建纹理
glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID);
///告诉OpenGLm_RendererID的纹理存储的是rbg8位,宽高的缓冲区
glTextureStorage2D(m_RendererID, 1, GL_RGB8,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,GL_RGB,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);
}
}
修改配置:
YOTO.h:
cpp
#pragma once
//用于YOTO APP
#include "YOTO/Application.h"
#include"YOTO/Layer.h"
#include "YOTO/Log.h"
#include"YOTO/Core/Timestep.h"
#include"YOTO/Input.h"
#include"YOTO/KeyCode.h"
#include"YOTO/MouseButtonCodes.h"
#include"YOTO/ImGui/ImGuiLayer.h"
//Renderer
#include"YOTO/Renderer/Renderer.h"
#include"YOTO/Renderer/RenderCommand.h"
#include"YOTO/Renderer/Buffer.h"
#include"YOTO/Renderer/Shader.h"
#include"YOTO/Renderer/Texture.h"
#include"YOTO/Renderer/VertexArray.h"
#include"YOTO/Renderer/OrthographicCamera.h"
//入口点
#include"YOTO/EntryPoint.h"
测试:
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("D:/GameEngine/yoto/SRC/Sandbox/assets/textures/Checkerboard.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.11f,y* 0.11f, 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)));
//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;
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();
}
cool!