跟着cherno手搓游戏引擎【14】封装opengl

本节先把代码粘上,后续会慢慢把注释都给加上,先看代码了解个大概(待更新)

前置:

RendererAPI.h:

#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:

#include"ytpch.h"
#include"Renderer.h"
namespace YOTO {RendererAPI Renderer::s_RendererAPI = RendererAPI::OpenGL;
}

抽象:

buffer.h:

#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:

#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:

#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:

#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:

#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:

#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:

#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:

#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:

#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:

#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 corelayout(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 corelayout(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 corelayout(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 corelayout(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就不改了,随便一测试画出来个矩形就对了

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

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

相关文章

JavaWeb后端登录校验功能(JWT令牌技术,Cookie技术,Session,拦截技术,过滤器)

目录 一.登录校验功能&#xff08;解决直接通过路径访问&#xff09; 1.实现思路 二.会话技术 ​编辑 1.Cookie技术 2.Session 3.令牌技术 1.简介 2.如何生成和解析 3.令牌的使用 三.Filter过滤器 1.什么是过滤器 2.实现步骤&#xff1a; 3.过滤器执行流程 4.拦截路径 5.过…

[C++历练之路]C++中的继承小学问

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; C中&#xff0c;继承是一种面向对象编程的重要概念&#xff0c;它允许一个类&#xff08;子类/派生类&#xff09;从另一个类&#xff08;父类/基类&#xff09;继承属性和方法。继承是…

Hadoop-MapReduce-YarnChild启动篇

一、源码下载 下面是hadoop官方源码下载地址&#xff0c;我下载的是hadoop-3.2.4&#xff0c;那就一起来看下吧 Index of /dist/hadoop/core 二、上下文 在上一篇<Hadoop-MapReduce-MRAppMaster启动篇>中已经将到&#xff1a;MRAppMaster的启动&#xff0c;那么运行M…

(刷题记录)移除元素

我的代码&#xff1a; class Solution {public int removeElement(int[] nums, int val) {int j0;for(int i0;i<nums.length;i){if(nums[i]!val){nums[j]nums[i];j;}}return j;} }思路&#xff1a;双指针&#xff0c;右指针指向当前要处理的元素&#xff0c;有不等的数就赋…

Docker私有仓库搭建

registry私有仓库 步骤一&#xff1a;先拉取registry的镜像 [rootlocalhost ~]#docker pull registry 步骤二&#xff1a;修改docker的配置文件重启 [rootlocalhost ~]#vim /etc/docker/daemon.json {"insecure-registries": ["192.168.66.66:5000"] }[r…

浅谈隔离放大器

浅谈隔离放大器 定义&#xff1a;隔离放大器是将输入的电量信号或物理量信号通过一种技术手段处理后,隔离输出一组模拟量信号,这组模拟量信号是以标准的4-20mA/0-20mA/0-10mA/0-10V/0-5V/1-5V/2-10V/0-2.5V/0-20mA/0-10mA/0-10V/0-100mV/0-5V等信号,以便控制系统及仪器仪表设备…

PGsql 解析json及json数组

