mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 13:48:30 +09:00
[Feat] (...): Add BufferState and VertexBufferState while implementing these gl functions.
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
//
|
||||
|
||||
// TODO: Add more gl error check for buffer state manager.
|
||||
|
||||
#include "BufferState.h"
|
||||
|
||||
GLenum BufferState::Create(GLuint* buffer) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Create called");
|
||||
if (!buffer) return GL_INVALID_VALUE;
|
||||
|
||||
GLuint id = 0;
|
||||
if (!freeIds_.empty()) {
|
||||
id = *freeIds_.begin();
|
||||
freeIds_.erase(freeIds_.begin());
|
||||
} else {
|
||||
id = ++lastId_;
|
||||
}
|
||||
*buffer = id;
|
||||
BufferObject& obj = buffers_[id];
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Create created buffer %d", id);
|
||||
obj.generated = true;
|
||||
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::CreateN(GLsizei n, GLuint* buffers) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: CreateN called with n=%d", n);
|
||||
if (n < 0) return GL_INVALID_VALUE;
|
||||
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
GLenum result = Create(&buffers[i]);
|
||||
if (result != GL_NO_ERROR) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: CreateN create buffer failed with error 0x%x", result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: CreateN created buffers successfully");
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::Bind(GLenum target, GLuint buffer) {
|
||||
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Bind called with target=0x%x, buffer=%u", target, buffer);
|
||||
|
||||
if (buffer != 0) {
|
||||
auto it = buffers_.find(buffer);
|
||||
if (it == buffers_.end()) {
|
||||
buffers_[buffer];
|
||||
} else {
|
||||
BufferObject& obj = it->second;
|
||||
if (obj.target != 0 && obj.target != target) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: Bind can not bind a buffer to different target 0x%x, current bind target is 0x%x", target, obj.target);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
buffers_[buffer].target = target;
|
||||
}
|
||||
|
||||
currentBindings_[target] = buffer;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Bind succeed bind buffer %u to target 0x%x", buffer, target);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::CommitStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage called on target 0x%x",target);
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage get buffer object %u at target 0x%x",it->second,target);
|
||||
obj.usage = usage;
|
||||
obj.data.resize(size);
|
||||
if (data) memcpy(obj.data.data(), data, size);
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage buffer at target 0x%x committed storage, size = %zu, usage=0x%x", target, size, usage);
|
||||
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer) {
|
||||
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
|
||||
if (MG_Constants::Buffer::VALID_ACCESS.find(access) == MG_Constants::Buffer::VALID_ACCESS.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemory buffer at target 0x%x acquired mapped memory, access mode = 0x%x", target, access);
|
||||
}
|
||||
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
if (obj.isMapped) return GL_INVALID_OPERATION;
|
||||
|
||||
obj.isMapped = true;
|
||||
*mappedPointer = obj.data.data();
|
||||
obj.isMapped = true;
|
||||
obj.accessMode = access;
|
||||
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::ReleaseBufferMemory(GLenum target) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: ReleaseBufferMemory called on target 0x%x",target);
|
||||
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
|
||||
|
||||
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
if (!obj.isMapped) return GL_INVALID_OPERATION;
|
||||
|
||||
obj.isMapped = false;
|
||||
obj.accessMode = GL_READ_WRITE;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: ReleaseBufferMemory buffer at target 0x%x released mapped memory", target);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool BufferState::ValidateHandle(GLuint buffer) {
|
||||
bool isvalid = buffers_.count(buffer) > 0;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: ValidateHandle called on buffer %u returns %d", buffer, isvalid);
|
||||
return isvalid;
|
||||
}
|
||||
|
||||
void BufferState::Delete(GLuint buffer) {
|
||||
if (buffers_.erase(buffer)) {
|
||||
freeIds_.insert(buffer);
|
||||
for (auto& [target, id] : currentBindings_) {
|
||||
if (id == buffer) id = 0;
|
||||
}
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Delete buffer %u", buffer);
|
||||
}
|
||||
|
||||
bool BufferState::IsValidTarget_(GLenum target) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: IsValidTarget_ called with target=0x%x,result=%d", target, !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end()));
|
||||
return !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end());
|
||||
}
|
||||
|
||||
GLenum BufferState::QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: QueryPropertyIntVector called at target 0x%x,param name = 0x%x",target,pname);
|
||||
static const std::set<GLenum> validTargets = {
|
||||
GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
|
||||
GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER
|
||||
};
|
||||
if (validTargets.find(target) == validTargets.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
|
||||
if (MG_Constants::Buffer::VALID_PARAM_NAMES.find(pname) == MG_Constants::Buffer::VALID_PARAM_NAMES.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
|
||||
auto bindingIt = currentBindings_.find(target);
|
||||
if (bindingIt == currentBindings_.end() || bindingIt->second == 0) {
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
GLuint bufferId = bindingIt->second;
|
||||
auto bufferIt = buffers_.find(bufferId);
|
||||
if (bufferIt == buffers_.end()) {
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
const BufferObject& buffer = bufferIt->second;
|
||||
|
||||
switch (pname) {
|
||||
case GL_BUFFER_ACCESS:
|
||||
*params = static_cast<GLint>(buffer.accessMode);
|
||||
break;
|
||||
case GL_BUFFER_MAPPED:
|
||||
*params = buffer.isMapped ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_BUFFER_SIZE:
|
||||
*params = static_cast<GLint>(buffer.data.size());
|
||||
break;
|
||||
case GL_BUFFER_USAGE:
|
||||
*params = static_cast<GLint>(buffer.usage);
|
||||
break;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: QueryPropertyIntVector Query info about buffer %u succeed",buffer.target);
|
||||
default:
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
GLuint BufferState::GetCurrentBinding(GLenum target) const {
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it != currentBindings_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_BUFFERSTATE_H
|
||||
#define MOBILEGL_BUFFERSTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
class BufferState {
|
||||
public:
|
||||
struct BufferObject {
|
||||
GLenum target = 0;
|
||||
GLenum usage = GL_STATIC_DRAW;
|
||||
std::vector<GLubyte> data;
|
||||
bool isMapped = false;
|
||||
bool generated = false;
|
||||
GLenum accessMode = GL_READ_WRITE;
|
||||
};
|
||||
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
GLenum Create(GLuint* buffer);
|
||||
GLenum CreateN(GLsizei n, GLuint* buffers);
|
||||
GLenum Bind(GLenum target, GLuint buffer);
|
||||
GLenum CommitStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer);
|
||||
GLenum ReleaseBufferMemory(GLenum target);
|
||||
GLenum QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const;
|
||||
|
||||
bool ValidateHandle(GLuint buffer);
|
||||
void Delete(GLuint buffer);
|
||||
GLuint GetCurrentBinding(GLenum target) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<GLuint, BufferObject> buffers_;
|
||||
std::set<GLuint> freeIds_;
|
||||
GLuint lastId_ = 0;
|
||||
std::unordered_map<GLenum, GLuint> currentBindings_;
|
||||
|
||||
static bool IsValidTarget_(GLenum target);
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_BUFFERSTATE_H
|
||||
@@ -13,7 +13,9 @@ private:
|
||||
std::unordered_map<GLenum, GLint> pixelStoreParams;
|
||||
|
||||
public:
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
GLenum SetPixelStoreInt(GLenum pname, GLint param);
|
||||
|
||||
GLint GetPixelStoreInt(GLenum pname);
|
||||
};
|
||||
|
||||
|
||||
@@ -7,16 +7,22 @@
|
||||
std::queue<GLenum> MG_State_T::glErrorQueue;
|
||||
TextureState* MG_State_T::textureState = nullptr;
|
||||
CommonState* MG_State_T::commonState = nullptr;
|
||||
BufferState* MG_State_T::bufferState = nullptr;
|
||||
VertexArrayState* MG_State_T::vertexArrayState = nullptr;
|
||||
|
||||
namespace MG_State {
|
||||
void Init() {
|
||||
MG_State_T::textureState = new TextureState();
|
||||
MG_State_T::commonState = new CommonState();
|
||||
MG_State_T::bufferState = new BufferState();
|
||||
MG_State_T::vertexArrayState = new VertexArrayState();
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
delete MG_State_T::textureState;
|
||||
delete MG_State_T::commonState;
|
||||
delete MG_State_T::bufferState;
|
||||
delete MG_State_T::vertexArrayState;
|
||||
}
|
||||
|
||||
void SetError(GLenum error) {
|
||||
@@ -34,7 +40,9 @@ namespace MG_State {
|
||||
MG_State_T::glErrorQueue.pop();
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Take these functions apart into multiple files.
|
||||
|
||||
// Texture
|
||||
GLenum BindTextureUnit(GLenum textureUnit) {
|
||||
return MG_State_T::textureState->BindUnit(textureUnit);
|
||||
@@ -83,7 +91,8 @@ namespace MG_State {
|
||||
GLenum GetTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params) {
|
||||
return MG_State_T::textureState->GetLevelPropertyIntVector(target, level, pname, params);
|
||||
}
|
||||
|
||||
|
||||
// Common
|
||||
GLenum MG_State::SetPixelStoreInt(GLenum pname, GLint param) {
|
||||
return MG_State_T::commonState->SetPixelStoreInt(pname, param);
|
||||
}
|
||||
@@ -91,5 +100,84 @@ namespace MG_State {
|
||||
GLint MG_State::GetPixelStoreInt(GLenum pname) {
|
||||
return MG_State_T::commonState->GetPixelStoreInt(pname);
|
||||
}
|
||||
|
||||
// Buffer
|
||||
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPtr) {
|
||||
return MG_State_T::bufferState->AcquireBufferMemory(target, access, mappedPtr);
|
||||
}
|
||||
|
||||
GLenum ReleaseBufferMemory(GLenum target) {
|
||||
return MG_State_T::bufferState->ReleaseBufferMemory(target);
|
||||
}
|
||||
|
||||
GLenum CreateBuffer(GLuint* buffer) {
|
||||
return MG_State_T::bufferState->Create(buffer);
|
||||
}
|
||||
|
||||
GLenum CreateBuffers(GLsizei n, GLuint* buffers) {
|
||||
return MG_State_T::bufferState->CreateN(n, buffers);
|
||||
}
|
||||
|
||||
GLenum BindBuffer(GLenum target, GLuint buffer) {
|
||||
if (target == GL_ELEMENT_ARRAY_BUFFER) {
|
||||
auto* vao = MG_State_T::vertexArrayState->GetCurrentVAO();
|
||||
if (!vao) return GL_INVALID_OPERATION;
|
||||
vao->elementBuffer = (GLuint)buffer;
|
||||
}
|
||||
return MG_State_T::bufferState->Bind(target, buffer);
|
||||
}
|
||||
|
||||
GLenum CommitBufferStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
|
||||
return MG_State_T::bufferState->CommitStorage(target, size, data, usage);
|
||||
}
|
||||
|
||||
bool ValidateBufferHandle(GLuint buffer) {
|
||||
return MG_State_T::bufferState->ValidateHandle(buffer);
|
||||
}
|
||||
|
||||
void DeleteBuffer(GLuint buffer) {
|
||||
return MG_State_T::bufferState->Delete(buffer);
|
||||
}
|
||||
|
||||
GLenum QueryBufferPropertyIntVector(GLenum target, GLenum pname, GLint* params) {
|
||||
return MG_State_T::bufferState->QueryPropertyIntVector(target, pname, params);
|
||||
}
|
||||
|
||||
// VertexArray
|
||||
GLenum BindVertexArray(GLuint array) {
|
||||
return MG_State_T::vertexArrayState->Bind(array);
|
||||
}
|
||||
|
||||
GLenum CreateVertexArray(GLuint* array) {
|
||||
return MG_State_T::vertexArrayState->Create(array);
|
||||
}
|
||||
|
||||
GLenum CreateVertexArrays(GLsizei n, GLuint* arrays) {
|
||||
return MG_State_T::vertexArrayState->CreateN(n, arrays);
|
||||
}
|
||||
|
||||
GLenum EnableVertexAttribArray(GLuint index) {
|
||||
return MG_State_T::vertexArrayState->EnableAttrib(index);
|
||||
}
|
||||
|
||||
GLenum DisableVertexAttribArray(GLuint index) {
|
||||
return MG_State_T::vertexArrayState->DisableAttrib(index);
|
||||
}
|
||||
|
||||
GLenum SetVertexAttributeLayout(GLuint index, GLint size, GLenum type,
|
||||
GLboolean normalized, GLsizei stride,
|
||||
const void* pointer) {
|
||||
GLuint currentBuffer = MG_State_T::bufferState->GetCurrentBinding(GL_ARRAY_BUFFER);
|
||||
return MG_State_T::vertexArrayState->SetAttribPointer(
|
||||
index, size, type, normalized, stride, pointer, false, currentBuffer
|
||||
);
|
||||
}
|
||||
|
||||
GLenum SetVertexAttributeLayoutInt(GLuint index, GLint size, GLenum type,
|
||||
GLsizei stride, const void* pointer) {
|
||||
GLuint currentBuffer = MG_State_T::bufferState->GetCurrentBinding(GL_ARRAY_BUFFER);
|
||||
return MG_State_T::vertexArrayState->SetAttribPointer(
|
||||
index, size, type, GL_FALSE, stride, pointer, true, currentBuffer
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ struct MG_State_T {
|
||||
static std::queue<GLenum> glErrorQueue;
|
||||
static TextureState* textureState;
|
||||
static CommonState* commonState;
|
||||
static BufferState* bufferState;
|
||||
static VertexArrayState* vertexArrayState;
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
@@ -35,9 +37,34 @@ namespace MG_State {
|
||||
GLenum DeleteTexture(GLuint texture);
|
||||
GLenum DeleteTextures(GLsizei n, const GLuint* textures);
|
||||
GLenum GetTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params);
|
||||
|
||||
// Common
|
||||
GLenum SetPixelStoreInt(GLenum pname, GLint param);
|
||||
|
||||
GLint GetPixelStoreInt(GLenum pname);
|
||||
|
||||
// Buffer
|
||||
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPtr);
|
||||
GLenum ReleaseBufferMemory(GLenum target);
|
||||
GLenum CreateBuffer(GLuint* buffer);
|
||||
GLenum CreateBuffers(GLsizei n, GLuint* buffers);
|
||||
GLenum BindBuffer(GLenum target, GLuint buffer);
|
||||
GLenum CommitBufferStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||
bool ValidateBufferHandle(GLuint buffer);
|
||||
void DeleteBuffer(GLuint buffer);
|
||||
GLenum QueryBufferPropertyIntVector(GLenum target, GLenum pname, GLint* params);
|
||||
|
||||
// VertexArray
|
||||
|
||||
GLenum CreateVertexArray(GLuint* array);
|
||||
GLenum CreateVertexArrays(GLsizei n, GLuint* arrays);
|
||||
GLenum BindVertexArray(GLuint array);
|
||||
GLenum EnableVertexAttribArray(GLuint index);
|
||||
GLenum DisableVertexAttribArray(GLuint index);
|
||||
GLenum SetVertexAttributeLayout(GLuint index, GLint size, GLenum type,
|
||||
GLboolean normalized, GLsizei stride,
|
||||
const void* pointer);
|
||||
GLenum SetVertexAttributeLayoutInt(GLuint index, GLint size, GLenum type,
|
||||
GLsizei stride, const void* pointer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -98,10 +98,9 @@ private:
|
||||
static void ReverseBitOrder_(const GLubyte* src, GLubyte* dst, size_t size);
|
||||
static GLubyte ReverseBits_(GLubyte b);
|
||||
void SwapPixelBytes_(GLenum format, GLenum type, const GLubyte* src, GLubyte* dst);
|
||||
|
||||
GLenum CheckUploadingTexture2DValidity_(GLenum target, GLint level, GLint internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||
GLenum type, const void* data);
|
||||
GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||
GLenum type, const void* data);
|
||||
GLenum CheckUpdatingTextureRegion2DValidity_(GLenum target, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, const GLvoid* data);
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
//
|
||||
|
||||
// TODO: Add more gl error check for buffer state manager.
|
||||
|
||||
#include "VertexArrayState.h"
|
||||
|
||||
VertexArrayState::VertexArrayState() {
|
||||
vaos_[0];
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::Create(GLuint* array) {
|
||||
if (array == nullptr) return GL_INVALID_VALUE;
|
||||
|
||||
GLuint id = freeIds_.empty() ? ++lastId_ : *freeIds_.begin();
|
||||
if (!freeIds_.empty()) {
|
||||
freeIds_.erase(freeIds_.begin());
|
||||
}
|
||||
|
||||
*array = id;
|
||||
vaos_[id].generated = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::CreateN(GLsizei n, GLuint* arrays) {
|
||||
if (n < 0) {
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (n > 0 && arrays == nullptr) {
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
if (GLenum error = Create(&arrays[i]); error != GL_NO_ERROR) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::Bind(GLuint array) {
|
||||
if (array != 0 && !vaos_.count(array)) return GL_INVALID_OPERATION;
|
||||
currentVao_ = array;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::EnableAttrib(GLuint index) {
|
||||
if (currentVao_ == 0) return GL_INVALID_OPERATION;
|
||||
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
|
||||
vaos_[currentVao_].attribs[index].enabled = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::DisableAttrib(GLuint index) {
|
||||
if (currentVao_ == 0) return GL_INVALID_OPERATION;
|
||||
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
|
||||
vaos_[currentVao_].attribs[index].enabled = false;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::SetAttribPointer(GLuint index, GLint size, GLenum type,
|
||||
GLboolean normalized, GLsizei stride,
|
||||
const void* pointer, bool isInteger,
|
||||
GLuint currentArrayBuffer) {
|
||||
if (currentVao_ == 0) return GL_INVALID_OPERATION;
|
||||
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
|
||||
|
||||
VertexAttribState state;
|
||||
state.size = size;
|
||||
state.type = type;
|
||||
state.normalized = normalized;
|
||||
state.stride = stride;
|
||||
state.pointer = pointer;
|
||||
state.buffer = currentArrayBuffer;
|
||||
state.isInteger = isInteger;
|
||||
|
||||
vaos_[currentVao_].attribs[index] = state;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLuint VertexArrayState::GetBoundElementBuffer() {
|
||||
auto it = vaos_.find(currentVao_);
|
||||
return (it != vaos_.end()) ? it->second.elementBuffer : 0;
|
||||
}
|
||||
|
||||
VertexArrayObject* VertexArrayState::GetCurrentVAO() {
|
||||
auto it = vaos_.find(currentVao_);
|
||||
return (it != vaos_.end()) ? &it->second : &vaos_.at(0);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_VERTEXARRAYSTATE_H
|
||||
#define MOBILEGL_VERTEXARRAYSTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
struct VertexAttribState {
|
||||
bool enabled = false;
|
||||
GLint size = 4;
|
||||
GLenum type = GL_FLOAT;
|
||||
GLboolean normalized = GL_FALSE;
|
||||
GLsizei stride = 0;
|
||||
const GLvoid* pointer = nullptr;
|
||||
GLuint buffer = 0;
|
||||
bool isInteger = false;
|
||||
};
|
||||
|
||||
struct VertexArrayObject {
|
||||
bool generated = false;
|
||||
GLuint elementBuffer = 0;
|
||||
std::unordered_map<GLuint, VertexAttribState> attribs;
|
||||
};
|
||||
|
||||
class VertexArrayState {
|
||||
public:
|
||||
VertexArrayState();
|
||||
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
GLenum Create(GLuint* array);
|
||||
GLenum CreateN(GLsizei n, GLuint* arrays);
|
||||
GLenum Bind(GLuint array);
|
||||
GLenum EnableAttrib(GLuint index);
|
||||
GLenum DisableAttrib(GLuint index);
|
||||
GLenum SetAttribPointer(GLuint index, GLint size, GLenum type,
|
||||
GLboolean normalized, GLsizei stride,
|
||||
const void* pointer, bool isInteger,
|
||||
GLuint currentArrayBuffer);
|
||||
|
||||
GLuint GetBoundElementBuffer();
|
||||
VertexArrayObject* GetCurrentVAO();
|
||||
|
||||
private:
|
||||
std::unordered_map<GLuint, VertexArrayObject> vaos_;
|
||||
std::set<GLuint> freeIds_;
|
||||
GLuint lastId_ = 0;
|
||||
GLuint currentVao_ = 0;
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_VERTEXARRAYSTATE_H
|
||||
Reference in New Issue
Block a user