From 3897dfa1c2f8a8b8fb42b26a84e515c70ffef34d Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Fri, 25 Oct 2019 11:39:19 -0400 Subject: [PATCH] Fix #126. Warning: Korlib C API change. Version bumped. --- korlib/module.cpp | 2 +- korlib/texture.cpp | 23 ++++++++++++++++++----- korman/exporter/material.py | 32 ++++++++++++++------------------ korman/korlib/__init__.py | 3 ++- korman/korlib/texture.py | 18 ++++++++++++++---- 5 files changed, 49 insertions(+), 29 deletions(-) diff --git a/korlib/module.cpp b/korlib/module.cpp index 7c20fbf..fd291ce 100644 --- a/korlib/module.cpp +++ b/korlib/module.cpp @@ -19,7 +19,7 @@ #include "texture.h" // This konstant is compared against that in the Python module to prevent sneaky errors... -#define KORLIB_API_VERSION 1 +#define KORLIB_API_VERSION 2 static PyMethodDef korlib_Methods[] = { { _pycs("create_bump_LUT"), (PyCFunction)create_bump_LUT, METH_VARARGS, NULL }, diff --git a/korlib/texture.cpp b/korlib/texture.cpp index 84fd9aa..0cf9dac 100644 --- a/korlib/texture.cpp +++ b/korlib/texture.cpp @@ -195,6 +195,12 @@ enum { TEX_DETAIL_MULTIPLY = 2, }; +enum { + kOpaque = 0, + kOnOff = 1, + kFull = 2, +}; + typedef struct { PyObject_HEAD PyObject* m_blenderImage; @@ -476,12 +482,19 @@ static PyMethodDef pyGLTexture_Methods[] = { static PyObject* pyGLTexture_get_has_alpha(pyGLTexture* self, void*) { char* data = PyBytes_AsString(self->m_imageData); size_t bufsz = self->m_width * self->m_height * sizeof(uint32_t); - for (size_t i = 3; i < bufsz; i += 4) { - if (data[i] != 255) { - return PyBool_FromLong(1); - } + bool transparency = false; + + uint32_t* datap = reinterpret_cast(data); + uint32_t* endp = reinterpret_cast(data + bufsz); + while (datap < endp) { + uint8_t alpha = ((*datap & 0xFF000000) >> 24); + if (alpha == 0x00) + transparency = true; + else if (alpha != 0xFF) + return PyLong_FromLong(kFull); + datap++; } - return PyBool_FromLong(0); + return PyLong_FromLong(transparency ? kOnOff : kOpaque); } static PyObject* pyGLTexture_get_image_data(pyGLTexture* self, void*) { diff --git a/korman/exporter/material.py b/korman/exporter/material.py index 2157530..8a2cc94 100644 --- a/korman/exporter/material.py +++ b/korman/exporter/material.py @@ -61,19 +61,16 @@ class _Texture: self.detail_opacity_start = kwargs["detail_opacity_start"] self.detail_opacity_stop = kwargs["detail_opacity_stop"] self.calc_alpha = False - self.use_alpha = True + self.alpha_type = TextureAlpha.full self.allowed_formats = {"DDS"} self.is_cube_map = False else: self.is_detail_map = False - use_alpha = kwargs.get("use_alpha") if kwargs.get("force_calc_alpha", False) or self.calc_alpha: self.calc_alpha = True - self.use_alpha = True - elif use_alpha is None: - self.use_alpha = (image.channels == 4 and image.use_alpha) + self.alpha_type = TextureAlpha.full else: - self.use_alpha = use_alpha + self.alpha_type = kwargs.get("alpha_type", TextureAlpha.opaque) self.allowed_formats = kwargs.get("allowed_formats", {"DDS"} if self.mipmap else {"PNG", "JPG"}) self.is_cube_map = kwargs.get("is_cube_map", False) @@ -124,8 +121,8 @@ class _Texture: def _update(self, other): """Update myself with any props that might be overridable from another copy of myself""" # NOTE: detail map properties should NEVER be overridden. NEVER. EVER. kthx. - if other.use_alpha: - self.use_alpha = True + if self.alpha_type < other.alpha_type: + self.alpha_type = other.alpha_type if other.mipmap: self.mipmap = True @@ -536,8 +533,8 @@ class MaterialConverter: # prevent that as well, so we could theoretically slice-and-dice the single # image here... but... meh. Offloading taim. self.export_prepared_image(texture=texture, owner=layer, indent=3, - use_alpha=False, mipmap=True, allowed_formats={"DDS"}, - is_cube_map=True, tag="cubemap") + alpha_type=TextureAlpha.opaque, mipmap=True, + allowed_formats={"DDS"}, is_cube_map=True, tag="cubemap") def export_dynamic_env(self, bo, layer, texture, pl_class): @@ -650,12 +647,13 @@ class MaterialConverter: # Does the image have any alpha at all? if texture.image is not None: - has_alpha = texture.use_calculate_alpha or slot.use_stencil or self._test_image_alpha(texture.image) + alpha_type = self._test_image_alpha(texture.image) + has_alpha = texture.use_calculate_alpha or slot.use_stencil or alpha_type != TextureAlpha.opaque if (texture.image.use_alpha and texture.use_alpha) and not has_alpha: warning = "'{}' wants to use alpha, but '{}' is opaque".format(texture.name, texture.image.name) self._exporter().report.warn(warning, indent=3) else: - has_alpha = True + alpha_type, has_alpha = TextureAlpha.opaque, False # First, let's apply any relevant flags state = layer.state @@ -699,7 +697,7 @@ class MaterialConverter: allowed_formats = {"DDS"} if mipmap else {"PNG", "BMP"} self.export_prepared_image(texture=texture, owner=layer, - use_alpha=has_alpha, force_calc_alpha=slot.use_stencil, + alpha_type=alpha_type, force_calc_alpha=slot.use_stencil, is_detail_map=layer_props.is_detail_map, detail_blend=detail_blend, detail_fade_start=layer_props.detail_fade_start, @@ -778,7 +776,7 @@ class MaterialConverter: compression = plBitmap.kUncompressed else: raise RuntimeError(allowed_formats) - dxt = plBitmap.kDXT5 if key.use_alpha or key.calc_alpha else plBitmap.kDXT1 + dxt = plBitmap.kDXT5 if key.alpha_type == TextureAlpha.full else plBitmap.kDXT1 # Mayhaps we have a cached version of this that has already been exported cached_image = texcache.get_from_texture(key, compression) @@ -1035,10 +1033,8 @@ class MaterialConverter: if result is not None: return result - if image.channels != 4: - result = False - elif not image.use_alpha: - result = False + if image.channels != 4 or not image.use_alpha: + result = TextureAlpha.opaque else: # Using bpy.types.Image.pixels is VERY VERY VERY slow... key = _Texture(image=image) diff --git a/korman/korlib/__init__.py b/korman/korlib/__init__.py index 70f717b..1b6270d 100644 --- a/korman/korlib/__init__.py +++ b/korman/korlib/__init__.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with Korman. If not, see . -_KORLIB_API_VERSION = 1 +_KORLIB_API_VERSION = 2 try: from _korlib import _KORLIB_API_VERSION as _C_API_VERSION @@ -70,6 +70,7 @@ except ImportError as ex: else: from _korlib import * + from .texture import TextureAlpha finally: from .console import ConsoleCursor, ConsoleToggler diff --git a/korman/korlib/texture.py b/korman/korlib/texture.py index f616394..e1d9948 100644 --- a/korman/korlib/texture.py +++ b/korman/korlib/texture.py @@ -15,6 +15,7 @@ import array import bgl +import enum from ..helpers import ensure_power_of_two import math from PyHSPlasma import plBitmap @@ -95,6 +96,13 @@ def scale_image(buf, srcW, srcH, dstW, dstH): return bytes(dst) +@enum.unique +class TextureAlpha(enum.IntEnum): + opaque = 0 + on_off = 1 + full = 2 + + class GLTexture: def __init__(self, texkey=None, image=None, bgra=False, fast=False): assert texkey or image @@ -224,11 +232,13 @@ class GLTexture: @property def has_alpha(self): - data = self._image_data + data, xparency = self._image_data, False for i in range(3, len(data), 4): - if data[i] != 255: - return True - return False + if data[i] == 0: + xparency = True + elif data[i] != 255: + return TextureAlpha.full + return TextureAlpha.on_off if xparency else TextureAlpha.opaque def _get_image_data(self): return (self._width, self._height, self._image_data)