Skip to content

Commit

Permalink
Merge pull request #21 from matyalatte/add_dnd
Browse files Browse the repository at this point in the history
v0.4.1 update
  • Loading branch information
matyalatte authored May 19, 2024
2 parents 809f24c + 03d1f0b commit ea9008f
Show file tree
Hide file tree
Showing 12 changed files with 197 additions and 75 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
run: |
flake8
python for_dev/lint.py --path=addons/blender_dds_addon
codespell -S ".git,.pytest_cache,external,htmlcov"
codespell
test:
# Most code is from pytest-blender's workflow by mondeja.
Expand All @@ -40,25 +40,25 @@ jobs:
fail-fast: false
matrix:
include:
# Test with 2.83, 3.3, 3.6, and 4.0 on Windows
# Test with 2.83, 3.3, 3.6, and 4.1 on Windows
- platform: windows-latest
blender-version: '4.0.2'
blender-version: '4.1.1'

- platform: windows-latest
blender-version: '3.6.9'
blender-version: '3.6.11'

- platform: windows-latest
blender-version: '3.3.16'
blender-version: '3.3.18'

- platform: windows-latest
blender-version: '2.83.20'

# Test with 3.6 on Unix/Linux systems
- platform: ubuntu-latest
blender-version: '3.6.9'
blender-version: '3.6.11'

- platform: macos-latest
blender-version: '3.6.9'
blender-version: '3.6.11'

steps:
- uses: actions/checkout@v4
Expand Down
8 changes: 5 additions & 3 deletions addons/blender_dds_addon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import importlib
from pathlib import Path

from .ui import import_dds, export_dds, custom_properties, preferences, texture_list
from .ui import (import_dds, export_dds, custom_properties,
preferences, texture_list, drag_drop)
from .directx.texconv import unload_texconv
from .astcenc.astcenc import unload_astcenc

bl_info = {
'name': 'DDS textures',
'author': 'Matyalatte',
'version': (0, 4, 0),
'version': (0, 4, 1),
'blender': (2, 83, 20),
'location': 'Image Editor > Sidebar > DDS Tab',
'description': 'Import and export .dds files',
Expand Down Expand Up @@ -41,7 +42,8 @@ def reload_package_recursive(current_dir, module_dict):
import_dds,
export_dds,
texture_list,
custom_properties
custom_properties,
drag_drop,
]


Expand Down
8 changes: 4 additions & 4 deletions addons/blender_dds_addon/directx/dds.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,11 +443,11 @@ def get_texture_type(self):
def get_block_size(self):
fmt = self.get_format_as_str()
if ("ASTC" in fmt):
block_parsed = fmt.split("_")[1].split("X")
return [int(s) for s in block_parsed]
parsed = fmt.split("_")[1].split("X")
return (int(parsed[0]), int(parsed[1]))
if ("BC" in fmt):
return [4, 4]
return [1, 1]
return (4, 4)
return (1, 1)

def get_byte_per_block(self):
fmt = self.get_format_as_str()
Expand Down
84 changes: 42 additions & 42 deletions addons/blender_dds_addon/directx/dxgi_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,48 +207,48 @@ def int_to_byte(n):