创建测试数据 drop table if exists json_test; create table json_test as select 111 as id, {"nodes":{"1692328028076":{"nodeId":"1692328028076","nodeName":"测试表1","nodeType":"DATACO…

单片机学习笔记---定时器计数器(含寄存器)工作原理介绍(详解篇2)

目录 T1工作在方式2时 T0工作在方式3时 四种工作方式的总结 定时计数器对输入信号的要求 定时计数器对的编程的一个要求 关于初值计算的问题 4种工作方式的最大定时时间的大小 关于编程方式的问题 实例分析 实例1 实例2 T1工作在方式2时 51单片机&#xff0c;有两个…

vue实践:构建高效的电子签名功能

前言 在现代数字化时代&#xff0c;电子签名成为了一种方便、高效且安全的签署文件的方式。本文将介绍电子签名的原理和实现方法&#xff0c;帮助你快速掌握这一重要的工具。 电子签名是什么&#xff1f; 电子签名是一种数字化的签名方式&#xff0c;用于验证和确认电子文档、…

matlab appdesigner系列-app程序打包成可执行exe程序

提供了3种打包方式&#xff1a; 1&#xff09;Matlab App &#xff0c;这种方式是生成Matlab内部使用的小程序&#xff0c;可添加到matlab app菜单栏中的常用程序中&#xff0c;也就是应用该程序之前&#xff0c;你必须安装了matlab&#xff1b; 2&#xff09;Web app 3&…

vs 撤销本地 commit 并保留更改

没想到特别好的办法&#xff0c;我想的是用 vs 打开 git 命令行工具 然后通过 git 命令来撤销提交&#xff0c;尝试之前建议先建个分支实验&#xff0c;以免丢失代码&#xff0c; git 操作见 git 合并多个 commit / 修改上一次 commit

2024.1.29 GNSS 学习笔记

1.假设只对4颗卫星进行观测定位&#xff0c;卫星的截止高度角是15&#xff0c;那么如何布设这四颗卫星的位置&#xff0c;使其围成的四面体的体积得到最大&#xff0c;以获得最好定位精度&#xff1f; 答&#xff1a;3颗卫星均匀分布在最低仰角面上&#xff0c;第4颗卫星在测站…

华为笔记本matebook pro X如何扩容 C 盘空间

一、前提条件 磁盘扩展与合并必须是相邻分区空间&#xff0c;且两个磁盘类型需要相同。以磁盘分区为 C 盘和 D 盘为例&#xff0c;如果您希望增加 C 盘容量&#xff0c;可以先将 D 盘合并到 C 盘&#xff0c;然后重新创建磁盘分区&#xff0c;分配 C 盘和 D 盘的空间大小。 访…

git push后,如何撤销git log上的错误注释

修改了本地的代码&#xff0c;执行了下面的操作&#xff0c;提交之后&#xff0c;怎么样修改 git add ********(文件名)//git add 添加修改文件名之后 git commit //git commit 在当前分支提交&#xff0c;编写提交注释 git push //git push 提交修…

Android T 远程动画显示流程(更新中)

序 本地动画和远程动画区别是什么? 本地动画&#xff1a;自给自足。对自身SurfaceControl矢量动画进行控制。 远程动画&#xff1a;拿来吧你&#xff01;一个app A对另一个app B通过binder跨进程通信&#xff0c;控制app B的SurfaceControl矢量动画。 无论是本地动画还是远程…

C++ Qt开发:运用QJSON模块解析数据

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QJson组件的实现对JSON文本的灵活解析…

echarts:获取省、市、区/县、镇的地图数据

目录 第一章 前言 第二章 获取地图的数据&#xff08;GeoJSON格式&#xff09; 2.1 获取省、市、区/县地图数据 2.2 获取乡/镇/街道地图数据 第一章 前言 需求&#xff1a;接到要做大屏的需求&#xff0c;其中需要用echarts绘画一个地图&#xff0c;但是需要的地图是区/县…

C语言系列-整数在内存中的存储大小端字节序

&#x1f308;个人主页: 会编程的果子君 ​&#x1f4ab;个人格言:“成为自己未来的主人~” 目录 整数在内存中的存储 大小端字节序和字节序判断 什么是大小端 为什么会有大小端 练习 整数在内存中的存储 在讲解操作符的时候&#xff0c;我们就讲过了下面的内容 整数的2…

高端车规MCU的破局之路

目录 1 低质量的无效内卷 2 高端车规MCU产品共性 2.1 支持标定测量 2.2 低延迟通信加速 2.3 完备的网络安全解决方案 2.4虚拟化 3 国产替代的囚徒困境 1 低质量的无效内卷 近几年&#xff0c;车规MCU国产替代的呼声此消彼长&#xff0c;但仍然集中在低端产品。 从产…

鸿蒙首批原生应用!无感验证已完美适配鸿蒙系统

顶象无感验证已成功适配鸿蒙系统&#xff0c;成为首批鸿蒙原生应用&#xff0c;助力鸿蒙生态的快速发展。 作为全场景分布式操作系统&#xff0c;鸿蒙系统旨在打破不同设备之间的界限&#xff0c;实现极速发现、极速连接、硬件互助、资源共享。迄今生态设备数已突破8亿台&…