diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index fda3ac0e..1d2c62ae 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -1,4 +1,5 @@ #include "GL_Texture.h" +#include "GL/glext.h" #include "MG_State/GLState/TextureState/TextureObject.h" #include "MG_Util/Types.h" #include "Validators.h" @@ -19,7 +20,71 @@ namespace MobileGL { void TexSubImage2D_State(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) { - // TODO: implement + // ======================= Converting ================================ + TextureUploadTarget textureUploadingTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target); + TextureTarget textureTarget = MG_Util::ConvertTextureUploadTargetToTextureTarget(textureUploadingTarget); + TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format); + TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type); + TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(format); + + // ===================== Error Checking ============================== + if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return; + if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) return; + if (!TextureImpl::ValidateTextureUploadTarget(textureUploadingTarget)) return; + if (!TextureImpl::ValidateTextureLevelNumber(level)) return; + if (!TextureImpl::ValidateTextureSizeWithTextureUploadTarget(textureUploadingTarget, width, height)) return; + if (!TextureImpl::ValidateTextureSizeRange(width, height)) return; + if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return; + if (!TextureImpl::ValidateTextureFormatWithType(textureInputFormat, textureInternalFormat, + texturePixelDataType)) + return; + if (!TextureImpl::ValidateTextureLevelWithUploadTarget(textureUploadingTarget, level)) return; + + // TODO: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the + // GL_PIXEL_UNPACK_BUFFER target and the buffer object's data store is currently mapped. + // GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the + // GL_PIXEL_UNPACK_BUFFER target and the data would be unpacked from the buffer object such that the + // memory reads required would exceed the data store size. GL_INVALID_OPERATION is generated if a + // non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER target and data is not evenly + // divisible into the number of bytes needed to store in memory a datum indicated by type. + + // ======================= Processing ================================ + auto activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit()); + auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget); + auto textureObject = bindingSlot.GetBoundObject(); + + // ===================== Error Checking ============================== + if (!TextureImpl::ValidateTextureObject(textureObject)) return; + if (!TextureImpl::ValidateTextureSubImageOffsets(textureObject, xoffset, width, yoffset, height)) return; + + // ======================= Processing ================================ + SizeT imageSize = + MG_Util::CalculateTextureImageSize(textureInternalFormat, texturePixelDataType, {width, height, 1}); + auto& mipmap = textureObject->GetMipmap(level); + Vector& data = mipmap.data; + + SizeT bytesPerPixel = MG_Util::GetTexturePixelSize(textureInternalFormat) * + MG_Util::GetTexturePixelDataTypeSize(texturePixelDataType); + SizeT rowStride = mipmap.size.x() * bytesPerPixel; + + const Uint8* srcData = reinterpret_cast(pixels); + if (!srcData) { + return; + } + + for (GLint row = 0; row < height; ++row) { + SizeT dstOffset = ((yoffset + row) * mipmap.size.x() + xoffset) * bytesPerPixel; + SizeT srcOffset = row * width * bytesPerPixel; + + if (dstOffset + width * bytesPerPixel <= data.size()) { + Copy(reinterpret_cast(srcData + srcOffset), + reinterpret_cast(&data[dstOffset]), width * bytesPerPixel); + } else { + return; + } + } + + mipmap.dirty = true; } void TexSubImage1D_State(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, @@ -57,7 +122,7 @@ namespace MobileGL { TextureTarget textureTarget = MG_Util::ConvertTextureUploadTargetToTextureTarget(textureUploadingTarget); TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format); TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type); - TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(format); + TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat); // ===================== Error Checking ============================== if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return; diff --git a/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp b/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp index b6c194c7..21ea27ff 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp @@ -229,6 +229,7 @@ namespace MobileGL::MG_Impl::GLImpl { return false; } } + return true; } Bool ValidateTextureObject(SharedPtr textureObject) { @@ -238,7 +239,6 @@ namespace MobileGL::MG_Impl::GLImpl { MakeShared("MG_Impl/GLImpl", "ValidateTextureObject", "Texture object is null")); return false; } - return true; } @@ -255,5 +255,39 @@ namespace MobileGL::MG_Impl::GLImpl { } return true; } + + Bool ValidateTextureSubImageOffsets(SharedPtr textureObject, Int xoffset, + Int width, Int yoffset, Int height, Int zoffset, Int depth) { + auto baseSize = textureObject->GetBaseSize(); + if (xoffset < 0 || (xoffset + width) > baseSize.x()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets", + "xoffset must be non-negative and (xoffset + width) must not exceed " + "the texture width.")); + return false; + } + if (baseSize.y() == 0) return true; + + if (yoffset < 0 || (yoffset + height) > baseSize.y()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets", + "yoffset must be non-negative and (yoffset + height) must not exceed " + "the texture height.")); + return false; + } + if (baseSize.z() == 0) return true; + + if (zoffset < 0 || (zoffset + depth) > baseSize.z()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets", + "zoffset must be non-negative and (zoffset + depth) must not exceed " + "the texture depth.")); + return false; + } + return true; + } } // namespace TextureImpl } // namespace MobileGL::MG_Impl::GLImpl diff --git a/MobileGL/MG_Impl/GLImpl/Texture/Validators.h b/MobileGL/MG_Impl/GLImpl/Texture/Validators.h index 23f3032b..18354fd5 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/Validators.h +++ b/MobileGL/MG_Impl/GLImpl/Texture/Validators.h @@ -21,5 +21,7 @@ namespace MobileGL::MG_Impl::GLImpl { Bool ValidateTextureObject(SharedPtr textureObject); Bool ValidateTextureTargetUniformity(SharedPtr textureObject, TextureTarget target); + Bool ValidateTextureSubImageOffsets(SharedPtr textureObject, Int xoffset, + Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0); } // namespace TextureImpl } // namespace MobileGL::MG_Impl::GLImpl \ No newline at end of file