# For detecting DXGI from fourCC
FOURCC_TO_DXGI = [
[[b'DXT1'], DXGI_FORMAT.BC1_UNORM],
[[b'DXT2', b'DXT3'], DXGI_FORMAT.BC2_UNORM],
[[b'DXT4', b'DXT5'], DXGI_FORMAT.BC3_UNORM],
[[b'ATI1', b'BC4U', b'3DC1'], DXGI_FORMAT.BC4_UNORM],
[[b'ATI2', b'BC5U', b'3DC2'], DXGI_FORMAT.BC5_UNORM],
[[b'BC4S'], DXGI_FORMAT.BC4_SNORM],
[[b'BC5S'], DXGI_FORMAT.BC5_SNORM],
[[b'BC6H'], DXGI_FORMAT.BC6H_UF16],
[[b'BC7L', b'BC7'], DXGI_FORMAT.BC7_UNORM],
[[b'RGBG'], DXGI_FORMAT.R8G8_B8G8_UNORM],
[[b'GRGB'], DXGI_FORMAT.G8R8_G8B8_UNORM],
[[b'YUY2', b'UYVY'], DXGI_FORMAT.YUY2],
[[int_to_byte(36)], DXGI_FORMAT.R16G16B16A16_UNORM],
[[int_to_byte(110)], DXGI_FORMAT.R16G16B16A16_SNORM],
[[int_to_byte(111)], DXGI_FORMAT.R16_FLOAT],
[[int_to_byte(112)], DXGI_FORMAT.R16G16_FLOAT],
[[int_to_byte(113)], DXGI_FORMAT.R16G16B16A16_FLOAT],
[[int_to_byte(114)], DXGI_FORMAT.R32_FLOAT],
[[int_to_byte(115)], DXGI_FORMAT.R32G32_FLOAT],
[[int_to_byte(116)], DXGI_FORMAT.R32G32B32A32_FLOAT],
[[b'AS44'], DXGI_FORMAT.ASTC_4X4_UNORM],
[[b'AS55'], DXGI_FORMAT.ASTC_5X5_UNORM],
[[b'AS66'], DXGI_FORMAT.ASTC_6X6_UNORM],
[[b'AS85'], DXGI_FORMAT.ASTC_8X5_UNORM],
[[b'AS86'], DXGI_FORMAT.ASTC_8X6_UNORM],
]
FOURCC_TO_DXGI = (
((b'DXT1'), DXGI_FORMAT.BC1_UNORM),
((b'DXT2', b'DXT3'), DXGI_FORMAT.BC2_UNORM),
((b'DXT4', b'DXT5'), DXGI_FORMAT.BC3_UNORM),
((b'ATI1', b'BC4U', b'3DC1'), DXGI_FORMAT.BC4_UNORM),
((b'ATI2', b'BC5U', b'3DC2'), DXGI_FORMAT.BC5_UNORM),
((b'BC4S'), DXGI_FORMAT.BC4_SNORM),
((b'BC5S'), DXGI_FORMAT.BC5_SNORM),
((b'BC6H'), DXGI_FORMAT.BC6H_UF16),
((b'BC7L', b'BC7'), DXGI_FORMAT.BC7_UNORM),
((b'RGBG'), DXGI_FORMAT.R8G8_B8G8_UNORM),
((b'GRGB'), DXGI_FORMAT.G8R8_G8B8_UNORM),
((b'YUY2', b'UYVY'), DXGI_FORMAT.YUY2),
((int_to_byte(36)), DXGI_FORMAT.R16G16B16A16_UNORM),
((int_to_byte(110)), DXGI_FORMAT.R16G16B16A16_SNORM),
((int_to_byte(111)), DXGI_FORMAT.R16_FLOAT),
((int_to_byte(112)), DXGI_FORMAT.R16G16_FLOAT),
((int_to_byte(113)), DXGI_FORMAT.R16G16B16A16_FLOAT),
((int_to_byte(114)), DXGI_FORMAT.R32_FLOAT),
((int_to_byte(115)), DXGI_FORMAT.R32G32_FLOAT),
((int_to_byte(116)), DXGI_FORMAT.R32G32B32A32_FLOAT),
((b'AS44'), DXGI_FORMAT.ASTC_4X4_UNORM),
((b'AS55'), DXGI_FORMAT.ASTC_5X5_UNORM),
((b'AS66'), DXGI_FORMAT.ASTC_6X6_UNORM),
((b'AS85'), DXGI_FORMAT.ASTC_8X5_UNORM),
((b'AS86'), DXGI_FORMAT.ASTC_8X6_UNORM),
)


