From 5ff9585c3db701dcc6f4251be0b0344482502b6c Mon Sep 17 00:00:00 2001 From: Jampi0n <27952849+Jampi0n@users.noreply.github.com> Date: Wed, 22 Jun 2022 19:26:04 +0200 Subject: [PATCH 1/4] Add transparency toggle --- src/DDSPreview.py | 94 +++++++++++++++++++++++++++++--------------- src/DDSPreview_en.ts | 29 ++++++++++---- 2 files changed, 84 insertions(+), 39 deletions(-) diff --git a/src/DDSPreview.py b/src/DDSPreview.py index 96e8398..73338bd 100644 --- a/src/DDSPreview.py +++ b/src/DDSPreview.py @@ -151,9 +151,11 @@ glVersionProfile.setVersion(2, 1) class DDSWidget(QOpenGLWidget): - def __init__(self, ddsFile, debugContext = False, parent = None, f = Qt.WindowFlags()): + def __init__(self, ddsPreview, ddsFile, debugContext = False, parent = None, f = Qt.WindowFlags()): super(DDSWidget, self).__init__(parent, f) - + + self.ddsPreview = ddsPreview + self.ddsFile = ddsFile self.clean = True @@ -166,8 +168,6 @@ def __init__(self, ddsFile, debugContext = False, parent = None, f = Qt.WindowFl self.vbo = None self.vao = None - self.backgroundColour = None - if debugContext: format = QSurfaceFormat() format.setOption(QSurfaceFormat.DebugContext) @@ -252,9 +252,10 @@ def paintGL(self): # Draw checkerboard so transparency is obvious self.transparecyProgram.bind() - - if self.backgroundColour and self.backgroundColour.isValid(): - self.transparecyProgram.setUniformValue("backgroundColour", self.backgroundColour) + + backgroundColour = self.ddsPreview.getBackgroundColour() + if backgroundColour and backgroundColour.isValid(): + self.transparecyProgram.setUniformValue("backgroundColour", backgroundColour) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) @@ -264,9 +265,12 @@ def paintGL(self): if self.texture: self.texture.bind() - - gl.glEnable(gl.GL_BLEND) - gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) + + if self.ddsPreview.getTransparency(): + gl.glEnable(gl.GL_BLEND) + gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) + else: + gl.glDisable(gl.GL_BLEND) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) @@ -291,12 +295,6 @@ def cleanup(self): 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) @@ -311,6 +309,12 @@ def init(self, organizer): self.__organizer = organizer return True + def pluginSetting(self, name): + return self.__organizer.pluginSetting(self.name(), name) + + def setPluginSetting(self, name, value): + self.__organizer.setPluginSetting(self.name(), name, value) + def name(self): return "DDS Preview Plugin" @@ -328,7 +332,8 @@ def settings(self): 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)] + mobase.PluginSetting("background a", self.__tr("Alpha channel of background colour"), 0), + mobase.PluginSetting("transparency", self.__tr("If enabled, transparency will be displayed."), True)] def supportedExtensions(self): return ["dds"] @@ -342,12 +347,13 @@ def genFilePreview(self, fileName, maxSize): # 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) - + + ddsWidget = DDSWidget(self, ddsFile, self.__organizer.pluginSetting(self.name(), "log gl errors")) + layout.addWidget(ddsWidget, 0, 0, 1, 3) + + layout.addWidget(self.__makeColourButton(ddsWidget), 1, 2, 1, 1) + layout.addWidget(self.__makeToggleTransparencyButton(ddsWidget), 1, 1, 1, 1) + widget = QWidget() widget.setLayout(layout) return widget @@ -363,20 +369,44 @@ def __makeLabel(self, ddsFile): 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")) - ddsWidget.setBackgroundColour(savedColour) - + def pickColour(unused): - newColour = QColorDialog.getColor(ddsWidget.getBackgroundColour(), button, "Background colour", QColorDialog.ShowAlphaChannel) + newColour = QColorDialog.getColor(self.getBackgroundColour(), button, "Background colour", QColorDialog.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()) + self.setPluginSetting("background r", newColour.red()) + self.setPluginSetting("background g", newColour.green()) + self.setPluginSetting("background b", newColour.blue()) + self.setPluginSetting("background a", newColour.alpha()) + ddsWidget.update() button.clicked.connect(pickColour) return button + + def __makeToggleTransparencyButton(self, ddsWidget): + def getButtonText(): + if self.getTransparency(): + return self.__tr("Disable Transparency") + else: + return self.__tr("Enable Transparency") + + button = QPushButton(getButtonText()) + # Since every conflicting mod gets its own button, the text needs to be updated when the page is changed. + button.showEvent = lambda _: button.setText(getButtonText()) + + def toggleTransparency(unused): + transparency = not self.getTransparency() + self.setPluginSetting("transparency", transparency) + ddsWidget.update() + button.setText(getButtonText()) + + button.clicked.connect(toggleTransparency) + return button + + def getBackgroundColour(self): + return QColor(self.pluginSetting("background r"), self.pluginSetting("background g"), self.pluginSetting("background b"), self.pluginSetting("background a")) + + def getTransparency(self): + return self.pluginSetting("transparency") def createPlugin(): return DDSPreview() \ No newline at end of file diff --git a/src/DDSPreview_en.ts b/src/DDSPreview_en.ts index b2b0a09..bd025ca 100644 --- a/src/DDSPreview_en.ts +++ b/src/DDSPreview_en.ts @@ -71,40 +71,55 @@ DDSPreview - + Lets you preview DDS files by actually uploading them to the GPU. - + If enabled, log OpenGL errors and debug messages. May decrease performance. - + Red channel of background colour - + Green channel of background colour - + Blue channel of background colour - + Alpha channel of background colour - + + If enabled, transparency will be displayed. + + + + Pick background colour + + + Disable Transparency + + + + + Enable Transparency + + DDSWidget From 14ec98b0cc5479eef6427aa4d3fd03ba72a1757a Mon Sep 17 00:00:00 2001 From: Jampi0n <27952849+Jampi0n@users.noreply.github.com> Date: Mon, 27 Jun 2022 18:23:20 +0200 Subject: [PATCH 2/4] Select which color channels are displayed --- src/DDSPreview.py | 133 +++++++++++++++++++++++++++++++------------ src/DDSPreview_en.ts | 32 +++++------ 2 files changed, 110 insertions(+), 55 deletions(-) diff --git a/src/DDSPreview.py b/src/DDSPreview.py index 73338bd..37e9d82 100644 --- a/src/DDSPreview.py +++ b/src/DDSPreview.py @@ -1,10 +1,11 @@ import struct import sys import threading +import enum 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 PyQt5.QtGui import QColor, QOpenGLBuffer, QOpenGLContext, QOpenGLDebugLogger, QOpenGLShader, QOpenGLShaderProgram, QOpenGLVersionProfile, QOpenGLVertexArrayObject, QSurfaceFormat +from PyQt5.QtWidgets import QColorDialog, QGridLayout, QLabel, QOpenGLWidget, QPushButton, QWidget, QComboBox from DDS.DDSFile import DDSFile @@ -146,17 +147,51 @@ ] +class ColourChannels(enum.Enum): + RGBA = "Colour and Alpha" + RGB = "Colour" + A = "Alpha" + R = "Red" + G = "Green" + B = "Blue" + + +class DDSOptions: + def __init__(self, colour: QColor = QColor(0, 0, 0, 0), channels: ColourChannels = ColourChannels.RGBA): + self.backgroundColour = None + self.channels = None + self.setBackgroundColour(colour) + self.setChannels(channels) + + def setBackgroundColour(self, colour: QColor): + if isinstance(colour, QColor) and colour.isValid(): + self.backgroundColour = colour + else: + raise TypeError(str(colour) + " is not a valid QColor object.") + + def getBackgroundColour(self) -> QColor: + return self.backgroundColour + + def setChannels(self, channels: ColourChannels): + if isinstance(channels, ColourChannels): + self.channels = channels + else: + raise TypeError(str(channels) + " is not a valid ColourChannels object.") + + def getChannels(self) -> ColourChannels: + return self.channels + glVersionProfile = QOpenGLVersionProfile() glVersionProfile.setVersion(2, 1) class DDSWidget(QOpenGLWidget): - def __init__(self, ddsPreview, ddsFile, debugContext = False, parent = None, f = Qt.WindowFlags()): + def __init__(self, ddsFile, ddsOptions = DDSOptions(), debugContext = False, parent = None, f = Qt.WindowFlags()): super(DDSWidget, self).__init__(parent, f) - self.ddsPreview = ddsPreview - self.ddsFile = ddsFile + + self.ddsOptions = ddsOptions self.clean = True @@ -253,7 +288,7 @@ def paintGL(self): # Draw checkerboard so transparency is obvious self.transparecyProgram.bind() - backgroundColour = self.ddsPreview.getBackgroundColour() + backgroundColour = self.ddsOptions.getBackgroundColour() if backgroundColour and backgroundColour.isValid(): self.transparecyProgram.setUniformValue("backgroundColour", backgroundColour) @@ -266,11 +301,35 @@ def paintGL(self): if self.texture: self.texture.bind() - if self.ddsPreview.getTransparency(): - gl.glEnable(gl.GL_BLEND) - gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) + gl.glEnable(gl.GL_BLEND) + gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) + + def drawColour(alpha): + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_R, gl.GL_RED) + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_G, gl.GL_GREEN) + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_B, gl.GL_BLUE) + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_A, alpha) + + def drawGrayscale(channel): + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_R, channel) + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_G, channel) + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_B, channel) + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_A, gl.GL_ONE) + + if self.ddsOptions.getChannels() == ColourChannels.RGBA: + drawColour(gl.GL_ALPHA) + elif self.ddsOptions.getChannels() == ColourChannels.RGB: + drawColour(gl.GL_ONE) + elif self.ddsOptions.getChannels() == ColourChannels.R: + drawGrayscale(gl.GL_RED) + elif self.ddsOptions.getChannels() == ColourChannels.G: + drawGrayscale(gl.GL_GREEN) + elif self.ddsOptions.getChannels() == ColourChannels.B: + drawGrayscale(gl.GL_BLUE) + elif self.ddsOptions.getChannels() == ColourChannels.A: + drawGrayscale(gl.GL_ALPHA) else: - gl.glDisable(gl.GL_BLEND) + drawGrayscale(gl.GL_ZERO) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) @@ -304,9 +363,16 @@ class DDSPreview(mobase.IPluginPreview): def __init__(self): super().__init__() self.__organizer = None + self.options = None def init(self, organizer): self.__organizer = organizer + savedColour = QColor(self.pluginSetting("background r"), self.pluginSetting("background g"), self.pluginSetting("background b"), self.pluginSetting("background a")) + try: + savedChannels = ColourChannels[self.pluginSetting("channels")] + except KeyError: + savedChannels = ColourChannels.RGBA + self.options = DDSOptions(savedColour, savedChannels) return True def pluginSetting(self, name): @@ -333,7 +399,7 @@ def settings(self): 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), - mobase.PluginSetting("transparency", self.__tr("If enabled, transparency will be displayed."), True)] + mobase.PluginSetting("channels", self.__tr("The colour channels that are displayed."), ColourChannels.RGBA.name)] def supportedExtensions(self): return ["dds"] @@ -348,11 +414,11 @@ def genFilePreview(self, fileName, maxSize): layout.setColumnStretch(0, 1) layout.addWidget(self.__makeLabel(ddsFile), 1, 0, 1, 1) - ddsWidget = DDSWidget(self, ddsFile, self.__organizer.pluginSetting(self.name(), "log gl errors")) + ddsWidget = DDSWidget(ddsFile, self.options, self.__organizer.pluginSetting(self.name(), "log gl errors")) layout.addWidget(ddsWidget, 0, 0, 1, 3) layout.addWidget(self.__makeColourButton(ddsWidget), 1, 2, 1, 1) - layout.addWidget(self.__makeToggleTransparencyButton(ddsWidget), 1, 1, 1, 1) + layout.addWidget(self.__makeChannelsButton(ddsWidget), 1, 1, 1, 1) widget = QWidget() widget.setLayout(layout) @@ -371,42 +437,35 @@ def __makeColourButton(self, ddsWidget): button = QPushButton(self.__tr("Pick background colour")) def pickColour(unused): - newColour = QColorDialog.getColor(self.getBackgroundColour(), button, "Background colour", QColorDialog.ShowAlphaChannel) + newColour = QColorDialog.getColor(self.options.getBackgroundColour(), button, "Background colour", QColorDialog.ShowAlphaChannel) if newColour.isValid(): self.setPluginSetting("background r", newColour.red()) self.setPluginSetting("background g", newColour.green()) self.setPluginSetting("background b", newColour.blue()) self.setPluginSetting("background a", newColour.alpha()) + self.options.setBackgroundColour(newColour) ddsWidget.update() button.clicked.connect(pickColour) return button - def __makeToggleTransparencyButton(self, ddsWidget): - def getButtonText(): - if self.getTransparency(): - return self.__tr("Disable Transparency") - else: - return self.__tr("Enable Transparency") - - button = QPushButton(getButtonText()) - # Since every conflicting mod gets its own button, the text needs to be updated when the page is changed. - button.showEvent = lambda _: button.setText(getButtonText()) - - def toggleTransparency(unused): - transparency = not self.getTransparency() - self.setPluginSetting("transparency", transparency) + def __makeChannelsButton(self, ddsWidget): + listwidget = QComboBox() + channelKeys = [e.name for e in ColourChannels] + channelNames = [e.value for e in ColourChannels] + + listwidget.addItems(channelNames) + listwidget.setCurrentText(self.options.channels.value) + listwidget.setToolTip(self.__tr("Change which channels are displayed.")) + + listwidget.showEvent = lambda _: listwidget.setCurrentText(self.options.channels.value) + def onChanged(newIndex): + self.options.channels = ColourChannels[channelKeys[newIndex]] + self.setPluginSetting("channels", self.options.channels.name) ddsWidget.update() - button.setText(getButtonText()) - - button.clicked.connect(toggleTransparency) - return button - - def getBackgroundColour(self): - return QColor(self.pluginSetting("background r"), self.pluginSetting("background g"), self.pluginSetting("background b"), self.pluginSetting("background a")) - def getTransparency(self): - return self.pluginSetting("transparency") + listwidget.currentIndexChanged.connect(onChanged) + return listwidget def createPlugin(): return DDSPreview() \ No newline at end of file diff --git a/src/DDSPreview_en.ts b/src/DDSPreview_en.ts index bd025ca..27d14c5 100644 --- a/src/DDSPreview_en.ts +++ b/src/DDSPreview_en.ts @@ -1,5 +1,6 @@ - + + DDSFile @@ -71,60 +72,55 @@ DDSPreview - + Lets you preview DDS files by actually uploading them to the GPU. - + If enabled, log OpenGL errors and debug messages. May decrease performance. - + Red channel of background colour - + Green channel of background colour - + Blue channel of background colour - + Alpha channel of background colour - - If enabled, transparency will be displayed. - - - - + Pick background colour - - Disable Transparency + + The colour channels that are displayed. - - Enable Transparency + + Change which channels are displayed. DDSWidget - + OpenGL debug message: {0} From 024072841e1045a2df464fe7da8873af5350b528 Mon Sep 17 00:00:00 2001 From: Jampi0n <27952849+Jampi0n@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:29:03 +0200 Subject: [PATCH 3/4] Implement channels inside the shaders --- src/DDSPreview.py | 173 +++++++++++++++++++++++++++++++--------------- 1 file changed, 118 insertions(+), 55 deletions(-) diff --git a/src/DDSPreview.py b/src/DDSPreview.py index 37e9d82..860dd6b 100644 --- a/src/DDSPreview.py +++ b/src/DDSPreview.py @@ -2,9 +2,10 @@ import sys import threading import enum +from typing import Iterable from PyQt5.QtCore import QCoreApplication, qDebug, Qt -from PyQt5.QtGui import QColor, QOpenGLBuffer, QOpenGLContext, QOpenGLDebugLogger, QOpenGLShader, QOpenGLShaderProgram, QOpenGLVersionProfile, QOpenGLVertexArrayObject, QSurfaceFormat +from PyQt5.QtGui import QColor, QOpenGLBuffer, QOpenGLContext, QOpenGLDebugLogger, QOpenGLShader, QOpenGLShaderProgram, QOpenGLVersionProfile, QOpenGLVertexArrayObject, QSurfaceFormat, QMatrix4x4, QVector4D from PyQt5.QtWidgets import QColorDialog, QGridLayout, QLabel, QOpenGLWidget, QPushButton, QWidget, QComboBox from DDS.DDSFile import DDSFile @@ -54,12 +55,14 @@ #version 150 uniform sampler2D aTexture; +uniform mat4 channelMatrix; +uniform vec4 channelOffset; in vec2 texCoord; void main() { - gl_FragData[0] = texture(aTexture, texCoord); + gl_FragData[0] = channelMatrix * texture(aTexture, texCoord) + channelOffset; } """ @@ -67,13 +70,15 @@ #version 150 uniform usampler2D aTexture; +uniform mat4 channelMatrix; +uniform vec4 channelOffset; in vec2 texCoord; void main() { // autofilled alpha is 1, so if we have a scaling factor, we need separate ones for luminance and alpha - gl_FragData[0] = texture(aTexture, texCoord); + gl_FragData[0] = channelMatrix * texture(aTexture, texCoord) + channelOffset; } """ @@ -81,13 +86,15 @@ #version 150 uniform isampler2D aTexture; +uniform mat4 channelMatrix; +uniform vec4 channelOffset; in vec2 texCoord; void main() { // autofilled alpha is 1, so if we have a scaling factor and offset, we need separate ones for luminance and alpha - gl_FragData[0] = texture(aTexture, texCoord); + gl_FragData[0] = channelMatrix * texture(aTexture, texCoord) + channelOffset; } """ @@ -95,6 +102,8 @@ #version 150 uniform samplerCube aTexture; +uniform mat4 channelMatrix; +uniform vec4 channelOffset; in vec2 texCoord; @@ -104,7 +113,7 @@ { float theta = -2.0 * PI * texCoord.x; float phi = PI * texCoord.y; - gl_FragData[0] = texture(aTexture, vec3(sin(theta) * sin(phi), cos(theta) * sin(phi), cos(phi))); + gl_FragData[0] = channelMatrix * texture(aTexture, vec3(sin(theta) * sin(phi), cos(theta) * sin(phi), cos(phi))) + channelOffset; } """ @@ -146,22 +155,17 @@ 1.0, -1.0, 0.5, 1.0, 1.0, 1.0, ] - -class ColourChannels(enum.Enum): - RGBA = "Colour and Alpha" - RGB = "Colour" - A = "Alpha" - R = "Red" - G = "Green" - B = "Blue" - - class DDSOptions: - def __init__(self, colour: QColor = QColor(0, 0, 0, 0), channels: ColourChannels = ColourChannels.RGBA): + def __init__(self, colour: QColor = QColor(0, 0, 0, 0), channelMatrix: QMatrix4x4 = QMatrix4x4(), channelOffset: QVector4D = QVector4D()): + # QMatrix4x4 with no arguments is the identity matrix, so no channel transformations + # declare member variables with None values self.backgroundColour = None - self.channels = None + self.channelMatrix = None + self.channelOffset = None + # initialize member variables with error checks self.setBackgroundColour(colour) - self.setChannels(channels) + self.setChannelMatrix(channelMatrix) + self.setChannelOffset(channelOffset) def setBackgroundColour(self, colour: QColor): if isinstance(colour, QColor) and colour.isValid(): @@ -172,14 +176,44 @@ def setBackgroundColour(self, colour: QColor): def getBackgroundColour(self) -> QColor: return self.backgroundColour - def setChannels(self, channels: ColourChannels): - if isinstance(channels, ColourChannels): - self.channels = channels + def getChannelMatrix(self) -> QMatrix4x4: + return self.channelMatrix + + def setChannelMatrix(self, matrix): + + def flattenList(lst: Iterable): + tmp = [] + for e in lst: + if isinstance(e, Iterable): + tmp += flattenList(e) + elif isinstance(e, (int, float)): + tmp += [float(e)] + else: + raise ValueError("Can only set a matrix with numbers.") + return tmp + + if isinstance(matrix, Iterable): + flattened = flattenList(matrix) + if len(flattened) != 16: + raise ValueError("Must provide exactly 16 values.") + matrix = QMatrix4x4(flattened) + + if isinstance(matrix, QMatrix4x4): + self.channelMatrix = matrix else: - raise TypeError(str(channels) + " is not a valid ColourChannels object.") + raise ValueError("Can only set a matrix with numbers.") + + def getChannelOffset(self) -> QVector4D: + return self.channelOffset + + def setChannelOffset(self, vector): + if isinstance(vector, Iterable): + vector = list(vector) + if len(vector) != 4: + raise ValueError("Must provide exactly 4 values.") + vector = QVector4D(vector[0], vector[1], vector[2], vector[3]) + self.channelOffset = vector - def getChannels(self) -> ColourChannels: - return self.channels glVersionProfile = QOpenGLVersionProfile() @@ -304,32 +338,8 @@ def paintGL(self): gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) - def drawColour(alpha): - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_R, gl.GL_RED) - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_G, gl.GL_GREEN) - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_B, gl.GL_BLUE) - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_A, alpha) - - def drawGrayscale(channel): - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_R, channel) - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_G, channel) - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_B, channel) - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_SWIZZLE_A, gl.GL_ONE) - - if self.ddsOptions.getChannels() == ColourChannels.RGBA: - drawColour(gl.GL_ALPHA) - elif self.ddsOptions.getChannels() == ColourChannels.RGB: - drawColour(gl.GL_ONE) - elif self.ddsOptions.getChannels() == ColourChannels.R: - drawGrayscale(gl.GL_RED) - elif self.ddsOptions.getChannels() == ColourChannels.G: - drawGrayscale(gl.GL_GREEN) - elif self.ddsOptions.getChannels() == ColourChannels.B: - drawGrayscale(gl.GL_BLUE) - elif self.ddsOptions.getChannels() == ColourChannels.A: - drawGrayscale(gl.GL_ALPHA) - else: - drawGrayscale(gl.GL_ZERO) + self.program.setUniformValue("channelMatrix", self.ddsOptions.getChannelMatrix()) + self.program.setUniformValue("channelOffset", self.ddsOptions.getChannelOffset()) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) @@ -358,12 +368,63 @@ def __tr(self, str): return QCoreApplication.translate("DDSWidget", str) +class ColourChannels(enum.Enum): + RGBA = "Colour and Alpha" + RGB = "Colour" + A = "Alpha" + R = "Red" + G = "Green" + B = "Blue" + + +class DDSChannelManager: + def __init__(self, channels: ColourChannels): + self.channels = channels + + def setChannels(self, options: DDSOptions, channels: ColourChannels): + self.channels = channels + def drawColour(alpha: bool): + colorMatrix = QMatrix4x4() + colorOffset = QVector4D() + if not alpha: + colorMatrix[3, 3] = 0 + colorOffset.setW(1.0) + options.setChannelMatrix(colorMatrix) + options.setChannelOffset(colorOffset) + + def drawGrayscale(channel: ColourChannels): + colorOffset = QVector4D(0, 0, 0, 1) + channelVector = [0, 0, 0, 0] + if channels == ColourChannels.R: + channelVector[0] = 1 + elif channel == ColourChannels.G: + channelVector[1] = 1 + elif channel == ColourChannels.B: + channelVector[2] = 1 + elif channels == ColourChannels.A: + channelVector[3] = 1 + else: + raise ValueError("channel must be a single color channel.") + alphaVector = [0, 0, 0, 0] + colorMatrix = channelVector * 3 + alphaVector + options.setChannelMatrix(colorMatrix) + options.setChannelOffset(colorOffset) + + if channels == ColourChannels.RGBA: + drawColour(True) + elif channels == ColourChannels.RGB: + drawColour(False) + else: + drawGrayscale(channels) + + class DDSPreview(mobase.IPluginPreview): def __init__(self): super().__init__() self.__organizer = None self.options = None + self.channelManager = None def init(self, organizer): self.__organizer = organizer @@ -372,7 +433,9 @@ def init(self, organizer): savedChannels = ColourChannels[self.pluginSetting("channels")] except KeyError: savedChannels = ColourChannels.RGBA - self.options = DDSOptions(savedColour, savedChannels) + self.options = DDSOptions(savedColour) + self.channelManager = DDSChannelManager(savedChannels) + self.channelManager.setChannels(self.options, savedChannels) return True def pluginSetting(self, name): @@ -455,13 +518,13 @@ def __makeChannelsButton(self, ddsWidget): channelNames = [e.value for e in ColourChannels] listwidget.addItems(channelNames) - listwidget.setCurrentText(self.options.channels.value) + listwidget.setCurrentText(self.channelManager.channels.value) listwidget.setToolTip(self.__tr("Change which channels are displayed.")) - listwidget.showEvent = lambda _: listwidget.setCurrentText(self.options.channels.value) + listwidget.showEvent = lambda _: listwidget.setCurrentText(self.channelManager.channels.value) def onChanged(newIndex): - self.options.channels = ColourChannels[channelKeys[newIndex]] - self.setPluginSetting("channels", self.options.channels.name) + self.channelManager.setChannels(self.options, ColourChannels[channelKeys[newIndex]]) + self.setPluginSetting("channels", self.channelManager.channels.name) ddsWidget.update() listwidget.currentIndexChanged.connect(onChanged) From a9a1bfe14f74314145bd6a4d15459346e876761d Mon Sep 17 00:00:00 2001 From: Jampi0n <27952849+Jampi0n@users.noreply.github.com> Date: Fri, 1 Jul 2022 10:57:33 +0200 Subject: [PATCH 4/4] Simplify set matrix and vector functions --- src/DDSPreview.py | 31 ++----------------------------- src/DDSPreview_en.ts | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/src/DDSPreview.py b/src/DDSPreview.py index 860dd6b..ed25d89 100644 --- a/src/DDSPreview.py +++ b/src/DDSPreview.py @@ -180,40 +180,13 @@ def getChannelMatrix(self) -> QMatrix4x4: return self.channelMatrix def setChannelMatrix(self, matrix): - - def flattenList(lst: Iterable): - tmp = [] - for e in lst: - if isinstance(e, Iterable): - tmp += flattenList(e) - elif isinstance(e, (int, float)): - tmp += [float(e)] - else: - raise ValueError("Can only set a matrix with numbers.") - return tmp - - if isinstance(matrix, Iterable): - flattened = flattenList(matrix) - if len(flattened) != 16: - raise ValueError("Must provide exactly 16 values.") - matrix = QMatrix4x4(flattened) - - if isinstance(matrix, QMatrix4x4): - self.channelMatrix = matrix - else: - raise ValueError("Can only set a matrix with numbers.") + self.channelMatrix = QMatrix4x4(matrix) def getChannelOffset(self) -> QVector4D: return self.channelOffset def setChannelOffset(self, vector): - if isinstance(vector, Iterable): - vector = list(vector) - if len(vector) != 4: - raise ValueError("Must provide exactly 4 values.") - vector = QVector4D(vector[0], vector[1], vector[2], vector[3]) - self.channelOffset = vector - + self.channelOffset = QVector4D(vector) glVersionProfile = QOpenGLVersionProfile() diff --git a/src/DDSPreview_en.ts b/src/DDSPreview_en.ts index 27d14c5..6f47bc7 100644 --- a/src/DDSPreview_en.ts +++ b/src/DDSPreview_en.ts @@ -72,47 +72,47 @@ DDSPreview - + Lets you preview DDS files by actually uploading them to the GPU. - + If enabled, log OpenGL errors and debug messages. May decrease performance. - + Red channel of background colour - + Green channel of background colour - + Blue channel of background colour - + Alpha channel of background colour - + Pick background colour - + The colour channels that are displayed. - + Change which channels are displayed. @@ -120,7 +120,7 @@ DDSWidget - + OpenGL debug message: {0}