diff --git a/korlib/texture.cpp b/korlib/texture.cpp index bcfd998..85a12f4 100644 --- a/korlib/texture.cpp +++ b/korlib/texture.cpp @@ -126,7 +126,19 @@ static PyObject* pyGLTexture_generate_mipmap(pyGLTexture* self) { Py_RETURN_NONE; } -static uint8_t* _get_level_data(pyGLTexture* self, GLint level, bool bgra, bool quiet, size_t* size) { +struct _LevelData +{ + GLint m_width; + GLint m_height; + uint8_t* m_data; + size_t m_dataSize; + + _LevelData(GLint w, GLint h, uint8_t* ptr, size_t sz) + : m_width(w), m_height(h), m_data(ptr), m_dataSize(sz) + { } +}; + +static _LevelData _get_level_data(pyGLTexture* self, GLint level, bool bgra, bool quiet) { GLint width, height; glGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_HEIGHT, &height); @@ -137,32 +149,46 @@ static uint8_t* _get_level_data(pyGLTexture* self, GLint level, bool bgra, bool size_t bufsz; bufsz = (width * height * 4); - if (size) *size = bufsz; uint8_t* buf = new uint8_t[bufsz]; glGetTexImage(GL_TEXTURE_2D, level, fmt, GL_UNSIGNED_BYTE, reinterpret_cast(buf)); - return buf; + return _LevelData(width, height, buf, bufsz); } static PyObject* pyGLTexture_get_level_data(pyGLTexture* self, PyObject* args, PyObject* kwargs) { static char* kwlist[] = { _pycs("level"), _pycs("calc_alpha"), _pycs("bgra"), - _pycs("quiet"), NULL }; + _pycs("quiet"), _pycs("fast"), NULL }; GLint level = 0; bool calc_alpha = false; bool bgra = false; bool quiet = false; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ibbb", kwlist, &level, &calc_alpha, &bgra, &quiet)) { - PyErr_SetString(PyExc_TypeError, "get_level_data expects an optional int, bool, bool, bool"); + bool fast = false; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ibbbb", kwlist, &level, &calc_alpha, &bgra, &quiet, &fast)) { + PyErr_SetString(PyExc_TypeError, "get_level_data expects an optional int, bool, bool, bool, bool"); return NULL; } - size_t bufsz; - uint8_t* buf = _get_level_data(self, level, bgra, quiet, &bufsz); + _LevelData data = _get_level_data(self, level, bgra, quiet); + if (fast) + return pyBuffer_Steal(data.m_data, data.m_dataSize); + + // OpenGL returns a flipped image, so we must reflip it. + size_t row_stride = data.m_width * 4; + uint8_t* sptr = data.m_data; + uint8_t* eptr = data.m_data + (data.m_dataSize - row_stride); + uint8_t* temp = new uint8_t[row_stride]; + do { + memcpy(temp, sptr, row_stride); + memcpy(sptr, eptr, row_stride); + memcpy(eptr, temp, row_stride); + } while ((sptr += row_stride) < (eptr -= row_stride)); + delete[] temp; + if (calc_alpha) { - for (size_t i = 0; i < bufsz; i += 4) - buf[i + 3] = (buf[i + 0] + buf[i + 1] + buf[i + 2]) / 3; + for (size_t i = 0; i < data.m_dataSize; i += 4) + data.m_data[i + 3] = (data.m_data[i + 0] + data.m_data[i + 1] + data.m_data[i + 2]) / 3; } - return pyBuffer_Steal(buf, bufsz); + return pyBuffer_Steal(data.m_data, data.m_dataSize); } static PyObject* pyGLTexture_store_in_mipmap(pyGLTexture* self, PyObject* args) { @@ -208,15 +234,14 @@ static PyMethodDef pyGLTexture_Methods[] = { }; static PyObject* pyGLTexture_get_has_alpha(pyGLTexture* self, void*) { - size_t bufsz; - uint8_t* buf = _get_level_data(self, 0, false, true, &bufsz); - for (size_t i = 3; i < bufsz; i += 4) { - if (buf[i] != 255) { - delete[] buf; + _LevelData data = _get_level_data(self, 0, false, true); + for (size_t i = 3; i < data.m_dataSize; i += 4) { + if (data.m_data[i] != 255) { + delete[] data.m_data; return PyBool_FromLong(1); } } - delete[] buf; + delete[] data.m_data; return PyBool_FromLong(0); } diff --git a/korman/exporter/mesh.py b/korman/exporter/mesh.py index d1a3c0f..17e6b7c 100644 --- a/korman/exporter/mesh.py +++ b/korman/exporter/mesh.py @@ -224,7 +224,7 @@ class MeshConverter: geoVertex.position = hsVector3(*source.co) geoVertex.normal = hsVector3(*source.normal) geoVertex.color = hsColor32(*vertex_color) - geoVertex.uvs = [hsVector3(uv[0], uv[1], 0.0) for uv in uvws] + geoVertex.uvs = [hsVector3(uv[0], 1.0 - uv[1], 0.0) for uv in uvws] data.blender2gs[vertex][coluv] = len(data.vertices) data.vertices.append(geoVertex) face_verts.append(data.blender2gs[vertex][coluv]) diff --git a/korman/korlib/texture.py b/korman/korlib/texture.py index 7480174..ff4468c 100644 --- a/korman/korlib/texture.py +++ b/korman/korlib/texture.py @@ -58,7 +58,7 @@ class GLTexture: # It will simplify our state tracking a bit. bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_GENERATE_MIPMAP, 1) - def get_level_data(self, level=0, calc_alpha=False, bgra=False, quiet=False): + def get_level_data(self, level=0, calc_alpha=False, bgra=False, quiet=False, fast=False): """Gets the uncompressed pixel data for a requested mip level, optionally calculating the alpha channel from the image color data """ @@ -72,15 +72,21 @@ class GLTexture: buf = bgl.Buffer(bgl.GL_BYTE, size) fmt = bgl.GL_BGRA if bgra else bgl.GL_RGBA bgl.glGetTexImage(bgl.GL_TEXTURE_2D, level, fmt, bgl.GL_UNSIGNED_BYTE, buf); + if fast: + return bytes(buf) - # Calculate le alphas - # NOTE: the variable names are correct for GL_RGBA. We'll still get the right values for - # BGRA, obviously, but red will suddenly be... blue. Yeah. + # OpenGL returns the images upside down, so we're going to rotate it in memory. + finalBuf = bytearray(size) + row_stride = width * 4 + for i in range(height): + src, dst = i * row_stride, (height - (i+1)) * row_stride + finalBuf[dst:dst+row_stride] = buf[src:src+row_stride] + + # Do we need to calculate the alpha component? if calc_alpha: for i in range(0, size, 4): - r, g, b = buf[i:i+3] - buf[i+3] = int((r + g + b) / 3) - return bytes(buf) + finalBuf[i+3] = int(sum(finalBuf[i:i+3]) / 3) + return bytes(finalBuf) def _get_integer(self, arg): buf = bgl.Buffer(bgl.GL_INT, 1) @@ -97,7 +103,7 @@ class GLTexture: @property def has_alpha(self): - data = self.get_level_data(quiet=True) + data = self.get_level_data(quiet=True, fast=True) for i in range(3, len(data), 4): if data[i] != 255: return True