# Used to detect DXGI format from DDS_PIXELFORMAT
BITMASK_TO_DXGI = [
[[0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000], DXGI_FORMAT.B8G8R8A8_UNORM],
[[0x00ff0000, 0x0000ff00, 0x000000ff, 0], DXGI_FORMAT.B8G8R8X8_UNORM],
[[0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000], DXGI_FORMAT.R8G8B8A8_UNORM],
[[0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000], DXGI_FORMAT.R10G10B10A2_UNORM],
[[0x0000ffff, 0xffff0000, 0, 0], DXGI_FORMAT.R16G16_UNORM],
[[0xffffffff, 0, 0, 0], DXGI_FORMAT.R32_FLOAT],
[[0x7c00, 0x03e0, 0x001f, 0x8000], DXGI_FORMAT.B5G5R5A1_UNORM],
[[0xf800, 0x07e0, 0x001f, 0], DXGI_FORMAT.B5G6R5_UNORM],
[[0x0f00, 0x00f0, 0x000f, 0xf000], DXGI_FORMAT.B4G4R4A4_UNORM],
[[0x00ff, 0, 0, 0xff00], DXGI_FORMAT.R8G8_UNORM],
[[0xffff, 0, 0, 0], DXGI_FORMAT.R16_UNORM],
[[0xff, 0, 0, 0], DXGI_FORMAT.R8_UNORM],
[[0, 0, 0, 0xff], DXGI_FORMAT.A8_UNORM]
]
BITMASK_TO_DXGI = (
((0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000), DXGI_FORMAT.B8G8R8A8_UNORM),
((0x00ff0000, 0x0000ff00, 0x000000ff, 0), DXGI_FORMAT.B8G8R8X8_UNORM),
((0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000), DXGI_FORMAT.R8G8B8A8_UNORM),
((0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000), DXGI_FORMAT.R10G10B10A2_UNORM),
((0x0000ffff, 0xffff0000, 0, 0), DXGI_FORMAT.R16G16_UNORM),
((0xffffffff, 0, 0, 0), DXGI_FORMAT.R32_FLOAT),
((0x7c00, 0x03e0, 0x001f, 0x8000), DXGI_FORMAT.B5G5R5A1_UNORM),
((0xf800, 0x07e0, 0x001f, 0), DXGI_FORMAT.B5G6R5_UNORM),
((0x0f00, 0x00f0, 0x000f, 0xf000), DXGI_FORMAT.B4G4R4A4_UNORM),
((0x00ff, 0, 0, 0xff00), DXGI_FORMAT.R8G8_UNORM),
((0xffff, 0, 0, 0), DXGI_FORMAT.R16_UNORM),
((0xff, 0, 0, 0), DXGI_FORMAT.R8_UNORM),
((0, 0, 0, 0xff), DXGI_FORMAT.A8_UNORM)
)
4 changes: 2 additions & 2 deletions addons/blender_dds_addon/directx/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def get_dll_close():
return ctypes.windll.kernel32.FreeLibrary
else:
# Search libc, libdl, and libSystem
for lib_name in ["c", "dl", "System"]:
for lib_name in {"c", "dl", "System"}:
dlclose = get_dll_close_from_lib(lib_name)
if dlclose is not None:
return dlclose
Expand All @@ -77,7 +77,7 @@ def get_dll_close():
def find_local_library(dir, lib_name):
for f in os.listdir(dir):
name, ext = os.path.splitext(f)
if ext not in [".dll", ".dylib", ".so"]:
if ext not in {".dll", ".dylib", ".so"}:
continue
if name.startswith(lib_name) or name.startswith("lib" + lib_name):
return os.path.join(dir, f)
Expand Down
12 changes: 6 additions & 6 deletions addons/blender_dds_addon/ui/bpy_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ def load_texture(file, name, color_space='Non-Color'):

# height, width, x+pos, x-pos, y+pos, y-pos, z+pos, z-pos
cube_layouts = {
"h-cross": [3, 4, [1, 2], [1, 0], [2, 1], [0, 1], [1, 1], [1, 3]],
"v-cross": [4, 3, [2, 2], [2, 0], [3, 1], [1, 1], [2, 1], [0, 1]],
"h-cross-fnz": [3, 4, [1, 2], [1, 0], [2, 1], [0, 1], [1, 1], [1, 3]],
"v-cross-fnz": [4, 3, [2, 2], [2, 0], [3, 1], [1, 1], [2, 1], [0, 1]],
"h-strip": [1, 6, [0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5]],
"v-strip": [6, 1, [5, 0], [4, 0], [3, 0], [2, 0], [1, 0], [0, 0]],
"h-cross": (3, 4, (1, 2), (1, 0), (2, 1), (0, 1), (1, 1), (1, 3)),
"v-cross": (4, 3, (2, 2), (2, 0), (3, 1), (1, 1), (2, 1), (0, 1)),
"h-cross-fnz": (3, 4, (1, 2), (1, 0), (2, 1), (0, 1), (1, 1), (1, 3)),
"v-cross-fnz": (4, 3, (2, 2), (2, 0), (3, 1), (1, 1), (2, 1), (0, 1)),
"h-strip": (1, 6, (0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5)),
"v-strip": (6, 1, (5, 0), (4, 0), (3, 0), (2, 0), (1, 0), (0, 0)),
}


Expand Down
2 changes: 1 addition & 1 deletion addons/blender_dds_addon/ui/custom_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def get_alt_fmt(fmt):

def is_supported(fmt):
return ('TYPELESS' not in fmt) and\
(len(fmt) > 4) and (fmt not in ["UNKNOWN", "OPAQUE_420"])
(len(fmt) > 4) and (fmt not in {"UNKNOWN", "OPAQUE_420"})


DDS_FMT_ITEMS = [(fmt, get_alt_fmt(fmt), '') for fmt in fmt_list if is_supported(fmt)]
Expand Down
114 changes: 114 additions & 0 deletions addons/blender_dds_addon/ui/drag_drop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import os
import time
import traceback

import bpy
from .import_dds import import_dds
from ..directx.texconv import Texconv, unload_texconv
from ..astcenc.astcenc import Astcenc, unload_astcenc
from .bpy_util import flush_stdout


def is_dds_panel(context):
return (context.area and context.area.type == 'IMAGE_EDITOR'
and context.region and context.region.type == 'UI'
and context.region.active_panel_category == 'DDS')


class DDS_OT_drag_drop_import(bpy.types.Operator):
"""Operator to import dropped .dds files."""
bl_idname = "dds.drag_drop_import"
bl_label = "Import a dropped dds file"
directory: bpy.props.StringProperty(subtype='FILE_PATH', options={'SKIP_SAVE'})
files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement, options={'SKIP_SAVE'})

