修改底层渲染为OpenGL
This commit is contained in:
359
source/EngineFrame/Render/RenderManager.cpp
Normal file
359
source/EngineFrame/Render/RenderManager.cpp
Normal file
@@ -0,0 +1,359 @@
|
||||
#include "RenderManager.h"
|
||||
#include <fstream>
|
||||
#include "Texture.h"
|
||||
|
||||
RenderManager::RenderManager(SDL_Window *window)
|
||||
{
|
||||
_window = window;
|
||||
// 创建OpenGL上下文
|
||||
_ctx = SDL_GL_CreateContext(window);
|
||||
if (!_ctx)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL context create failed: %s\n", SDL_GetError());
|
||||
}
|
||||
|
||||
// 初始化GLAD
|
||||
if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress))
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GLAD init failed!\n");
|
||||
}
|
||||
|
||||
// 获取窗口大小
|
||||
int width, height;
|
||||
SDL_GetWindowSize(window, &width, &height);
|
||||
// 设置视口
|
||||
glViewport(0, 0, width, height);
|
||||
// 设置窗口尺寸
|
||||
_windowWidth = width;
|
||||
_windowHeight = height;
|
||||
// 设置正交投影矩阵
|
||||
_orthoMatrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f);
|
||||
|
||||
// 设置清屏颜色
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
// 启用混合模式
|
||||
glEnable(GL_BLEND);
|
||||
// 默认设置标准alpha混合
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// 初始化着色器程序
|
||||
InitShaderProgram();
|
||||
// 初始化绘制2D纹理缓冲程序
|
||||
Init2DTextureProgram();
|
||||
|
||||
// 设定默认使用的着色器程序和缓冲程序
|
||||
SetCurrentShaderProgram("normal");
|
||||
SetCurrentBufferObject("2DTexture");
|
||||
}
|
||||
|
||||
RenderManager::~RenderManager()
|
||||
{
|
||||
// 释放着色器程序
|
||||
for (auto &[name, program] : _shaderProgramMap)
|
||||
{
|
||||
glDeleteProgram(program);
|
||||
}
|
||||
// 释放缓冲对象
|
||||
for (auto &[name, program] : _RenderParamsMap)
|
||||
{
|
||||
glDeleteVertexArrays(1, &program.VAO);
|
||||
glDeleteBuffers(1, &program.VBO);
|
||||
glDeleteBuffers(1, &program.EBO);
|
||||
}
|
||||
// 释放OpenGL上下文
|
||||
SDL_GL_DeleteContext(_ctx);
|
||||
}
|
||||
|
||||
void RenderManager::InitShaderProgram()
|
||||
{
|
||||
std::ifstream shaderFile("shader/config.json");
|
||||
|
||||
nlohmann::json shaderConfig;
|
||||
shaderFile >> shaderConfig;
|
||||
|
||||
for (auto &[groupName, groupData] : shaderConfig["shader"].items())
|
||||
{
|
||||
if (!groupData.is_object())
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "着色器组 %s 格式错误,跳过\n", groupName.c_str());
|
||||
continue;
|
||||
}
|
||||
if (!groupData.contains("vertex") || !groupData["vertex"].is_string())
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 vertex 路径,跳过\n", groupName.c_str());
|
||||
continue;
|
||||
}
|
||||
if (!groupData.contains("fragment") || !groupData["fragment"].is_string())
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 fragment 路径,跳过\n", groupName.c_str());
|
||||
continue;
|
||||
}
|
||||
std::string vertPath = groupData["vertex"].get<std::string>();
|
||||
std::string fragPath = groupData["fragment"].get<std::string>();
|
||||
|
||||
GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertPath);
|
||||
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragPath);
|
||||
if (vertexShader == 0 || fragmentShader == 0)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器编译失败,跳过\n", groupName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
GLuint program = glCreateProgram();
|
||||
glAttachShader(program, vertexShader);
|
||||
glAttachShader(program, fragmentShader);
|
||||
glLinkProgram(program);
|
||||
GLint programLinksuccess;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &programLinksuccess);
|
||||
if (!programLinksuccess)
|
||||
{
|
||||
char infoLog[512];
|
||||
glGetProgramInfoLog(program, 512, nullptr, infoLog);
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器链接失败,失败原因: %s\n", groupName.c_str(), infoLog);
|
||||
}
|
||||
|
||||
_shaderProgramMap[groupName] = program;
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderManager::Init2DTextureProgram()
|
||||
{
|
||||
// 初始化顶点数据(矩形的四个顶点)
|
||||
float vertices[] = {
|
||||
0.0f, 0.0f, 0.0f, 0.0f, // 左下(单位坐标)
|
||||
1.0f, 0.0f, 1.0f, 0.0f, // 右下
|
||||
1.0f, 1.0f, 1.0f, 1.0f, // 右上
|
||||
0.0f, 1.0f, 0.0f, 1.0f // 左上
|
||||
};
|
||||
// 索引数组
|
||||
unsigned int indices[] = {0, 1, 2, 2, 3, 0};
|
||||
GLuint VAO, VBO, EBO;
|
||||
// 创建VAO/VBO/EBO
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glGenBuffers(1, &VBO);
|
||||
glGenBuffers(1, &EBO);
|
||||
|
||||
glBindVertexArray(VAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
|
||||
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));
|
||||
glEnableVertexAttribArray(1);
|
||||
// 创建完解绑
|
||||
glBindVertexArray(0);
|
||||
|
||||
SetCurrentShaderProgram("normal");
|
||||
glUseProgram(_currentShaderProgram);
|
||||
|
||||
// 获取uniform变量位置
|
||||
GLuint _uModelLoc = glGetUniformLocation(_currentShaderProgram, "uModel");
|
||||
GLuint _uViewProjLoc = glGetUniformLocation(_currentShaderProgram, "uViewProj");
|
||||
GLuint _uTextureLoc = glGetUniformLocation(_currentShaderProgram, "uTexture");
|
||||
if (_uModelLoc == -1 || _uViewProjLoc == -1 || _uTextureLoc == -1)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "无法获取着色器 uniform 变量位置\n");
|
||||
}
|
||||
std::vector<GLuint> uniformLocs = {_uModelLoc, _uViewProjLoc, _uTextureLoc};
|
||||
|
||||
DrawLogicFunc drawFunc = [this](
|
||||
RefPtr<Texture> textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata)
|
||||
{
|
||||
GLuint texture = textureObj->getID();
|
||||
if (!texture || !dstrect)
|
||||
return;
|
||||
|
||||
glUseProgram(_currentShaderProgram);
|
||||
|
||||
glm::mat4 model = glm::mat4(1.0f);
|
||||
|
||||
// 平移
|
||||
model = glm::translate(model, glm::vec3(dstrect->x, dstrect->y, 0.0f));
|
||||
|
||||
// 计算旋转中心
|
||||
float centerX = center ? center->x : dstrect->w * 0.5f;
|
||||
float centerY = center ? center->y : dstrect->h * 0.5f;
|
||||
|
||||
// 旋转中心平移
|
||||
model = glm::translate(model, glm::vec3(centerX, centerY, 0.0f));
|
||||
|
||||
// 旋转
|
||||
if (angle != 0.0)
|
||||
{
|
||||
model = glm::rotate(model, glm::radians(static_cast<float>(angle)), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
// 旋转中心平移
|
||||
model = glm::translate(model, glm::vec3(-centerX, -centerY, 0.0f));
|
||||
|
||||
// 缩放和翻转
|
||||
float scaleX = dstrect->w;
|
||||
float scaleY = dstrect->h;
|
||||
|
||||
// 应用翻转(通过负缩放实现)
|
||||
if (flip & SDL_FLIP_HORIZONTAL)
|
||||
scaleX = -scaleX;
|
||||
if (flip & SDL_FLIP_VERTICAL)
|
||||
scaleY = -scaleY;
|
||||
|
||||
model = glm::scale(model, glm::vec3(scaleX, scaleY, 1.0f));
|
||||
|
||||
// 翻转后的位置补偿
|
||||
if (flip & SDL_FLIP_HORIZONTAL)
|
||||
{
|
||||
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
if (flip & SDL_FLIP_VERTICAL)
|
||||
{
|
||||
model = glm::translate(model, glm::vec3(0.0f, -1.0f, 0.0f));
|
||||
}
|
||||
|
||||
// 设置着色器 uniforms
|
||||
glUniformMatrix4fv(_currentRenderParams.UnimLocs[0], 1, GL_FALSE, glm::value_ptr(model));
|
||||
glUniformMatrix4fv(_currentRenderParams.UnimLocs[1], 1, GL_FALSE, glm::value_ptr(_orthoMatrix));
|
||||
|
||||
// 绑定纹理并设置采样器
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glUniform1i(_currentRenderParams.UnimLocs[2], 0);
|
||||
|
||||
// 处理纹理裁剪
|
||||
int texWidth = textureObj->getSize().width;
|
||||
int texHeight = textureObj->getSize().height;
|
||||
|
||||
// 计算纹理坐标
|
||||
float minu, minv, maxu, maxv;
|
||||
if (srcrect)
|
||||
{
|
||||
minu = (float)srcrect->x / texWidth;
|
||||
minv = (float)srcrect->y / texHeight;
|
||||
maxu = (float)(srcrect->x + srcrect->w) / texWidth;
|
||||
maxv = (float)(srcrect->y + srcrect->h) / texHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
minu = 0.0f;
|
||||
minv = 0.0f;
|
||||
maxu = 1.0f;
|
||||
maxv = 1.0f;
|
||||
}
|
||||
|
||||
// 计算顶点位置(单位矩形,通过模型变换进行缩放和平移)
|
||||
float minx = 0.0f;
|
||||
float miny = 0.0f;
|
||||
float maxx = 1.0f;
|
||||
float maxy = 1.0f;
|
||||
|
||||
// 创建顶点数据(位置 + 纹理坐标)
|
||||
float vertices[] = {
|
||||
// 位置 // 纹理坐标
|
||||
minx, miny, minu, minv, // 左上
|
||||
maxx, miny, maxu, minv, // 右上
|
||||
maxx, maxy, maxu, maxv, // 右下
|
||||
minx, maxy, minu, maxv // 左下
|
||||
};
|
||||
|
||||
// 更新VBO数据
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _currentRenderParams.VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
// 绘制纹理
|
||||
glBindVertexArray(_currentRenderParams.VAO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
};
|
||||
|
||||
GL_RenderParams bufferObject = {VAO, VBO, EBO, uniformLocs, drawFunc};
|
||||
AddBufferObject("2DTexture", bufferObject);
|
||||
}
|
||||
|
||||
void RenderManager::SetCurrentShaderProgram(std::string name)
|
||||
{
|
||||
if (_shaderProgramMap.find(name) != _shaderProgramMap.end())
|
||||
{
|
||||
this->_currentShaderProgram = _shaderProgramMap[name];
|
||||
}
|
||||
else
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到着色器程序: %s\n", name.c_str());
|
||||
}
|
||||
|
||||
void RenderManager::SetCurrentBufferObject(std::string name)
|
||||
{
|
||||
if (_RenderParamsMap.find(name) != _RenderParamsMap.end())
|
||||
{
|
||||
this->_currentRenderParams = _RenderParamsMap[name];
|
||||
}
|
||||
else
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染参数: %s\n", name.c_str());
|
||||
}
|
||||
|
||||
void RenderManager::ClearScreen()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void RenderManager::SwapBuffer()
|
||||
{
|
||||
SDL_GL_SwapWindow(_window);
|
||||
}
|
||||
|
||||
void RenderManager::SetClipRect(const SDL_Rect *rect)
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(rect->x, _windowHeight - rect->y - rect->h, rect->w, rect->h);
|
||||
}
|
||||
|
||||
void RenderManager::CloseClipRect()
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void RenderManager::DrawTexture(RefPtr<Texture> textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata)
|
||||
{
|
||||
if (_currentRenderParams.DrawFunc != nullptr)
|
||||
_currentRenderParams.DrawFunc(textureObj, srcrect, dstrect, angle, center, flip, userdata);
|
||||
else
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染逻辑函数\n");
|
||||
}
|
||||
|
||||
GLuint RenderManager::CompileShader(GLenum type, std::string Path)
|
||||
{
|
||||
std::ifstream Source("shader/" + Path);
|
||||
if (!Source.is_open())
|
||||
{
|
||||
SDL_LogError(0, "Failed to open shader file: %s\n", Path.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string ShaderSource((std::istreambuf_iterator<char>(Source)), std::istreambuf_iterator<char>());
|
||||
const char *SourcePtr = ShaderSource.c_str();
|
||||
|
||||
GLuint ShaderId = glCreateShader(type);
|
||||
glShaderSource(ShaderId, 1, &SourcePtr, NULL);
|
||||
glCompileShader(ShaderId);
|
||||
|
||||
// 检查编译错误
|
||||
GLint success;
|
||||
glGetShaderiv(ShaderId, GL_COMPILE_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
char infoLog[512];
|
||||
glGetShaderInfoLog(ShaderId, 512, nullptr, infoLog);
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Shader compile error: %s\n", infoLog);
|
||||
glDeleteShader(ShaderId);
|
||||
return 0;
|
||||
}
|
||||
return ShaderId;
|
||||
}
|
||||
|
||||
void RenderManager::AddBufferObject(std::string name, GL_RenderParams bufferObject)
|
||||
{
|
||||
_RenderParamsMap[name] = bufferObject;
|
||||
}
|
||||
78
source/EngineFrame/Render/RenderManager.h
Normal file
78
source/EngineFrame/Render/RenderManager.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
#include <SDL.h>
|
||||
#include <SDL_image.h>
|
||||
#include <glad/glad.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <json.hpp>
|
||||
#include "EngineFrame/Render/Texture.h"
|
||||
class RenderManager
|
||||
{
|
||||
public:
|
||||
// 绘制纹理的逻辑函数
|
||||
using DrawLogicFunc = std::function<void(RefPtr<Texture>, const SDL_Rect *, const SDL_FRect *,
|
||||
double, const SDL_FPoint *, SDL_RendererFlip,
|
||||
void *)>;
|
||||
|
||||
struct GL_RenderParams
|
||||
{
|
||||
GLuint VAO;
|
||||
GLuint VBO;
|
||||
GLuint EBO;
|
||||
std::vector<GLuint> UnimLocs;
|
||||
DrawLogicFunc DrawFunc = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
SDL_Window *_window;
|
||||
// 窗口尺寸
|
||||
int _windowWidth;
|
||||
int _windowHeight;
|
||||
// 正交投影矩阵
|
||||
glm::mat4 _orthoMatrix;
|
||||
|
||||
// 渲染器上下文
|
||||
SDL_GLContext _ctx;
|
||||
// 着色器程序
|
||||
std::map<std::string, GLuint> _shaderProgramMap;
|
||||
// 渲染参数
|
||||
std::map<std::string, GL_RenderParams> _RenderParamsMap;
|
||||
|
||||
// 当前使用着色器程序
|
||||
GLuint _currentShaderProgram;
|
||||
// 当前使用渲染参数
|
||||
GL_RenderParams _currentRenderParams;
|
||||
|
||||
public:
|
||||
RenderManager(SDL_Window *window);
|
||||
~RenderManager();
|
||||
|
||||
// 初始化着色器程序
|
||||
void InitShaderProgram();
|
||||
// 初始化绘制2D纹理缓冲程序
|
||||
void Init2DTextureProgram();
|
||||
// 设定当前使用的着色器程序
|
||||
void SetCurrentShaderProgram(std::string name);
|
||||
// 设定当前使用的缓冲对象
|
||||
void SetCurrentBufferObject(std::string name);
|
||||
|
||||
// 清空屏幕
|
||||
void ClearScreen();
|
||||
// 交换缓冲区
|
||||
void SwapBuffer();
|
||||
// 设置裁切区域
|
||||
void SetClipRect(const SDL_Rect *rect);
|
||||
// 关闭裁切区域
|
||||
void CloseClipRect();
|
||||
// 绘制纹理
|
||||
void DrawTexture(RefPtr<Texture> texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata = nullptr);
|
||||
|
||||
private:
|
||||
// 编译着色器
|
||||
GLuint CompileShader(GLenum type, std::string Path);
|
||||
// 新增缓冲程序
|
||||
void AddBufferObject(std::string name, GL_RenderParams bufferObject);
|
||||
};
|
||||
@@ -1,91 +1,204 @@
|
||||
#include "EngineFrame/Render/Texture.h"
|
||||
#include "Texture.h"
|
||||
#include "Asset/Asset_ImagePack.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include "Texture.h"
|
||||
|
||||
Texture::Texture()
|
||||
{
|
||||
}
|
||||
|
||||
Texture::Texture(std::string PngPath)
|
||||
Texture::~Texture()
|
||||
{
|
||||
glDeleteTextures(1, &m_TextureID);
|
||||
}
|
||||
|
||||
bool Texture::Init(std::string PngPath)
|
||||
{
|
||||
SDL_Surface *surface = IMG_Load(PngPath.c_str());
|
||||
if (!surface)
|
||||
{
|
||||
SDL_Log("无法加载图片: %s", SDL_GetError());
|
||||
return;
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Couldn't load image %s: %s", PngPath.c_str(), IMG_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_texture = SDL_CreateTextureFromSurface(Game::GetInstance().GetRenderer(), surface);
|
||||
if (!m_texture)
|
||||
{
|
||||
SDL_Log("无法创建纹理: %s", SDL_GetError());
|
||||
SDL_FreeSurface(surface); // 记得释放surface
|
||||
return;
|
||||
}
|
||||
|
||||
this->TextureSize.width = surface->w;
|
||||
this->TextureSize.height = surface->h;
|
||||
this->TextureFramepos.width = surface->w;
|
||||
this->TextureFramepos.height = surface->h;
|
||||
SDL_Surface *rgbaSurface = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
|
||||
SDL_FreeSurface(surface);
|
||||
if (!rgbaSurface)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to convert surface: %s\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 生成OpenGL纹理
|
||||
glGenTextures(1, &m_TextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, m_TextureID);
|
||||
|
||||
// 环绕方式
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// 缩小过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
// 放大过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
// 处理像素对齐(确保SDL的像素行对齐与OpenGL兼容)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// 记录纹理信息
|
||||
m_TextureSize.width = rgbaSurface->w;
|
||||
m_TextureSize.height = rgbaSurface->h;
|
||||
m_FrameSize.width = rgbaSurface->w;
|
||||
m_FrameSize.height = rgbaSurface->h;
|
||||
m_Path = PngPath;
|
||||
|
||||
// 将像素数据上传到GPU
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0, // 纹理级别(基础级)
|
||||
GL_RGBA8, // 内部存储格式(8位RGBA)
|
||||
m_TextureSize.width,
|
||||
m_TextureSize.height,
|
||||
0, // 边框(必须为0)
|
||||
GL_RGBA, // 源数据格式(与SDL转换后的格式一致)
|
||||
GL_UNSIGNED_BYTE, // 源数据类型(无符号字节)
|
||||
rgbaSurface->pixels);
|
||||
|
||||
// 释放转换后的表面(数据已上传到GPU)
|
||||
SDL_FreeSurface(rgbaSurface);
|
||||
return true;
|
||||
}
|
||||
|
||||
Texture::Texture(std::string imgPath, int Index)
|
||||
bool Texture::Init(std::string ImgPath, int Index)
|
||||
{
|
||||
this->ImgPath = imgPath;
|
||||
this->Index = Index;
|
||||
Asset_ImagePack::IMG *Info = Asset_ImagePack::GetInstance().GetIMG(imgPath);
|
||||
m_Path = ImgPath;
|
||||
m_TextureIndex = Index;
|
||||
Asset_ImagePack::IMG *Info = Asset_ImagePack::GetInstance().GetIMG(ImgPath);
|
||||
if (Info->lpImgName == "sprite/interface/base.img")
|
||||
return;
|
||||
return false;
|
||||
Asset_ImagePack::ImgInfo &Buf = Info->lp_lplist[Index];
|
||||
|
||||
m_texture = SDL_CreateTexture(
|
||||
Game::GetInstance().GetRenderer(),
|
||||
SDL_PIXELFORMAT_ARGB8888, // 匹配RGBA数据格式
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
Buf.Width, Buf.Height);
|
||||
if (!m_texture)
|
||||
// 检查像素数据是否有效
|
||||
if (!Buf.PNGdata || Buf.Width <= 0 || Buf.Height <= 0)
|
||||
{
|
||||
SDL_Log("纹理创建失败: %s", SDL_GetError());
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "无效的图像数据: %s (index: %d)", ImgPath.c_str(), Index);
|
||||
return false;
|
||||
}
|
||||
int pitch = Buf.Width * 4;
|
||||
SDL_UpdateTexture(m_texture, NULL, Buf.PNGdata, pitch);
|
||||
SDL_SetTextureBlendMode(m_texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureScaleMode(m_texture, SDL_ScaleModeNearest);
|
||||
|
||||
this->TexturePos.x = Buf.Xpos;
|
||||
this->TexturePos.y = Buf.Ypos;
|
||||
this->TextureSize.width = Buf.Width;
|
||||
this->TextureSize.height = Buf.Height;
|
||||
this->TextureFramepos.width = Buf.FrameXpos;
|
||||
this->TextureFramepos.height = Buf.FrameYpos;
|
||||
int pixelCount = Buf.Width * Buf.Height;
|
||||
uint32_t *srcPixels = reinterpret_cast<uint32_t *>(Buf.PNGdata);
|
||||
uint32_t *dstPixels = new uint32_t[pixelCount];
|
||||
for (int i = 0; i < pixelCount; ++i)
|
||||
{
|
||||
uint8_t b = (srcPixels[i] >> 0) & 0xFF; // 蓝
|
||||
uint8_t g = (srcPixels[i] >> 8) & 0xFF; // 绿
|
||||
uint8_t r = (srcPixels[i] >> 16) & 0xFF; // 红
|
||||
uint8_t a = (srcPixels[i] >> 24) & 0xFF; // 透明
|
||||
dstPixels[i] = (a << 24) | (b << 16) | (g << 8) | r; // 重组为 RGBA
|
||||
}
|
||||
|
||||
// 生成OpenGL纹理
|
||||
glGenTextures(1, &m_TextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, m_TextureID);
|
||||
|
||||
// 设置纹理参数(保持与原有SDL纹理相同的采样模式)
|
||||
// 环绕方式:重复
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// 过滤方式:最近邻(与SDL_ScaleModeNearest对应)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// 处理像素对齐(SDL表面可能有不同的行对齐方式)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// 记录纹理信息
|
||||
m_TextureSize.width = Buf.Width;
|
||||
m_TextureSize.height = Buf.Height;
|
||||
m_FrameSize.width = Buf.FrameXpos;
|
||||
m_FrameSize.height = Buf.FrameYpos;
|
||||
m_TexturePos.x = Buf.Xpos;
|
||||
m_TexturePos.y = Buf.Ypos;
|
||||
|
||||
// 上传纹理数据到GPU
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0, // 基础纹理级别
|
||||
GL_RGBA8, // 内部存储格式(8位RGBA)
|
||||
m_TextureSize.width,
|
||||
m_TextureSize.height,
|
||||
0, // 无边框
|
||||
GL_RGBA, // 源数据格式(根据实际数据格式调整)
|
||||
GL_UNSIGNED_BYTE, // 源数据类型
|
||||
dstPixels);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Texture::~Texture()
|
||||
bool Texture::Init(SDL_Surface *rgbaSurface)
|
||||
{
|
||||
SDL_DestroyTexture(m_texture);
|
||||
// 生成OpenGL纹理
|
||||
glGenTextures(1, &m_TextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, m_TextureID);
|
||||
|
||||
// 环绕方式
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// 缩小过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
// 放大过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// 处理像素对齐(确保SDL的像素行对齐与OpenGL兼容)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// 记录纹理信息
|
||||
m_TextureSize.width = rgbaSurface->w;
|
||||
m_TextureSize.height = rgbaSurface->h;
|
||||
m_FrameSize.width = rgbaSurface->w;
|
||||
m_FrameSize.height = rgbaSurface->h;
|
||||
|
||||
// 将像素数据上传到GPU
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0, // 纹理级别(基础级)
|
||||
GL_RGBA8, // 内部存储格式(8位RGBA)
|
||||
m_TextureSize.width,
|
||||
m_TextureSize.height,
|
||||
0, // 边框(必须为0)
|
||||
GL_RGBA, // 源数据格式(与SDL转换后的格式一致)
|
||||
GL_UNSIGNED_BYTE, // 源数据类型(无符号字节)
|
||||
rgbaSurface->pixels);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SDL_Texture *Texture::GetTexture()
|
||||
bool Texture::Init(VecSize size)
|
||||
{
|
||||
return m_texture;
|
||||
}
|
||||
glGenTextures(1, &m_TextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, m_TextureID);
|
||||
// 设置纹理参数(根据需求调整尺寸、格式)
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0, // 多级渐远纹理级别
|
||||
GL_RGBA, // 内部格式(存储格式)
|
||||
size.width, // 纹理宽度
|
||||
size.height, // 纹理高度
|
||||
0, // 边框(必须为0)
|
||||
GL_RGBA, // 源数据格式
|
||||
GL_UNSIGNED_BYTE, // 源数据类型
|
||||
nullptr // 初始数据(为空,后续绘制填充)
|
||||
);
|
||||
|
||||
RefPtr<Texture> Texture::GetTextureCopy()
|
||||
{
|
||||
RefPtr<Texture> nt = new Texture(this->ImgPath, this->Index);
|
||||
return nt;
|
||||
}
|
||||
// 记录纹理信息
|
||||
m_TextureSize = size;
|
||||
m_FrameSize = size;
|
||||
|
||||
void Texture::SetBlendMode(SDL_BlendMode blendMode)
|
||||
{
|
||||
SDL_SetTextureBlendMode(m_texture, blendMode);
|
||||
}
|
||||
// 环绕方式
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// 缩小过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
// 放大过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
SDL_BlendMode Texture::GetBlendMode()
|
||||
{
|
||||
SDL_BlendMode blendMode;
|
||||
SDL_GetTextureBlendMode(m_texture, &blendMode);
|
||||
return blendMode;
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // 解绑
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,33 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_image.h>
|
||||
#include <glad/glad.h>
|
||||
#include <string>
|
||||
#include "Tool/RefPtr.h"
|
||||
#include "Tool/Common.h"
|
||||
#include "Tool/RefObject.h"
|
||||
#include "Tool/RefPtr.h"
|
||||
#include "Tool/IntrusiveList.hpp"
|
||||
|
||||
class Texture : public RefObject
|
||||
{
|
||||
private:
|
||||
SDL_Texture *m_texture = nullptr;
|
||||
std::string ImgPath = "";
|
||||
int Index = 0;
|
||||
public:
|
||||
VecSize TextureSize = {0, 0}; // 纹理大小
|
||||
VecPos TexturePos = {0, 0}; // 纹理位置
|
||||
VecSize TextureFramepos = {0, 0}; // 帧域宽高
|
||||
// OpenGL 纹理ID
|
||||
GLuint m_TextureID;
|
||||
// 纹理大小
|
||||
VecSize m_TextureSize;
|
||||
// 帧域大小
|
||||
VecSize m_FrameSize;
|
||||
// 纹理坐标
|
||||
VecPos m_TexturePos;
|
||||
// 纹理透明度
|
||||
float m_Alpha = 1.0f;
|
||||
|
||||
// 纹理路径
|
||||
std::string m_Path;
|
||||
// 纹理编号(可选 在使用img构造时才会有编号)
|
||||
int m_TextureIndex = -1;
|
||||
|
||||
public:
|
||||
Texture(/* args */);
|
||||
Texture(std::string PngPath);
|
||||
Texture(std::string imgPath, int Index);
|
||||
~Texture();
|
||||
Texture(const Texture &) = delete;
|
||||
Texture &operator=(const Texture &) = delete;
|
||||
|
||||
public:
|
||||
void SetBlendMode(SDL_BlendMode blendMode);
|
||||
// 获取混合模式
|
||||
SDL_BlendMode GetBlendMode();
|
||||
// 获取纹理
|
||||
SDL_Texture *GetTexture();
|
||||
// 获取一个拷贝的纹理
|
||||
RefPtr<Texture> GetTextureCopy();
|
||||
// 获取纹理ID
|
||||
GLuint getID() const { return m_TextureID; }
|
||||
// 设置纹理透明度
|
||||
void setAlpha(float alpha) { m_Alpha = alpha; }
|
||||
// 获取纹理透明度
|
||||
float getAlpha() const { return m_Alpha; }
|
||||
// 获取纹理大小
|
||||
VecSize getSize() const { return m_TextureSize; }
|
||||
// 获取纹理坐标
|
||||
VecPos getPos() const { return m_TexturePos; }
|
||||
// 获取纹理路径
|
||||
std::string getPath() const { return m_Path; }
|
||||
// 获取纹理编号
|
||||
int getIndex() const { return m_TextureIndex; }
|
||||
// 获取帧域大小
|
||||
VecSize getFrameSize() const { return m_FrameSize; }
|
||||
|
||||
public:
|
||||
bool Init(std::string PngPath);
|
||||
bool Init(std::string ImgPath, int index);
|
||||
bool Init(SDL_Surface *surface);
|
||||
bool Init(VecSize size);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user