mirror of
https://github.com/ModOrganizer2/modorganizer-preview_dds.git
synced 2026-07-27 14:06:05 -07:00
Fixes for Qt6
This commit is contained in:
+244
-115
File diff suppressed because it is too large
Load Diff
+65
-44
@@ -1,39 +1,44 @@
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication, qCritical
|
||||
from PyQt5.QtGui import QOpenGLTexture
|
||||
from PyQt6.QtCore import QCoreApplication, qCritical
|
||||
from PyQt6.QtOpenGL import QOpenGLTexture
|
||||
|
||||
from . import DDSDefinitions
|
||||
from .glstuff import GLTextureFormat
|
||||
|
||||
|
||||
class DDSReadException(Exception):
|
||||
"""Thrown if there was an error reading a DDS file"""
|
||||
pass
|
||||
|
||||
ddsCubemapFaces = { DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_POSITIVEX: QOpenGLTexture.CubeMapPositiveX,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_NEGATIVEX: QOpenGLTexture.CubeMapNegativeX,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_POSITIVEY: QOpenGLTexture.CubeMapPositiveY,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_NEGATIVEY: QOpenGLTexture.CubeMapNegativeY,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_POSITIVEZ: QOpenGLTexture.CubeMapPositiveZ,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_NEGATIVEZ: QOpenGLTexture.CubeMapNegativeZ }
|
||||
|
||||
ddsCubemapFaces = {
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_POSITIVEX: QOpenGLTexture.CubeMapFace.CubeMapPositiveX,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_NEGATIVEX: QOpenGLTexture.CubeMapFace.CubeMapNegativeX,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_POSITIVEY: QOpenGLTexture.CubeMapFace.CubeMapPositiveY,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_NEGATIVEY: QOpenGLTexture.CubeMapFace.CubeMapNegativeY,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_POSITIVEZ: QOpenGLTexture.CubeMapFace.CubeMapPositiveZ,
|
||||
DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP_NEGATIVEZ: QOpenGLTexture.CubeMapFace.CubeMapNegativeZ}
|
||||
|
||||
|
||||
class DDSFile:
|
||||
def __init__(self, fileName):
|
||||
self.fileName = fileName
|
||||
self.header = DDSDefinitions.DDS_HEADER()
|
||||
self.dxt10Header = None
|
||||
self.glFormat = None
|
||||
self.glFormat: GLTextureFormat = None
|
||||
self.data = None
|
||||
self.isCubemap = None
|
||||
|
||||
|
||||
def load(self):
|
||||
with Path(self.fileName).open('rb') as file:
|
||||
magicNumber = file.read(4)
|
||||
if magicNumber != DDSDefinitions.DDS_MAGIC_NUMBER:
|
||||
qCritical(self.__tr("Magic number mismatch."))
|
||||
raise DDSReadException()
|
||||
|
||||
|
||||
self.header.fromStream(file)
|
||||
|
||||
|
||||
if self.header.ddspf.dwFlags & DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_FOURCC:
|
||||
fourCC = self.header.ddspf.dwFourCC
|
||||
if fourCC == b"DX10":
|
||||
@@ -41,12 +46,12 @@ class DDSFile:
|
||||
self.dxt10Header.fromStream(file)
|
||||
else:
|
||||
fourCC = None
|
||||
|
||||
|
||||
self.glFormat = DDSDefinitions.getGLFormat(self.header.ddspf, self.dxt10Header)
|
||||
self.data = []
|
||||
# Do this once per layer/mip level whatever, (times one per scanline if uncompressed). Also, potentially recompute this based on the format and size in case writers lie.
|
||||
#self.data.append(file.read(self.header.dwPitchOrLinearSize))
|
||||
|
||||
# self.data.append(file.read(self.header.dwPitchOrLinearSize))
|
||||
|
||||
layerCount = 1
|
||||
if self.header.dwCaps2 & DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP:
|
||||
self.isCubemap = True
|
||||
@@ -56,13 +61,14 @@ class DDSFile:
|
||||
layerCount += 1
|
||||
else:
|
||||
self.isCubemap = False
|
||||
|
||||
|
||||
for layer in range(layerCount):
|
||||
nextWidth = self.header.dwWidth
|
||||
nextHeight = self.header.dwHeight
|
||||
mipCount = self.mipLevels()
|
||||
for level in range(mipCount):
|
||||
if self.header.ddspf.dwFlags & (DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_ALPHA | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_RGB | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_YUV | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_LUMINANCE):
|
||||
if self.header.ddspf.dwFlags & (
|
||||
DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_ALPHA | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_RGB | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_YUV | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_LUMINANCE):
|
||||
size = nextWidth * nextHeight * ((self.header.ddspf.dwRGBBitCount + 7) // 8)
|
||||
elif fourCC:
|
||||
if self.dxt10Header:
|
||||
@@ -73,7 +79,7 @@ class DDSFile:
|
||||
self.data.append(file.read(size))
|
||||
nextWidth = max(nextWidth // 2, 1)
|
||||
nextHeight = max(nextHeight // 2, 1)
|
||||
|
||||
|
||||
def getDescription(self):
|
||||
format = ""
|
||||
# DX10 header says the format enum
|
||||
@@ -82,39 +88,45 @@ class DDSFile:
|
||||
# Pixel Format says the FourCC
|
||||
elif self.header.ddspf.dwFlags & DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_FOURCC:
|
||||
fourCC = self.header.ddspf.dwFourCC
|
||||
format = self.__tr("{0} (equivalent to {1})").format(fourCC.decode('ascii'), DDSDefinitions.fourCCToDXGI(fourCC).name.replace("DXGI_FORMAT_", ""))
|
||||
format = self.__tr("{0} (equivalent to {1})").format(fourCC.decode('ascii'),
|
||||
DDSDefinitions.fourCCToDXGI(fourCC).name.replace(
|
||||
"DXGI_FORMAT_", ""))
|
||||
# We've got bitmasks for the colour channels
|
||||
else:
|
||||
# This could be prettier if there was logic to detect that certain common bitmasks represented things more easily represented, like RGBA8
|
||||
if self.header.ddspf.dwFlags & (DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_RGB | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_YUV):
|
||||
format += self.__tr("Red bitmask {0}, Green bitmask {1}, Blue bitmask {2}").format(self.header.ddspf.dwRBitMask.hex().upper(), self.header.ddspf.dwGBitMask.hex().upper(), self.header.ddspf.dwBBitMask.hex().upper())
|
||||
if self.header.ddspf.dwFlags & (
|
||||
DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_RGB | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_YUV):
|
||||
format += self.__tr("Red bitmask {0}, Green bitmask {1}, Blue bitmask {2}").format(
|
||||
self.header.ddspf.dwRBitMask.hex().upper(), self.header.ddspf.dwGBitMask.hex().upper(),
|
||||
self.header.ddspf.dwBBitMask.hex().upper())
|
||||
if self.header.ddspf.dwFlags & DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_LUMINANCE:
|
||||
if format != "":
|
||||
format += ", "
|
||||
format += self.__tr("Luminance bitmask {0}").format(self.header.ddspf.dwRBitMask.hex().upper())
|
||||
if self.header.ddspf.dwFlags & (DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_ALPHA | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_ALPHAPIXELS):
|
||||
if self.header.ddspf.dwFlags & (
|
||||
DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_ALPHA | DDSDefinitions.DDS_PIXELFORMAT.Flags.DDPF_ALPHAPIXELS):
|
||||
if format != "":
|
||||
format += ", "
|
||||
format += self.__tr("Alpha bitmask {0}").format(self.header.ddspf.dwABitMask.hex().upper())
|
||||
|
||||
|
||||
size = self.__tr("{0}×{1}").format(self.header.dwWidth, self.header.dwHeight)
|
||||
|
||||
|
||||
dimensions = self.__tr("Cubemap") if self.isCubemap else self.__tr("2D")
|
||||
|
||||
|
||||
mipmaps = self.__tr("Mipmapped") if self.mipLevels() != 1 else self.__tr("No mipmaps")
|
||||
|
||||
|
||||
return self.__tr("{0}, {1} {2}, {3}").format(format, size, dimensions, mipmaps)
|
||||
|
||||
|
||||
def mipLevels(self):
|
||||
if self.header.dwFlags & DDSDefinitions.DDS_HEADER.Flags.DDSD_MIPMAPCOUNT:
|
||||
return self.header.dwMipMapCount
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
def asQOpenGLTexture(self, gl, context):
|
||||
if not self.data:
|
||||
return
|
||||
|
||||
|
||||
if self.glFormat.requirements:
|
||||
minVersion, extensions = self.glFormat.requirements
|
||||
glVersion = (gl.glGetIntegerv(gl.GL_MAJOR_VERSION), gl.glGetIntegerv(gl.GL_MINOR_VERSION))
|
||||
@@ -127,15 +139,15 @@ class DDSFile:
|
||||
if not compatible:
|
||||
qCritical(self.__tr("OpenGL driver incompatible with texture format."))
|
||||
return None
|
||||
|
||||
|
||||
if self.header.dwCaps2 & DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP:
|
||||
texture = QOpenGLTexture(QOpenGLTexture.TargetCubeMap)
|
||||
texture = QOpenGLTexture(QOpenGLTexture.Target.TargetCubeMap)
|
||||
if self.header.dwWidth != self.header.dwHeight:
|
||||
qCritical(self.__tr("Cubemap faces must be square"))
|
||||
return None
|
||||
else:
|
||||
# Assume GL_TEXTURE_2D for now
|
||||
texture = QOpenGLTexture(QOpenGLTexture.Target2D)
|
||||
texture = QOpenGLTexture(QOpenGLTexture.Target.Target2D)
|
||||
# Assume single layer for now
|
||||
# self.texture.setLayers(1)
|
||||
mipCount = self.mipLevels()
|
||||
@@ -143,9 +155,9 @@ class DDSFile:
|
||||
texture.setMipLevels(mipCount)
|
||||
texture.setMipLevelRange(0, mipCount - 1)
|
||||
texture.setSize(self.header.dwWidth, self.header.dwHeight)
|
||||
texture.setFormat(self.glFormat.internalFormat)
|
||||
texture.setFormat(QOpenGLTexture.TextureFormat(self.glFormat.internalFormat))
|
||||
texture.allocateStorage()
|
||||
|
||||
|
||||
if self.header.dwCaps2 & DDSDefinitions.DDS_HEADER.Caps2.DDSCAPS2_CUBEMAP:
|
||||
# Lisa hasn't whipped David Wang into shape yet. At least there are fewer bugs than under Raja.
|
||||
# The specific bug has been reported and AMD "will try to reproduce it soon"
|
||||
@@ -158,11 +170,19 @@ class DDSFile:
|
||||
for i in range(mipCount):
|
||||
if self.glFormat.compressed:
|
||||
if not noDSA:
|
||||
texture.setCompressedData(i, 0, ddsCubemapFaces[face], len(self.data[faceIndex * mipCount + i]), self.data[faceIndex * mipCount + i])
|
||||
texture.setCompressedData(i, 0, ddsCubemapFaces[face],
|
||||
len(self.data[faceIndex * mipCount + i]),
|
||||
self.data[faceIndex * mipCount + i])
|
||||
else:
|
||||
gl.glCompressedTexSubImage2D(ddsCubemapFaces[face], i, 0, 0, max(self.header.dwWidth // 2 ** i, 1), max(self.header.dwHeight // 2 ** i, 1), self.glFormat.internalFormat, len(self.data[faceIndex * mipCount + i]), self.data[faceIndex * mipCount + i])
|
||||
gl.glCompressedTexSubImage2D(ddsCubemapFaces[face], i, 0, 0,
|
||||
max(self.header.dwWidth // 2 ** i, 1),
|
||||
max(self.header.dwHeight // 2 ** i, 1),
|
||||
self.glFormat.internalFormat,
|
||||
len(self.data[faceIndex * mipCount + i]),
|
||||
self.data[faceIndex * mipCount + i])
|
||||
else:
|
||||
texture.setData(i, 0, ddsCubemapFaces[face], self.glFormat.format, self.glFormat.type, self.glFormat.converter(self.data[faceIndex * mipCount + i]))
|
||||
texture.setData(i, 0, ddsCubemapFaces[face], self.glFormat.format, self.glFormat.type,
|
||||
self.glFormat.converter(self.data[faceIndex * mipCount + i]))
|
||||
faceIndex += 1
|
||||
if noDSA:
|
||||
texture.release()
|
||||
@@ -171,15 +191,16 @@ class DDSFile:
|
||||
if self.glFormat.compressed:
|
||||
texture.setCompressedData(i, 0, len(self.data[i]), self.data[i])
|
||||
else:
|
||||
texture.setData(i, 0, self.glFormat.format, self.glFormat.type, self.glFormat.converter(self.data[i]))
|
||||
|
||||
texture.setWrapMode(QOpenGLTexture.ClampToEdge)
|
||||
|
||||
texture.setData(i, 0, self.glFormat.format, self.glFormat.type,
|
||||
self.glFormat.converter(self.data[i]))
|
||||
|
||||
texture.setWrapMode(QOpenGLTexture.WrapMode.ClampToEdge)
|
||||
|
||||
if self.glFormat.samplerType != "F":
|
||||
# integer textures can't be filtered
|
||||
texture.setMinMagFilters(QOpenGLTexture.NearestMipMapNearest, QOpenGLTexture.Nearest)
|
||||
|
||||
texture.setMinMagFilters(QOpenGLTexture.Filter.NearestMipMapNearest, QOpenGLTexture.Filter.Nearest)
|
||||
|
||||
return texture
|
||||
|
||||
|
||||
def __tr(self, str):
|
||||
return QCoreApplication.translate("DDSFile", str)
|
||||
+8
-4
@@ -1,5 +1,6 @@
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
class GL_IMAGE_FORMAT(IntEnum):
|
||||
GL_BYTE = 0x1400
|
||||
GL_UNSIGNED_BYTE = 0x1401
|
||||
@@ -111,9 +112,9 @@ class GL_IMAGE_FORMAT(IntEnum):
|
||||
GL_RGBA16F = 0x881A
|
||||
GL_RGB16F = 0x881B
|
||||
GL_R11F_G11F_B10F = 0x8C3A
|
||||
GL_UNSIGNED_INT_10F_11F_11F_REV_EXT = 0x8C3B # EXT_packed_float
|
||||
GL_UNSIGNED_INT_10F_11F_11F_REV_EXT = 0x8C3B # EXT_packed_float
|
||||
GL_RGB9_E5 = 0x8C3D
|
||||
GL_UNSIGNED_INT_5_9_9_9_REV_EXT = 0x8C3E # EXT_texture_shared_exponent
|
||||
GL_UNSIGNED_INT_5_9_9_9_REV_EXT = 0x8C3E # EXT_texture_shared_exponent
|
||||
GL_SRGB = 0x8C40
|
||||
GL_SRGB8 = 0x8C41
|
||||
GL_SRGB_ALPHA = 0x8C42
|
||||
@@ -173,12 +174,13 @@ class GL_IMAGE_FORMAT(IntEnum):
|
||||
GL_COMPRESSED_RGBA8_ETC2_EAC = 0x9278
|
||||
GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279
|
||||
|
||||
|
||||
class GLTextureFormat:
|
||||
def __init__(self, requirements, internalFormat, compressed):
|
||||
self.requirements = requirements
|
||||
self.internalFormat = internalFormat
|
||||
self.compressed = compressed
|
||||
|
||||
|
||||
if internalFormat.name.endswith("UI"):
|
||||
self.samplerType = "UI"
|
||||
elif internalFormat.name.endswith("I"):
|
||||
@@ -186,12 +188,14 @@ class GLTextureFormat:
|
||||
else:
|
||||
self.samplerType = "F"
|
||||
|
||||
|
||||
class CompressedGLTextureFormat(GLTextureFormat):
|
||||
def __init__(self, requirements, internalFormat):
|
||||
super().__init__(requirements, internalFormat, True)
|
||||
|
||||
|
||||
class UncompressedGLTextureFormat(GLTextureFormat):
|
||||
def __init__(self, requirements, internalFormat, format, type, converter = None):
|
||||
def __init__(self, requirements, internalFormat, format, type, converter=None):
|
||||
super().__init__(requirements, internalFormat, False)
|
||||
self.format = format
|
||||
self.type = type
|
||||
|
||||
+86
-77
@@ -2,9 +2,12 @@ import struct
|
||||
import sys
|
||||
import threading
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication, qDebug, Qt
|
||||
from PyQt5.QtGui import QColor, QOpenGLBuffer, QOpenGLContext, QOpenGLDebugLogger, QOpenGLShader, QOpenGLShaderProgram, QOpenGLTexture, QOpenGLVersionProfile, QOpenGLVertexArrayObject, QSurfaceFormat
|
||||
from PyQt5.QtWidgets import QCheckBox, QDialog, QGridLayout, QLabel, QOpenGLWidget, QPushButton, QWidget
|
||||
from PyQt6.QtCore import QCoreApplication, qDebug, Qt
|
||||
from PyQt6.QtGui import QColor, QOpenGLContext, QSurfaceFormat, QWindow
|
||||
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
|
||||
from PyQt6.QtWidgets import QCheckBox, QDialog, QGridLayout, QLabel, QPushButton, QWidget, QColorDialog
|
||||
from PyQt6.QtOpenGL import QOpenGLBuffer, QOpenGLDebugLogger, QOpenGLShader, QOpenGLShaderProgram, QOpenGLTexture, \
|
||||
QOpenGLVersionProfile, QOpenGLVertexArrayObject, QOpenGLFunctions_4_1_Core, QOpenGLVersionFunctionsFactory
|
||||
|
||||
from DDS.DDSFile import DDSFile
|
||||
|
||||
@@ -136,61 +139,61 @@ void main()
|
||||
|
||||
vertices = [
|
||||
# vertex coordinates texture coordinates
|
||||
-1.0, -1.0, 0.5, 1.0, 0.0, 1.0,
|
||||
-1.0, 1.0, 0.5, 1.0, 0.0, 0.0,
|
||||
1.0, 1.0, 0.5, 1.0, 1.0, 0.0,
|
||||
|
||||
-1.0, -1.0, 0.5, 1.0, 0.0, 1.0,
|
||||
1.0, 1.0, 0.5, 1.0, 1.0, 0.0,
|
||||
1.0, -1.0, 0.5, 1.0, 1.0, 1.0,
|
||||
-1.0, -1.0, 0.5, 1.0, 0.0, 1.0,
|
||||
-1.0, 1.0, 0.5, 1.0, 0.0, 0.0,
|
||||
1.0, 1.0, 0.5, 1.0, 1.0, 0.0,
|
||||
|
||||
-1.0, -1.0, 0.5, 1.0, 0.0, 1.0,
|
||||
1.0, 1.0, 0.5, 1.0, 1.0, 0.0,
|
||||
1.0, -1.0, 0.5, 1.0, 1.0, 1.0,
|
||||
]
|
||||
|
||||
|
||||
|
||||
glVersionProfile = QOpenGLVersionProfile()
|
||||
glVersionProfile.setVersion(2, 1)
|
||||
|
||||
|
||||
class DDSWidget(QOpenGLWidget):
|
||||
def __init__(self, ddsFile, debugContext = False, parent = None, f = Qt.WindowFlags()):
|
||||
super(DDSWidget, self).__init__(parent, f)
|
||||
|
||||
def __init__(self, ddsFile, debugContext=False, parent=None, flags=Qt.WindowType(0)):
|
||||
super(DDSWidget, self).__init__(parent, flags=flags)
|
||||
|
||||
self.ddsFile = ddsFile
|
||||
|
||||
|
||||
self.clean = True
|
||||
|
||||
|
||||
self.logger = None
|
||||
|
||||
|
||||
self.program = None
|
||||
self.transparecyProgram = None
|
||||
self.texture = None
|
||||
self.vbo = None
|
||||
self.vao = None
|
||||
|
||||
|
||||
self.backgroundColour = None
|
||||
|
||||
|
||||
if debugContext:
|
||||
format = QSurfaceFormat()
|
||||
format.setOption(QSurfaceFormat.DebugContext)
|
||||
format.setOption(QSurfaceFormat.FormatOption.DebugContext)
|
||||
self.setFormat(format)
|
||||
self.logger = QOpenGLDebugLogger(self)
|
||||
|
||||
|
||||
def __del__(self):
|
||||
self.cleanup()
|
||||
|
||||
|
||||
def __dtor__(self):
|
||||
self.cleanup()
|
||||
|
||||
|
||||
def initializeGL(self):
|
||||
if self.logger:
|
||||
self.logger.initialize()
|
||||
self.logger.messageLogged.connect(lambda message: qDebug(self.__tr("OpenGL debug message: {0}").fomat(message.message())))
|
||||
self.logger.messageLogged.connect(
|
||||
lambda message: qDebug(self.__tr("OpenGL debug message: {0}").fomat(message.message())))
|
||||
self.logger.startLogging()
|
||||
|
||||
gl = QOpenGLContext.currentContext().versionFunctions(glVersionProfile)
|
||||
|
||||
gl = QOpenGLVersionFunctionsFactory.get(glVersionProfile)
|
||||
QOpenGLContext.currentContext().aboutToBeDestroyed.connect(self.cleanup)
|
||||
|
||||
|
||||
self.clean = False
|
||||
|
||||
|
||||
fragmentShader = None
|
||||
vertexShader = vertexShader2D
|
||||
if self.ddsFile.isCubemap:
|
||||
@@ -205,79 +208,79 @@ class DDSWidget(QOpenGLWidget):
|
||||
fragmentShader = fragmentShaderUInt
|
||||
else:
|
||||
fragmentShader = fragmentShaderSInt
|
||||
|
||||
|
||||
self.program = QOpenGLShaderProgram(self)
|
||||
self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertexShader)
|
||||
self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragmentShader)
|
||||
self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertexShader)
|
||||
self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragmentShader)
|
||||
self.program.bindAttributeLocation("position", 0)
|
||||
self.program.bindAttributeLocation("texCoordIn", 1)
|
||||
self.program.link()
|
||||
|
||||
|
||||
self.transparecyProgram = QOpenGLShaderProgram(self)
|
||||
self.transparecyProgram.addShaderFromSourceCode(QOpenGLShader.Vertex, transparencyVS)
|
||||
self.transparecyProgram.addShaderFromSourceCode(QOpenGLShader.Fragment, transparencyFS)
|
||||
self.transparecyProgram.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, transparencyVS)
|
||||
self.transparecyProgram.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, transparencyFS)
|
||||
self.transparecyProgram.bindAttributeLocation("position", 0)
|
||||
self.transparecyProgram.link()
|
||||
|
||||
|
||||
self.vao = QOpenGLVertexArrayObject(self)
|
||||
vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)
|
||||
|
||||
self.vbo = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
|
||||
|
||||
self.vbo = QOpenGLBuffer(QOpenGLBuffer.Type.VertexBuffer)
|
||||
self.vbo.create()
|
||||
self.vbo.bind()
|
||||
|
||||
|
||||
theBytes = struct.pack("%sf" % len(vertices), *vertices)
|
||||
self.vbo.allocate(theBytes, len(theBytes))
|
||||
|
||||
|
||||
gl.glEnableVertexAttribArray(0)
|
||||
gl.glEnableVertexAttribArray(1)
|
||||
gl.glVertexAttribPointer(0, 4, gl.GL_FLOAT, False, 6 * 4, 0)
|
||||
gl.glVertexAttribPointer(1, 2, gl.GL_FLOAT, False, 6 * 4, 4 * 4)
|
||||
|
||||
|
||||
self.texture = self.ddsFile.asQOpenGLTexture(gl, QOpenGLContext.currentContext())
|
||||
|
||||
|
||||
def resizeGL(self, w, h):
|
||||
aspectRatioTex = self.texture.width() / self.texture.height() if self.texture else 1.0
|
||||
aspectRatioWidget = w / h
|
||||
ratioRatio = aspectRatioTex / aspectRatioWidget
|
||||
|
||||
|
||||
self.program.bind()
|
||||
self.program.setUniformValue("aspectRatioRatio", ratioRatio)
|
||||
self.program.release()
|
||||
|
||||
|
||||
def paintGL(self):
|
||||
gl = QOpenGLContext.currentContext().versionFunctions(glVersionProfile)
|
||||
|
||||
gl = QOpenGLVersionFunctionsFactory.get(glVersionProfile)
|
||||
|
||||
vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)
|
||||
|
||||
|
||||
# Draw checkerboard so transparency is obvious
|
||||
self.transparecyProgram.bind()
|
||||
|
||||
|
||||
if self.backgroundColour and self.backgroundColour.isValid():
|
||||
self.transparecyProgram.setUniformValue("backgroundColour", self.backgroundColour)
|
||||
|
||||
|
||||
gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6)
|
||||
|
||||
|
||||
self.transparecyProgram.release()
|
||||
|
||||
|
||||
self.program.bind()
|
||||
|
||||
|
||||
if self.texture:
|
||||
self.texture.bind()
|
||||
|
||||
|
||||
gl.glEnable(gl.GL_BLEND)
|
||||
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
|
||||
gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6)
|
||||
|
||||
|
||||
if self.texture:
|
||||
self.texture.release()
|
||||
self.program.release()
|
||||
|
||||
|
||||
def cleanup(self):
|
||||
if not self.clean:
|
||||
self.makeCurrent()
|
||||
|
||||
|
||||
self.program = None
|
||||
self.transparecyProgram = None
|
||||
if self.texture:
|
||||
@@ -287,22 +290,22 @@ class DDSWidget(QOpenGLWidget):
|
||||
self.vbo = None
|
||||
self.vao.destroy()
|
||||
self.vao = None
|
||||
|
||||
|
||||
self.doneCurrent()
|
||||
self.clean = True
|
||||
|
||||
|
||||
def setBackgroundColour(self, colour):
|
||||
self.backgroundColour = colour
|
||||
|
||||
|
||||
def getBackgroundColour(self):
|
||||
return self.backgroundColour
|
||||
|
||||
|
||||
def __tr(self, str):
|
||||
return QCoreApplication.translate("DDSWidget", str)
|
||||
|
||||
|
||||
class DDSPreview(mobase.IPluginPreview):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.__organizer = None
|
||||
@@ -324,15 +327,16 @@ class DDSPreview(mobase.IPluginPreview):
|
||||
return mobase.VersionInfo(1, 0, 0, 0)
|
||||
|
||||
def settings(self):
|
||||
return [mobase.PluginSetting("log gl errors", self.__tr("If enabled, log OpenGL errors and debug messages. May decrease performance."), False),
|
||||
return [mobase.PluginSetting("log gl errors", self.__tr(
|
||||
"If enabled, log OpenGL errors and debug messages. May decrease performance."), False),
|
||||
mobase.PluginSetting("background r", self.__tr("Red channel of background colour"), 0),
|
||||
mobase.PluginSetting("background g", self.__tr("Green channel of background colour"), 0),
|
||||
mobase.PluginSetting("background b", self.__tr("Blue channel of background colour"), 0),
|
||||
mobase.PluginSetting("background a", self.__tr("Alpha channel of background colour"), 0)]
|
||||
|
||||
|
||||
def supportedExtensions(self):
|
||||
return ["dds"]
|
||||
|
||||
|
||||
def genFilePreview(self, fileName, maxSize):
|
||||
ddsFile = DDSFile(fileName)
|
||||
ddsFile.load()
|
||||
@@ -342,41 +346,46 @@ class DDSPreview(mobase.IPluginPreview):
|
||||
# Label grows before button
|
||||
layout.setColumnStretch(0, 1)
|
||||
layout.addWidget(self.__makeLabel(ddsFile), 1, 0, 1, 1)
|
||||
|
||||
|
||||
ddsWidget = DDSWidget(ddsFile, self.__organizer.pluginSetting(self.name(), "log gl errors"))
|
||||
layout.addWidget(ddsWidget, 0, 0, 1, 2)
|
||||
|
||||
|
||||
layout.addWidget(self.__makeColourButton(ddsWidget), 1, 1, 1, 1)
|
||||
|
||||
|
||||
widget = QWidget()
|
||||
widget.setLayout(layout)
|
||||
return widget
|
||||
|
||||
|
||||
def __tr(self, str):
|
||||
return QCoreApplication.translate("DDSPreview", str)
|
||||
|
||||
|
||||
def __makeLabel(self, ddsFile):
|
||||
label = QLabel(ddsFile.getDescription())
|
||||
label.setWordWrap(True)
|
||||
label.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
||||
return label
|
||||
|
||||
|
||||
def __makeColourButton(self, ddsWidget):
|
||||
button = QPushButton(self.__tr("Pick background colour"))
|
||||
savedColour = QColor(self.__organizer.pluginSetting(self.name(), "background r"), self.__organizer.pluginSetting(self.name(), "background g"), self.__organizer.pluginSetting(self.name(), "background b"), self.__organizer.pluginSetting(self.name(), "background a"))
|
||||
savedColour = QColor(self.__organizer.pluginSetting(self.name(), "background r"),
|
||||
self.__organizer.pluginSetting(self.name(), "background g"),
|
||||
self.__organizer.pluginSetting(self.name(), "background b"),
|
||||
self.__organizer.pluginSetting(self.name(), "background a"))
|
||||
ddsWidget.setBackgroundColour(savedColour)
|
||||
|
||||
|
||||
def pickColour(unused):
|
||||
newColour = QColorDialog.getColor(ddsWidget.getBackgroundColour(), button, "Background colour", QColorDialog.ShowAlphaChannel)
|
||||
newColour = QColorDialog.getColor(ddsWidget.getBackgroundColour(), button, "Background colour",
|
||||
QColorDialog.ColorDialogOption.ShowAlphaChannel)
|
||||
if newColour.isValid():
|
||||
ddsWidget.setBackgroundColour(newColour)
|
||||
self.__organizer.setPluginSetting(self.name(), "background r", newColour.red())
|
||||
self.__organizer.setPluginSetting(self.name(), "background g", newColour.green())
|
||||
self.__organizer.setPluginSetting(self.name(), "background b", newColour.blue())
|
||||
self.__organizer.setPluginSetting(self.name(), "background a", newColour.alpha())
|
||||
|
||||
|
||||
button.clicked.connect(pickColour)
|
||||
return button
|
||||
|
||||
|
||||
|
||||
def createPlugin():
|
||||
return DDSPreview()
|
||||
Reference in New Issue
Block a user