@classmethod
def poll(cls, context):
return is_dds_panel(context)

def execute(self, context):
if not self.directory or not self.files:
return {'CANCELLED'}

texconv = Texconv()
astcenc = Astcenc()

try:
start_time = time.time()
count = 0

for file in self.files:
filepath = os.path.join(self.directory, file.name)
import_dds(context, filepath,
texconv=texconv, astcenc=astcenc)
flush_stdout()
count += 1
elapsed_s = f'{(time.time() - start_time):.2f}s'
if count == 0:
raise RuntimeError("Imported no DDS files.")
elif count == 1:
m = f'Success! Imported a DDS file in {elapsed_s}'
else:
m = f'Success! Imported {count} DDS files in {elapsed_s}'
print(m)
self.report({'INFO'}, m)
ret = {'FINISHED'}

except Exception as e:
print(traceback.format_exc())
self.report({'ERROR'}, e.args[0])
ret = {'CANCELLED'}

# release DLL resources
unload_texconv()
unload_astcenc()

return ret

def invoke(self, context, event):
if self.directory and self.files:
return self.execute(context)
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}


if (4, 1, 0) > bpy.app.version:
# blender 4.0 or older don't support drag-drop
class Dummy:
pass
handler_cls = Dummy
else:
handler_cls = bpy.types.FileHandler


class DDS_FH_import(handler_cls):
bl_idname = "DDS_FH_import"
bl_label = "File handler for dds import"
bl_import_operator = "dds.drag_drop_import"
bl_file_extensions = ".dds"

@classmethod
def poll_drop(cls, context):
return is_dds_panel(context)


classes = (
DDS_OT_drag_drop_import,
DDS_FH_import,
)

if (4, 1, 0) > bpy.app.version:
# blender 4.0 or older don't support drag-drop
classes = ()


def register():
"""Add UI panel, operator, and properties."""
for c in classes:
bpy.utils.register_class(c)


def unregister():
"""Remove UI panel, operator, and properties."""
for c in classes:
bpy.utils.unregister_class(c)
18 changes: 9 additions & 9 deletions addons/blender_dds_addon/ui/export_dds.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def save_dds(tex, file, dds_fmt, invert_normals=False, no_mip=False,
if is_srgb and color_space != 'sRGB':
print("Warning: Specified DXGI format uses sRGB as a color space,"
f"but the texture uses {color_space} in Blender")
elif (not is_srgb) and color_space not in ['Non-Color', 'Raw']:
elif (not is_srgb) and color_space not in {'Non-Color', 'Raw'}:
print("Warning: Specified DXGI format does not use any color space conversion,"
f"but the texture uses {color_space} in Blender")

Expand All @@ -88,12 +88,12 @@ def gcd(m, n):
h_ratio = h // face_size

expected_ratio_dict = {
"h-cross": [4, 3],
"v-cross": [3, 4],
"h-cross-fnz": [4, 3],
"v-cross-fnz": [3, 4],
"h-strip": [6, 1],
"v-strip": [1, 6]
"h-cross": (4, 3),
"v-cross": (3, 4),
"h-cross-fnz": (4, 3),
"v-cross-fnz": (3, 4),
"h-strip": (6, 1),
"v-strip": (1, 6)
}

expected_ratio = expected_ratio_dict[cubemap_layout]
Expand Down Expand Up @@ -233,9 +233,9 @@ def put_export_options(context, layout):
if not dds_properties_exist():
layout.prop(dds_options, 'no_mip')
layout.prop(dds_options, 'texture_type')
if dds_options.texture_type in ["cube", "cube_array"]:
if dds_options.texture_type in {"cube", "cube_array"}:
layout.prop(dds_options, "cubemap_layout")
if dds_options.texture_type in ["2d_array", "cube_array", "volume"]:
if dds_options.texture_type in {"2d_array", "cube_array", "volume"}:
draw_texture_list(layout, context, dds_options)
layout.prop(dds_options, 'allow_slow_codec')

Expand Down
3 changes: 3 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
ver 0.4.1
- Added support for drag-drop import

ver 0.4.0
- Added support for arm64 chips on macOS (e.g. Apple M1)
- Added support for ASTC formats
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Blender-DDS-Addon v0.4.0
# Blender-DDS-Addon v0.4.1

[![Github All Releases](https://img.shields.io/github/downloads/matyalatte/Blender-DDS-Addon/total.svg)]()
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
Expand Down
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ max-line-length = 119

[tool:pytest]
pythonpath = addons

[codespell]
skip = .git,.pytest_cache,external,htmlcov

0 comments on commit ea9008f

Please sign in to comment.