#include "gx/gll/GLMipmap.h" #include "gx/gll/GLCommand.h" #include "gx/gll/GLDevice.h" #include "gx/gll/GLFramebuffer.h" #include int32_t GLMipmap::GetDepthBits() { return this->m_DepthBits; } void GLMipmap::Attach(GLFramebuffer* framebuffer, GLenum attachPoint, int32_t a4) { if (!this->m_AttachPoints) { this->m_AttachPoints = new std::vector(); } auto& attachPoints = *this->m_AttachPoints; auto framebufferID = framebuffer->m_FramebufferID; if (framebufferID >= attachPoints.size()) { attachPoints.resize(framebufferID + 1); } else { BLIZZARD_ASSERT(attachPoints[framebufferID].framebuffer != framebuffer || attachPoints[framebufferID].point != attachPoint); auto& attach = attachPoints[framebufferID]; if ( attach.point && (attach.point != GL_DEPTH_ATTACHMENT || attachPoint != GL_STENCIL_ATTACHMENT) && (attach.point != GL_STENCIL_ATTACHMENT || attachPoint != GL_DEPTH_ATTACHMENT) ) { framebuffer->Detach(attach.point); } } GLDevice* device = GLDevice::Get(); auto currentTarget = device->GetCurrentTarget(); device->BindFramebuffer(framebuffer); if (framebufferID) { if (this->m_Target == GL_TEXTURE_3D) { glFramebufferTexture3DEXT( GL_FRAMEBUFFER, attachPoint, GL_TEXTURE_3D, this->m_Texture->m_TextureID, this->m_Level, a4 ); } else { glFramebufferTexture2DEXT( GL_FRAMEBUFFER, attachPoint, this->m_Target, this->m_Texture->m_TextureID, this->m_Level ); } } if (attachPoint == GL_DEPTH_ATTACHMENT && !this->m_DepthBits) { GLint depthBits = 0; glGetIntegerv(GL_DEPTH_BITS, &depthBits); this->m_DepthBits = depthBits; } device->BindFramebuffer(currentTarget); auto& attach = attachPoints[framebufferID]; attach.framebuffer = framebuffer; attach.zOffset = a4; if ( (attach.point != GL_DEPTH_ATTACHMENT || attachPoint != GL_STENCIL_ATTACHMENT) && (attach.point != GL_STENCIL_ATTACHMENT || attachPoint != GL_DEPTH_ATTACHMENT) ) { attach.point = attachPoint; } else { attach.point = GL_DEPTH_STENCIL; } } void GLMipmap::Detach(GLFramebuffer* framebuffer, GLenum attachPoint, bool a4) { GLuint framebufferID = framebuffer->m_FramebufferID; auto& attachPoints = *this->m_AttachPoints; BLIZZARD_ASSERT(attachPoints.size() >= framebufferID); BLIZZARD_ASSERT(attachPoints[framebufferID].framebuffer == framebuffer); if (!a4 && framebufferID) { GLDevice* v12 = GLDevice::Get(); GLFramebuffer* v14 = v12->GetCurrentTarget(); v12->BindFramebuffer(framebuffer); if (this->m_Target == GL_TEXTURE_3D) { glFramebufferTexture3DEXT(GL_FRAMEBUFFER, attachPoint, GL_TEXTURE_3D, 0, 0, 0); } else { glFramebufferTexture2DEXT(GL_FRAMEBUFFER, attachPoint, this->m_Target, 0, 0); } v12->BindFramebuffer(v14); } GLAttachPoint* v9 = &attachPoints[framebufferID]; if (v9->point == GL_DEPTH_STENCIL) { BLIZZARD_ASSERT(this->GetFormat() == GLTF_D24S8); if (attachPoint == GL_DEPTH_ATTACHMENT) { v9->point = GL_STENCIL_ATTACHMENT; } else if (attachPoint == GL_STENCIL_ATTACHMENT) { v9->point = GL_DEPTH_ATTACHMENT; } else { BLIZZARD_ASSERT(false); } } else { BLIZZARD_ASSERT(attachPoints[framebufferID].point == attachPoint); v9->framebuffer = 0; v9->point = 0; v9->zOffset = 0; // TODO // this->m_Texture->m_TimeStamp = Blizzard::Time::GetTimestamp(); } } void GLMipmap::DetachAll() { if (!this->m_AttachPoints) { return; } auto& attachPoints = *this->m_AttachPoints; for (int32_t i = 0; i < attachPoints.size(); i++) { BLIZZARD_ASSERT(attachPoints[i].point != GL_ZERO); BLIZZARD_ASSERT(attachPoints[i].framebuffer->m_FramebufferID == i); attachPoints[i].framebuffer->Detach(attachPoints[i].point); } } GLTextureFormat GLMipmap::GetFormat() { return this->m_Texture->GetFormat(); } TextureFormatInfo& GLMipmap::GetFormatInfo() { return this->m_Texture->GetFormatInfo(); }; uint16_t GLMipmap::GetHeight() { return this->m_Height; } int32_t GLMipmap::GetPitch() { int32_t bpp = this->GetFormatInfo().m_BytePerPixel; int32_t v4 = this->m_Texture->var12 >> this->m_Level; return v4 >= bpp ? v4 : bpp; } GLTexture* GLMipmap::GetTexture() { return this->m_Texture; } uint32_t GLMipmap::GetTextureID() { return this->m_Texture->m_TextureID; } uint16_t GLMipmap::GetWidth() { return this->m_Width; } void* GLMipmap::Map(GLEnum mode, const GLBox* area) { BLIZZARD_ASSERT(!this->m_Texture->IsSystemBuffer()); BLIZZARD_ASSERT(this->m_Data != nullptr); BLIZZARD_ASSERT(!this->m_Texture->IsRenderTarget()); BLIZZARD_ASSERT(mode != GL_ZERO); BLIZZARD_ASSERT(this->m_MapParams == nullptr); if (mode != GL_READ_ONLY) { this->m_Texture->m_MappedMipmaps++; } MapParams* mapParams = new MapParams(); this->m_MapParams = mapParams; if (area) { BLIZZARD_ASSERT(area->width > 0); BLIZZARD_ASSERT(area->height > 0); BLIZZARD_ASSERT(area->depth > 0); BLIZZARD_ASSERT(!this->GetFormatInfo().m_IsCompressed || ((area->top & 0x3) == 0 && (area->left & 0x3) == 0 && (area->width & 0x3) == 0 && (area->height & 0x3) == 0)); BLIZZARD_ASSERT((area->height + area->top) <= this->m_Height); BLIZZARD_ASSERT((area->depth + area->front) <= this->m_Depth); BLIZZARD_ASSERT((area->width + area->left) <= this->m_Width); mapParams->m_MapArea = { area->left, area->top, area->front, area->width, area->height, area->depth }; int32_t size = this->GetFormatInfo().m_BytePerPixel * this->m_Width * mapParams->m_MapArea.depth * mapParams->m_MapArea.height; mapParams->m_Size = this->GetFormatInfo().m_IsCompressed ? size >> 4 : size; mapParams->m_Unk7 = (this->GetFormatInfo().m_BytePerPixel * mapParams->m_MapArea.left) >> this->GetFormatInfo().m_IsCompressed ? 2 : 0; } else { mapParams->m_MapArea = { 0, 0, 0, this->m_Width, this->m_Height, this->m_Depth }; mapParams->m_Size = this->m_Size; mapParams->m_Unk7 = 0; } mapParams->m_MapMode = mode; int32_t rowPitch = this->GetPitch(); BLIZZARD_ASSERT(((mapParams->m_MapArea.top * rowPitch) + mapParams->m_MapArea.left * this->GetFormatInfo().m_BytePerPixel) < (this->GetFormatInfo().m_IsCompressed ? this->m_Size << 4 : this->m_Size)); int32_t v22 = rowPitch * this->m_Height; if (this->GetFormatInfo().m_IsCompressed) { v22 >>= 2; } unsigned char* v24 = this->m_Data + ((mapParams->m_MapArea.top * rowPitch) >> (this->GetFormatInfo().m_IsCompressed ? 2 : 0)) + (mapParams->m_MapArea.front * v22); mapParams->m_Unk8 = v24; return v24 + mapParams->m_Unk7; } void* GLMipmap::Map(GLEnum mode, const GLRect* rect) { if (rect) { GLBox area = { rect->left, rect->top, 0, rect->width, rect->height, 1 }; return this->Map(mode, &area); } else { return this->Map(mode, static_cast(nullptr)); } } void GLMipmap::ReleaseObject() { BLIZZARD_ASSERT(this->m_MapParams == nullptr); this->RemoveDebugMipmap(); this->DetachAll(); if (this->m_AttachPoints) { delete this->m_AttachPoints; } this->m_AttachPoints = nullptr; this->m_Unk24 = 0; } void GLMipmap::RemoveDebugMipmap() { // TODO } void GLMipmap::ResetData(GLEnum target, int32_t level, unsigned char* data) { BLIZZARD_ASSERT(this->m_Target != GL_TEXTURE_3D || !this->GetFormatInfo().m_IsCompressed); this->m_Target = target; this->m_Level = level; this->m_Data = data; BLIZZARD_ASSERT(this->GetFormat() != GLTF_INVALID); BLIZZARD_ASSERT(this->GetFormat() < GLTF_NUM_TEXTURE_FORMATS); if (!this->m_Texture->IsSystemBuffer() && this->m_Texture->IsRenderTarget()) { BLIZZARD_ASSERT(!this->GetFormatInfo().m_IsCompressed); this->TexImage(nullptr); this->m_Unk24 = 1; } } void GLMipmap::ResetSize(uint32_t width, uint32_t height, uint32_t depth) { this->m_Width = width ? width : 1; this->m_Height = height ? height : 1; this->m_Depth = depth ? depth : 1; if (this->GetFormatInfo().m_IsCompressed) { BLIZZARD_ASSERT(this->m_Depth == 1); this->m_Width = (this->m_Width + 3) & 0xFFFC; this->m_Height = (this->m_Height + 3) & 0xFFFC; } uint32_t v11 = this->GetFormatInfo().m_BytePerPixel; uint32_t v20 = this->m_Texture->var12 >> this->m_Level; if (v20 >= v11) { v11 = v20; } uint32_t v15 = v11 * this->m_Height; uint32_t v12; if (this->GetFormatInfo().m_IsCompressed) { v12 = v15 >> 2; } else { v12 = v15; } this->m_Size = this->m_Depth * v12; } void GLMipmap::TexImage(const void* pixels) { BLIZZARD_ASSERT((this->m_Texture->IsRenderTarget() || pixels != nullptr) && GLDevice::Get()->GetVertexArrayStates().buffers[eGLBT_PIXEL_UNPACK] == 0); if (this->m_Target == GL_TEXTURE_3D) { glTexImage3D( GL_TEXTURE_3D, this->m_Level, this->GetFormatInfo().m_InternalFormat, this->m_Width, this->m_Height, this->m_Depth, 0, this->GetFormatInfo().m_DataFormat, this->GetFormatInfo().m_DataType, pixels ); } else if (this->GetFormatInfo().m_IsCompressed) { glCompressedTexImage2D( this->m_Target, this->m_Level, this->GetFormatInfo().m_InternalFormat, this->m_Width, this->m_Height, 0, this->m_Size, pixels ); } else { glTexImage2D( this->m_Target, this->m_Level, this->GetFormatInfo().m_InternalFormat, this->m_Width, this->m_Height, 0, this->GetFormatInfo().m_DataFormat, this->GetFormatInfo().m_DataType, pixels ); } } void GLMipmap::TexSubImage(const GLBox& a2, int32_t size, const void* pixels) { BLIZZARD_ASSERT(!this->m_Texture->IsRenderTarget() && pixels != nullptr && GLDevice::Get()->GetVertexArrayStates().buffers[eGLBT_PIXEL_UNPACK] == 0); if (this->m_Target == GL_TEXTURE_3D) { glPixelStorei(GL_UNPACK_ROW_LENGTH, this->m_Width); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, this->m_Height); glTexSubImage3D( this->m_Target, this->m_Level, a2.left, a2.top, a2.front, a2.width, a2.height, a2.depth, this->GetFormatInfo().m_DataFormat, this->GetFormatInfo().m_DataType, pixels ); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); } else if (this->GetFormatInfo().m_IsCompressed) { glCompressedTexSubImage2D( this->m_Target, this->m_Level, 0, a2.top, this->m_Width, a2.height, this->GetFormatInfo().m_InternalFormat, size, pixels ); } else { glPixelStorei(GL_UNPACK_ROW_LENGTH, this->m_Width); glTexSubImage2D( this->m_Target, this->m_Level, a2.left, a2.top, a2.width, a2.height, this->GetFormatInfo().m_DataFormat, this->GetFormatInfo().m_DataType, pixels ); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } } void GLMipmap::Unmap() { BLIZZARD_ASSERT(!this->m_Texture->IsRenderTarget()); BLIZZARD_ASSERT(!this->m_Texture->IsSystemBuffer()); BLIZZARD_ASSERT(this->m_MapParams != nullptr); if (this->m_MapParams->m_MapMode == GL_READ_ONLY) { delete this->m_MapParams; this->m_MapParams = nullptr; return; } GLDevice* device = GLDevice::Get(); BLIZZARD_ASSERT(this->m_Texture->m_MappedMipmaps > 0); if (device->m_TexWorker) { device->m_TexWorker->Lock(); GLTexUnmap* command = new GLTexUnmap(this->m_Texture, this, this->m_MapParams); device->m_TexWorker->Send(command); device->m_TexWorker->Signal(); device->m_TexWorker->Unlock(); } else { this->Unmap(this->m_MapParams); } this->m_MapParams = nullptr; } void GLMipmap::Unmap(MapParams* mapParams) { BLIZZARD_ASSERT(mapParams != nullptr); this->m_Texture->Bind(nullptr, 0); if (this->m_Unk24) { if (this->GetFormatInfo().m_IsCompressed) { GLBox area = { 0, mapParams->m_MapArea.top, mapParams->m_MapArea.front, this->m_Width, mapParams->m_MapArea.height, mapParams->m_MapArea.depth }; this->TexSubImage(area, mapParams->m_Size, mapParams->m_Unk8); } else { this->TexSubImage(mapParams->m_MapArea, mapParams->m_Size, mapParams->m_Unk8 + mapParams->m_Unk7); } } else { this->TexImage(this->m_Data); this->m_Unk24 = 1; } delete mapParams; // TODO this->m_Texture->m_MappedMipmaps--; }