[Scummvm-git-logs] scummvm master -> 02294ee7175ac3e2b400569508a432c19ee2be13

aquadran aquadran at gmail.com
Thu Nov 12 07:18:47 UTC 2020


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
bd37cd3012 TINYGL: Make gl_resizeImage* pixel-format-independent
f8c72b5967 TINYGL: Move texture resampling from create time to render time
6f8303c2e3 MYST3: Use TGL_UNSIGNED_SHORT_5_6_5 texture format in gfx_tinygl
02294ee717 GRAPHICS: Use memcpy when copying to same-format-no-alpha destination


Commit: bd37cd301206f042222513cb02b0ef64bc91b5f1
    https://github.com/scummvm/scummvm/commit/bd37cd301206f042222513cb02b0ef64bc91b5f1
Author: Vincent Pelletier (plr.vincent at gmail.com)
Date: 2020-11-12T08:13:49+01:00

Commit Message:
TINYGL: Make gl_resizeImage* pixel-format-independent

Changed paths:
    graphics/tinygl/image_util.cpp
    graphics/tinygl/texture.cpp
    graphics/tinygl/zgl.h


diff --git a/graphics/tinygl/image_util.cpp b/graphics/tinygl/image_util.cpp
index 2bd9010ca4..7b20e30a4b 100644
--- a/graphics/tinygl/image_util.cpp
+++ b/graphics/tinygl/image_util.cpp
@@ -41,15 +41,16 @@ static inline int interpolate(int v00, int v01, int v10, int xf, int yf) {
 
 // TODO: more accurate resampling
 
-void gl_resizeImage(unsigned char *dest, int xsize_dest, int ysize_dest,
-					unsigned char *src, int xsize_src, int ysize_src) {
-	unsigned char *pix, *pix_src;
-	int point1_offset = 0, point2_offset = 0, point3_offset = 0;
+void gl_resizeImage(Graphics::PixelBuffer &dest, int xsize_dest, int ysize_dest,
+		    const Graphics::PixelBuffer &src, int xsize_src, int ysize_src) {
+	int point1_offset, point2_offset, point3_offset, dest_offset = 0;
+	int point_y_offset, point_offset;
 	float x1, y1, x1inc, y1inc;
-	int xi, yi, xf, yf;
-
-	pix = dest;
-	pix_src = src;
+	int xi, yi, xf, yf, curr_yf;
+	bool space_below, space_right;
+	uint8 r00, g00, b00, a00;
+	uint8 r01, g01, b01, a01;
+	uint8 r10, g10, b10, a10;
 
 	x1inc = (float)(xsize_src - 1) / (float)(xsize_dest - 1);
 	y1inc = (float)(ysize_src - 1) / (float)(ysize_dest - 1);
@@ -57,55 +58,49 @@ void gl_resizeImage(unsigned char *dest, int xsize_dest, int ysize_dest,
 	y1 = 0;
 	for (int y = 0; y < ysize_dest; y++) {
 		x1 = 0;
+		yi = (int)floorf(y1);
+		yf = (int)((y1 - yi) * INTERP_NORM);
+		point_y_offset = yi * xsize_src;
+		space_below = (yi + 1) < ysize_src;
 		for (int x = 0; x < xsize_dest; x++) {
-			xi = (int)x1;
-			yi = (int)y1;
-			xf = (int)((x1 - floor(x1)) * INTERP_NORM);
-			yf = (int)((y1 - floor(y1)) * INTERP_NORM);
-
+			xi = (int)floorf(x1);
+			xf = (int)((x1 - xi) * INTERP_NORM);
+			point1_offset = point_offset = point_y_offset + xi;
+			space_right = (xi + 1) < xsize_src;
 			if ((xf + yf) <= INTERP_NORM) {
-				for (int j = 0; j < 3; j++) {
-					point1_offset = (yi * xsize_src + xi) * 4 + j;
-					if ((xi + 1) < xsize_src)
-						point2_offset = (yi * xsize_src + xi + 1) * 4 + j;
-					else
-						point2_offset = point1_offset;
-					if ((yi + 1) < ysize_src)
-						point3_offset = ((yi + 1) * xsize_src + xi) * 4 + j;
-					else
-						point3_offset = point1_offset;
-					pix[j] = interpolate(pix_src[point1_offset], pix_src[point2_offset], pix_src[point3_offset], xf, yf);
-				}
-				pix[3] = pix_src[(yi * xsize_src + xi) * 4 + 3];
+				curr_yf = yf;
+				if (space_right)
+					point2_offset = point_offset + 1;
+				else
+					point2_offset = point_offset;
+				if (space_below)
+					point3_offset = point_offset + xsize_src;
+				else
+					point3_offset = point_offset;
 			} else {
 				xf = INTERP_NORM - xf;
-				yf = INTERP_NORM - yf;
-				for (int j = 0; j < 3; j++) {
-					pix[j] = interpolate(pix_src[point1_offset], pix_src[point2_offset], pix_src[point3_offset], xf, yf);
-					if ((xi + 1) < xsize_src) {
-						if ((yi + 1) < ysize_src)
-							point1_offset = ((yi + 1) * xsize_src + xi + 1) * 4 + j;
-						else
-							point1_offset = (yi * xsize_src + xi + 1) * 4 + j;
-					} else {
-						if ((yi + 1) < ysize_src)
-							point1_offset = ((yi + 1) * xsize_src + xi) * 4 + j;
-						else
-							point1_offset = (yi * xsize_src + xi) * 4 + j;
-					}
-					if ((yi + 1) < ysize_src)
-						point2_offset = ((yi + 1) * xsize_src + xi) * 4 + j;
-					else
-						point2_offset = (yi * xsize_src + xi) * 4 + j;
-					if ((xi + 1) < xsize_src)
-						point3_offset = (yi * xsize_src + xi + 1) * 4 + j;
-					else
-						point3_offset = (yi * xsize_src + xi) * 4 + j;
-					pix[j] = interpolate(pix_src[point1_offset], pix_src[point2_offset], pix_src[point3_offset], xf, yf);
-				}
-				pix[3] = pix_src[(yi * xsize_src + xi) * 4 + 3];
+				curr_yf = INTERP_NORM - yf;
+				if (space_right) {
+					point1_offset += 1;
+					point3_offset = point_offset + 1;
+				} else
+					point3_offset = point_offset;
+				if (space_below) {
+					point1_offset += xsize_src;
+					point2_offset = point_offset + xsize_src;
+				} else
+					point2_offset = point_offset;
 			}
-			pix += 4;
+			src.getARGBAt(point1_offset, r00, g00, b00, a00);
+			src.getARGBAt(point2_offset, r01, g01, b01, a01);
+			src.getARGBAt(point3_offset, r10, g10, b10, a10);
+			dest.setPixelAt(
+				dest_offset++,
+				interpolate(r00, r01, r10, xf, curr_yf),
+				interpolate(g00, g01, g10, xf, curr_yf),
+				interpolate(b00, b01, b10, xf, curr_yf),
+				interpolate(a00, a01, a10, xf, curr_yf)
+			);
 			x1 += x1inc;
 		}
 		y1 += y1inc;
@@ -115,32 +110,23 @@ void gl_resizeImage(unsigned char *dest, int xsize_dest, int ysize_dest,
 #define FRAC_BITS 16
 
 // resizing with no interlating nor nearest pixel
-void gl_resizeImageNoInterpolate(unsigned char *dest, int xsize_dest, int ysize_dest,
-								 unsigned char *src, int xsize_src, int ysize_src) {
-	unsigned char *pix, *pix_src, *pix1;
+void gl_resizeImageNoInterpolate(Graphics::PixelBuffer &dest, int xsize_dest, int ysize_dest,
+				 const Graphics::PixelBuffer &src, int xsize_src, int ysize_src) {
+	int dest_offset = 0;
 	int x1, y1, x1inc, y1inc;
-	int xi, yi;
-
-	pix = dest;
-	pix_src = src;
+	int yi;
+	uint8 r, g, b, a;
 
 	x1inc = (int)((float)((xsize_src) << FRAC_BITS) / (float)(xsize_dest));
 	y1inc = (int)((float)((ysize_src) << FRAC_BITS) / (float)(ysize_dest));
 
 	y1 = 0;
 	for (int y = 0; y < ysize_dest; y++) {
+		yi = (y1 >> FRAC_BITS) * xsize_src;
 		x1 = 0;
 		for (int x = 0; x < xsize_dest; x++) {
-			xi = x1 >> FRAC_BITS;
-			yi = y1 >> FRAC_BITS;
-			pix1 = pix_src + (yi * xsize_src + xi) * 4;
-
-			pix[0] = pix1[0];
-			pix[1] = pix1[1];
-			pix[2] = pix1[2];
-			pix[3] = pix1[3];
-
-			pix += 4;
+			src.getARGBAt(yi + (x1 >> FRAC_BITS), r, g, b, a);
+			dest.setPixelAt(dest_offset++, r, g, b, a);
 			x1 += x1inc;
 		}
 		y1 += y1inc;
diff --git a/graphics/tinygl/texture.cpp b/graphics/tinygl/texture.cpp
index 18fbbcc21c..dd3dee16c3 100644
--- a/graphics/tinygl/texture.cpp
+++ b/graphics/tinygl/texture.cpp
@@ -211,16 +211,10 @@ void glopTexImage2D(GLContext *c, GLParam *p) {
 	if (pixels != NULL) {
 		Graphics::PixelBuffer src(formatType2PixelFormat(format, type), pixels);
 		if (width != c->_textureSize || height != c->_textureSize) {
-			Graphics::PixelBuffer src_conv(pf, width * height, DisposeAfterUse::YES);
-			src_conv.copyBuffer(
-				0,
-				width * height,
-				src
-			);
 			// we use interpolation for better looking result
 			gl_resizeImage(
-				internal.getRawBuffer(), c->_textureSize, c->_textureSize,
-				src_conv.getRawBuffer(), width, height
+				internal, c->_textureSize, c->_textureSize,
+				src, width, height
 			);
 		} else {
 			internal.copyBuffer(
diff --git a/graphics/tinygl/zgl.h b/graphics/tinygl/zgl.h
index b19b14d5bf..0711a43386 100644
--- a/graphics/tinygl/zgl.h
+++ b/graphics/tinygl/zgl.h
@@ -423,10 +423,10 @@ void free_texture(GLContext *c, int h);
 void free_texture(GLContext *c, GLTexture *t);
 
 // image_util.c
-void gl_resizeImage(unsigned char *dest, int xsize_dest, int ysize_dest,
-					unsigned char *src, int xsize_src, int ysize_src);
-void gl_resizeImageNoInterpolate(unsigned char *dest, int xsize_dest, int ysize_dest,
-								 unsigned char *src, int xsize_src, int ysize_src);
+void gl_resizeImage(Graphics::PixelBuffer &dest, int xsize_dest, int ysize_dest,
+		    const Graphics::PixelBuffer &src, int xsize_src, int ysize_src);
+void gl_resizeImageNoInterpolate(Graphics::PixelBuffer &dest, int xsize_dest, int ysize_dest,
+				 const Graphics::PixelBuffer &src, int xsize_src, int ysize_src);
 
 void tglIssueDrawCall(Graphics::DrawCall *drawCall);
 


Commit: f8c72b5967f8fdfa6f2a15e7141b4f7bb94496a5
    https://github.com/scummvm/scummvm/commit/f8c72b5967f8fdfa6f2a15e7141b4f7bb94496a5
Author: Vincent Pelletier (plr.vincent at gmail.com)
Date: 2020-11-12T08:15:39+01:00

Commit Message:
TINYGL: Move texture resampling from create time to render time

Thanks to pixel repacking using cpu data cache, this has a low runtime
cost even for TGL_LINEAR.
Adds support for TGL_NEAREST.
Adds support for TGL_MIRRORED_REPEAT, TGL_CLAMP_TO_EDGE and TGL_REPEAT.
Also, add support for more texture clamping and resampling options.

Mipmaps are not supported, although their sampling modes will be
applied - but to the full-size texture instead of selected mipmap.

Note: Texture sampler is still chosen at texture creation time.

Changed paths:
  A graphics/tinygl/texelbuffer.cpp
  A graphics/tinygl/texelbuffer.h
    graphics/module.mk
    graphics/tinygl/clip.cpp
    graphics/tinygl/gl.h
    graphics/tinygl/texture.cpp
    graphics/tinygl/zbuffer.cpp
    graphics/tinygl/zbuffer.h
    graphics/tinygl/zdirtyrect.cpp
    graphics/tinygl/zdirtyrect.h
    graphics/tinygl/zgl.h
    graphics/tinygl/ztriangle.cpp


diff --git a/graphics/module.mk b/graphics/module.mk
index 8bcff4a94e..0c367008dc 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -71,6 +71,7 @@ MODULE_OBJS += \
 	tinygl/select.o \
 	tinygl/specbuf.o \
 	tinygl/texture.o \
+	tinygl/texelbuffer.o \
 	tinygl/vertex.o \
 	tinygl/zbuffer.o \
 	tinygl/zline.o \
diff --git a/graphics/tinygl/clip.cpp b/graphics/tinygl/clip.cpp
index 244210929d..b6b6f3469e 100644
--- a/graphics/tinygl/clip.cpp
+++ b/graphics/tinygl/clip.cpp
@@ -411,7 +411,7 @@ void gl_draw_triangle_fill(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p
 #ifdef TINYGL_PROFILE
 		count_triangles_textured++;
 #endif
-		c->fb->setTexture(c->current_texture->images[0].pixmap);
+		c->fb->setTexture(c->current_texture->images[0].pixmap, c->texture_wrap_s, c->texture_wrap_t);
 		if (c->current_shade_model == TGL_SMOOTH) {
 			c->fb->fillTriangleTextureMappingPerspectiveSmooth(&p0->zp, &p1->zp, &p2->zp);
 		} else {
diff --git a/graphics/tinygl/gl.h b/graphics/tinygl/gl.h
index c7eb3aca0f..1a4a410d28 100644
--- a/graphics/tinygl/gl.h
+++ b/graphics/tinygl/gl.h
@@ -537,6 +537,8 @@ enum {
 	TGL_NEAREST                     = 0x2600,
 	TGL_REPEAT                      = 0x2901,
 	TGL_CLAMP                       = 0x2900,
+	TGL_CLAMP_TO_EDGE		= 0x812F,
+	TGL_MIRRORED_REPEAT		= 0x8370,
 	TGL_S                           = 0x2000,
 	TGL_T                           = 0x2001,
 	TGL_R                           = 0x2002,
diff --git a/graphics/tinygl/texelbuffer.cpp b/graphics/tinygl/texelbuffer.cpp
new file mode 100644
index 0000000000..d14bcf9fe0
--- /dev/null
+++ b/graphics/tinygl/texelbuffer.cpp
@@ -0,0 +1,225 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "graphics/tinygl/gl.h"
+#include "graphics/tinygl/zgl.h"
+#include "graphics/tinygl/zbuffer.h"
+#include "graphics/tinygl/texelbuffer.h"
+
+namespace Graphics {
+
+#define ZB_POINT_ST_UNIT (1 << ZB_POINT_ST_FRAC_BITS)
+#define ZB_POINT_ST_FRAC_MASK (ZB_POINT_ST_UNIT - 1)
+
+TexelBuffer::TexelBuffer(unsigned int width, unsigned int height, unsigned int textureSize) {
+	assert(width);
+	assert(height);
+	assert(textureSize);
+
+	_width = width;
+	_height = height;
+	_fracTextureUnit = textureSize << ZB_POINT_ST_FRAC_BITS;
+	_fracTextureMask = _fracTextureUnit - 1;
+	_widthRatio = (float) width / textureSize;
+	_heightRatio = (float) height / textureSize;
+}
+
+static inline unsigned int wrap(unsigned int wrap_mode, int coord, unsigned int _fracTextureUnit, unsigned int _fracTextureMask) {
+	switch (wrap_mode) {
+	case TGL_MIRRORED_REPEAT:
+		if (coord & _fracTextureUnit)
+			return _fracTextureMask - (coord & _fracTextureMask);
+		return coord & _fracTextureMask;
+	case TGL_CLAMP_TO_EDGE:
+		if (coord < 0)
+			return 0;
+		if ((unsigned int) coord > _fracTextureMask)
+			return _fracTextureMask;
+		return coord;
+	default:
+		// Fall through
+	case TGL_REPEAT:
+		return coord & _fracTextureMask;
+	}
+}
+
+void TexelBuffer::getARGBAt(
+	unsigned int wrap_s, unsigned int wrap_t,
+	int s, int t,
+	uint8 &a, uint8 &r, uint8 &g, uint8 &b
+) const {
+	unsigned int x, y;
+	x = wrap(wrap_s, s, _fracTextureUnit, _fracTextureMask) * _widthRatio;
+	y = wrap(wrap_t, t, _fracTextureUnit, _fracTextureMask) * _heightRatio;
+	getARGBAt(
+		(x >> ZB_POINT_ST_FRAC_BITS) + (y >> ZB_POINT_ST_FRAC_BITS) * _width,
+		x & ZB_POINT_ST_FRAC_MASK, y & ZB_POINT_ST_FRAC_MASK,
+		a, r, g, b
+	);
+}
+
+// Nearest: store texture in original size.
+NearestTexelBuffer::NearestTexelBuffer(const PixelBuffer &buf, unsigned int width, unsigned int height, unsigned int textureSize) : TexelBuffer(width, height, textureSize) {
+	unsigned int pixel_count = _width * _height;
+	_buf = PixelBuffer(buf.getFormat(), pixel_count, DisposeAfterUse::NO);
+	_buf.copyBuffer(0, pixel_count, buf);
+}
+
+NearestTexelBuffer::~NearestTexelBuffer() {
+	_buf.free();
+}
+
+void NearestTexelBuffer::getARGBAt(
+	unsigned int pixel,
+	unsigned int, unsigned int,
+	uint8 &a, uint8 &r, uint8 &g, uint8 &b
+) const {
+	_buf.getARGBAt(pixel, a, r, g, b);
+}
+
+// Bilinear: each texture coordinates corresponds to the 4 original image
+// pixels linear interpolation has to work on, so that they are near each
+// other in CPU data cache, and a single actual memory fetch happens. This
+// allows applying linear filtering at render time at a very low performance
+// cost. As we expect to work on small-ish textures (512*512 ?) the 4x memory
+// usage increase should be negligible.
+#define A_OFFSET (0 * 4)
+#define R_OFFSET (1 * 4)
+#define G_OFFSET (2 * 4)
+#define B_OFFSET (3 * 4)
+#define P00_OFFSET 0
+#define P01_OFFSET 1
+#define P10_OFFSET 2
+#define P11_OFFSET 3
+#define PIXEL_PER_TEXEL_SHIFT 2
+
+BilinearTexelBuffer::BilinearTexelBuffer(const PixelBuffer &buf, unsigned int width, unsigned int height, unsigned int textureSize) : TexelBuffer(width, height, textureSize) {
+	unsigned int pixel00_offset = 0, pixel11_offset, pixel01_offset, pixel10_offset;
+	uint8 *texel8;
+	uint32 *texel32;
+
+	texel32 = _texels = new uint32[_width * _height << PIXEL_PER_TEXEL_SHIFT];
+	for (unsigned int y = 0; y < _height; y++) {
+		for (unsigned int x = 0; x < _width; x++) {
+			texel8 = (uint8 *)texel32;
+			pixel11_offset = pixel00_offset + _width + 1;
+			buf.getARGBAt(
+				pixel00_offset,
+				*(texel8 + P00_OFFSET + A_OFFSET),
+				*(texel8 + P00_OFFSET + R_OFFSET),
+				*(texel8 + P00_OFFSET + G_OFFSET),
+				*(texel8 + P00_OFFSET + B_OFFSET)
+			);
+			if ((x + 1) == _width) {
+				pixel11_offset -= 1;
+				pixel01_offset = pixel00_offset;
+			} else
+				pixel01_offset = pixel00_offset + 1;
+			buf.getARGBAt(
+				pixel01_offset,
+				*(texel8 + P01_OFFSET + A_OFFSET),
+				*(texel8 + P01_OFFSET + R_OFFSET),
+				*(texel8 + P01_OFFSET + G_OFFSET),
+				*(texel8 + P01_OFFSET + B_OFFSET)
+			);
+			if ((y + 1) == _height) {
+				pixel11_offset -= _width;
+				pixel10_offset = pixel00_offset;
+			} else
+				pixel10_offset = pixel00_offset + _width;
+			buf.getARGBAt(
+				pixel10_offset,
+				*(texel8 + P10_OFFSET + A_OFFSET),
+				*(texel8 + P10_OFFSET + R_OFFSET),
+				*(texel8 + P10_OFFSET + G_OFFSET),
+				*(texel8 + P10_OFFSET + B_OFFSET)
+			);
+			buf.getARGBAt(
+				pixel11_offset,
+				*(texel8 + P11_OFFSET + A_OFFSET),
+				*(texel8 + P11_OFFSET + R_OFFSET),
+				*(texel8 + P11_OFFSET + G_OFFSET),
+				*(texel8 + P11_OFFSET + B_OFFSET)
+			);
+			texel32 += 1 << PIXEL_PER_TEXEL_SHIFT;
+			pixel00_offset++;
+		}
+	}
+}
+
+BilinearTexelBuffer::~BilinearTexelBuffer() {
+	delete[] _texels;
+}
+
+static inline int interpolate(int v00, int v01, int v10, int xf, int yf) {
+	return v00 + (((v01 - v00) * xf + (v10 - v00) * yf) >> ZB_POINT_ST_FRAC_BITS);
+}
+
+void BilinearTexelBuffer::getARGBAt(
+	unsigned int pixel,
+	unsigned int ds, unsigned int dt,
+	uint8 &a, uint8 &r, uint8 &g, uint8 &b
+) const {
+	unsigned int p00_offset, p01_offset, p10_offset;
+	uint8 *texel = (uint8 *)(_texels + (pixel << PIXEL_PER_TEXEL_SHIFT));
+	if ((ds + dt) > ZB_POINT_ST_UNIT) {
+		p00_offset = P11_OFFSET;
+		p10_offset = P01_OFFSET;
+		p01_offset = P10_OFFSET;
+		ds = ZB_POINT_ST_UNIT - ds;
+		dt = ZB_POINT_ST_UNIT - dt;
+	} else {
+		p00_offset = P00_OFFSET;
+		p10_offset = P10_OFFSET;
+		p01_offset = P01_OFFSET;
+	}
+	a = interpolate(
+		*(texel + p00_offset + A_OFFSET),
+		*(texel + p01_offset + A_OFFSET),
+		*(texel + p10_offset + A_OFFSET),
+		ds,
+		dt
+	);
+	r = interpolate(
+		*(texel + p00_offset + R_OFFSET),
+		*(texel + p01_offset + R_OFFSET),
+		*(texel + p10_offset + R_OFFSET),
+		ds,
+		dt
+	);
+	g = interpolate(
+		*(texel + p00_offset + G_OFFSET),
+		*(texel + p01_offset + G_OFFSET),
+		*(texel + p10_offset + G_OFFSET),
+		ds,
+		dt
+	);
+	b = interpolate(
+		*(texel + p00_offset + B_OFFSET),
+		*(texel + p01_offset + B_OFFSET),
+		*(texel + p10_offset + B_OFFSET),
+		ds,
+		dt
+	);
+}
+
+}
diff --git a/graphics/tinygl/texelbuffer.h b/graphics/tinygl/texelbuffer.h
new file mode 100644
index 0000000000..651964eee3
--- /dev/null
+++ b/graphics/tinygl/texelbuffer.h
@@ -0,0 +1,85 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GRAPHICS_TEXELBUFFER_H
+#define GRAPHICS_TEXELBUFFER_H
+
+#include "graphics/pixelbuffer.h"
+
+namespace Graphics {
+
+class TexelBuffer {
+public:
+	TexelBuffer(unsigned int width, unsigned int height, unsigned int textureSize);
+	virtual ~TexelBuffer() {};
+
+	void getARGBAt(
+		unsigned int wrap_s, unsigned int wrap_t,
+		int s, int t,
+		uint8 &a, uint8 &r, uint8 &g, uint8 &b
+	) const;
+
+protected:
+	virtual void getARGBAt(
+		unsigned int pixel,
+		unsigned int ds, unsigned int dt,
+		uint8 &a, uint8 &r, uint8 &g, uint8 &b
+	) const = 0;
+	unsigned int _width, _height, _fracTextureUnit, _fracTextureMask;
+	float _widthRatio, _heightRatio;
+};
+
+class NearestTexelBuffer : public TexelBuffer {
+public:
+	NearestTexelBuffer(const PixelBuffer &buf, unsigned int width, unsigned int height, unsigned int textureSize);
+	~NearestTexelBuffer();
+
+protected:
+	void getARGBAt(
+		unsigned int pixel,
+		unsigned int, unsigned int,
+		uint8 &a, uint8 &r, uint8 &g, uint8 &b
+	) const override;
+
+private:
+	PixelBuffer _buf;
+};
+
+class BilinearTexelBuffer : public TexelBuffer {
+public:
+	BilinearTexelBuffer(const PixelBuffer &buf, unsigned int width, unsigned int height, unsigned int textureSize);
+	~BilinearTexelBuffer();
+
+protected:
+	void getARGBAt(
+		unsigned int pixel,
+		unsigned int ds, unsigned int dt,
+		uint8 &a, uint8 &r, uint8 &g, uint8 &b
+	) const override;
+
+private:
+	uint32 *_texels;
+};
+
+}
+
+#endif
diff --git a/graphics/tinygl/texture.cpp b/graphics/tinygl/texture.cpp
index dd3dee16c3..d5b04d1a0d 100644
--- a/graphics/tinygl/texture.cpp
+++ b/graphics/tinygl/texture.cpp
@@ -106,8 +106,10 @@ void free_texture(GLContext *c, GLTexture *t) {
 
 	for (int i = 0; i < MAX_TEXTURE_LEVELS; i++) {
 		im = &t->images[i];
-		if (im->pixmap)
-			im->pixmap.free();
+		if (im->pixmap) {
+			delete im->pixmap;
+			im->pixmap = nullptr;
+		}
 	}
 
 	gl_free(t);
@@ -137,6 +139,8 @@ void glInitTextures(GLContext *c) {
 	// textures
 	c->texture_2d_enabled = 0;
 	c->current_texture = find_texture(c, 0);
+	c->texture_mag_filter = TGL_LINEAR;
+	c->texture_min_filter = TGL_NEAREST_MIPMAP_LINEAR;
 }
 
 void glopBindTexture(GLContext *c, GLParam *p) {
@@ -182,56 +186,40 @@ void glopTexImage2D(GLContext *c, GLParam *p) {
 	if (border != 0)
 		error("tglTexImage2D: invalid border");
 
-	Graphics::PixelFormat pf;
-	switch (format) {
-		case TGL_RGBA:
-		case TGL_RGB:
-#if defined(SCUMM_BIG_ENDIAN)
-			pf = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
-#elif defined(SCUMM_LITTLE_ENDIAN)
-			pf = Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
-#endif
-			break;
-		case TGL_BGRA:
-		case TGL_BGR:
-#if defined(SCUMM_BIG_ENDIAN)
-			pf = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 0, 8, 16);
-#elif defined(SCUMM_LITTLE_ENDIAN)
-			pf = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
-#endif
-			break;
-		default:
-			break;
+	c->current_texture->versionNumber++;
+	im = &c->current_texture->images[level];
+	im->xsize = c->_textureSize;
+	im->ysize = c->_textureSize;
+	if (im->pixmap) {
+		delete im->pixmap;
+		im->pixmap = nullptr;
 	}
-	Graphics::PixelBuffer internal(
-		pf,
-		c->_textureSize * c->_textureSize,
-		DisposeAfterUse::NO
-	);
 	if (pixels != NULL) {
+		unsigned int filter;
 		Graphics::PixelBuffer src(formatType2PixelFormat(format, type), pixels);
-		if (width != c->_textureSize || height != c->_textureSize) {
-			// we use interpolation for better looking result
-			gl_resizeImage(
-				internal, c->_textureSize, c->_textureSize,
-				src, width, height
+		if (width > c->_textureSize || height > c->_textureSize)
+			filter = c->texture_mag_filter;
+		else
+			filter = c->texture_min_filter;
+		switch (filter) {
+		case TGL_LINEAR_MIPMAP_NEAREST:
+		case TGL_LINEAR_MIPMAP_LINEAR:
+		case TGL_LINEAR:
+			im->pixmap = new Graphics::BilinearTexelBuffer(
+				src,
+				width, height,
+				c->_textureSize
 			);
-		} else {
-			internal.copyBuffer(
-				0,
-				c->_textureSize * c->_textureSize,
-				src
+			break;
+		default:
+			im->pixmap = new Graphics::NearestTexelBuffer(
+				src,
+				width, height,
+				c->_textureSize
 			);
+			break;
 		}
 	}
-
-	c->current_texture->versionNumber++;
-	im = &c->current_texture->images[level];
-	im->xsize = c->_textureSize;
-	im->ysize = c->_textureSize;
-	if (im->pixmap)
-		im->pixmap.free();
-	im->pixmap = internal;
 }
 
 // TODO: not all tests are done
@@ -253,7 +241,7 @@ error:
 }
 
 // TODO: not all tests are done
-void glopTexParameter(GLContext *, GLParam *p) {
+void glopTexParameter(GLContext *c, GLParam *p) {
 	int target = p[1].i;
 	int pname = p[2].i;
 	int param = p[3].i;
@@ -265,9 +253,34 @@ error:
 
 	switch (pname) {
 	case TGL_TEXTURE_WRAP_S:
+		c->texture_wrap_s = param;
+		break;
 	case TGL_TEXTURE_WRAP_T:
-		if (param != TGL_REPEAT)
+		c->texture_wrap_t = param;
+		break;
+	case TGL_TEXTURE_MAG_FILTER:
+		switch (param) {
+		case TGL_NEAREST:
+		case TGL_LINEAR:
+			c->texture_mag_filter = param;
+			break;
+		default:
 			goto error;
+		}
+		break;
+	case TGL_TEXTURE_MIN_FILTER:
+		switch (param) {
+		case TGL_LINEAR_MIPMAP_NEAREST:
+		case TGL_LINEAR_MIPMAP_LINEAR:
+		case TGL_NEAREST_MIPMAP_NEAREST:
+		case TGL_NEAREST_MIPMAP_LINEAR:
+		case TGL_NEAREST:
+		case TGL_LINEAR:
+			c->texture_min_filter = param;
+			break;
+		default:
+			goto error;
+		}
 		break;
 	default:
 		;
diff --git a/graphics/tinygl/zbuffer.cpp b/graphics/tinygl/zbuffer.cpp
index 1f689af414..b925eaafc1 100644
--- a/graphics/tinygl/zbuffer.cpp
+++ b/graphics/tinygl/zbuffer.cpp
@@ -325,8 +325,10 @@ void FrameBuffer::clearOffscreenBuffer(Buffer *buf) {
 	buf->used = false;
 }
 
-void FrameBuffer::setTexture(const Graphics::PixelBuffer &texture) {
+void FrameBuffer::setTexture(const Graphics::TexelBuffer *texture, unsigned int wraps, unsigned int wrapt) {
 	current_texture = texture;
+	wrapS = wraps;
+	wrapT = wrapt;
 }
 
 } // end of namespace TinyGL
diff --git a/graphics/tinygl/zbuffer.h b/graphics/tinygl/zbuffer.h
index 8965cc0975..5fdfbe5ec4 100644
--- a/graphics/tinygl/zbuffer.h
+++ b/graphics/tinygl/zbuffer.h
@@ -30,6 +30,7 @@
 #define GRAPHICS_TINYGL_ZBUFFER_H_
 
 #include "graphics/pixelbuffer.h"
+#include "graphics/tinygl/texelbuffer.h"
 #include "graphics/tinygl/gl.h"
 #include "common/rect.h"
 
@@ -424,7 +425,7 @@ struct FrameBuffer {
 	void blitOffscreenBuffer(Buffer *buffer);
 	void selectOffscreenBuffer(Buffer *buffer);
 	void clearOffscreenBuffer(Buffer *buffer);
-	void setTexture(const Graphics::PixelBuffer &texture);
+	void setTexture(const Graphics::TexelBuffer *texture, unsigned int wraps, unsigned int wrapt);
 
 	template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, int kDrawLogic, bool kDepthWrite, bool enableAlphaTest, bool kEnableScissor, bool enableBlending>
 	void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
@@ -482,9 +483,10 @@ struct FrameBuffer {
 
 	unsigned char *dctable;
 	int *ctable;
-	Graphics::PixelBuffer current_texture;
+	const Graphics::TexelBuffer *current_texture;
 	int _textureSize;
 	int _textureSizeMask;
+	unsigned int wrapS, wrapT;
 
 	FORCEINLINE bool isBlendingEnabled() const { return _blendingEnabled; }
 	FORCEINLINE void getBlendingFactors(int &sourceFactor, int &destinationFactor) const { sourceFactor = _sourceBlendingFactor; destinationFactor = _destinationBlendingFactor; }
diff --git a/graphics/tinygl/zdirtyrect.cpp b/graphics/tinygl/zdirtyrect.cpp
index 4a3275e310..18fc9e253a 100644
--- a/graphics/tinygl/zdirtyrect.cpp
+++ b/graphics/tinygl/zdirtyrect.cpp
@@ -453,6 +453,8 @@ RasterizationDrawCall::RasterizationState RasterizationDrawCall::captureState()
 	state.shadowMode = c->shadow_mode;
 	state.texture2DEnabled = c->texture_2d_enabled;
 	state.texture = c->current_texture;
+	state.wrapS = c->texture_wrap_s;
+	state.wrapT = c->texture_wrap_t;
 	state.shadowMaskBuf = c->fb->shadow_mask_buf;
 	state.depthFunction = c->fb->getDepthFunc();
 	state.depthWrite = c->fb->getDepthWrite();
@@ -489,6 +491,8 @@ void RasterizationDrawCall::applyState(const RasterizationDrawCall::Rasterizatio
 	c->shadow_mode = state.shadowMode;
 	c->texture_2d_enabled = state.texture2DEnabled;
 	c->current_texture = state.texture; 
+	c->texture_wrap_s = state.wrapS;
+	c->texture_wrap_t = state.wrapT;
 	c->fb->shadow_mask_buf = state.shadowMaskBuf;
 
 	memcpy(c->viewport.scale._v, state.viewportScaling, sizeof(c->viewport.scale._v));
diff --git a/graphics/tinygl/zdirtyrect.h b/graphics/tinygl/zdirtyrect.h
index f1a3396ab8..f579294ad3 100644
--- a/graphics/tinygl/zdirtyrect.h
+++ b/graphics/tinygl/zdirtyrect.h
@@ -132,6 +132,7 @@ private:
 		bool alphaTest;
 		int alphaFunc, alphaRefValue;
 		TinyGL::GLTexture *texture;
+		unsigned int wrapS, wrapT;
 		unsigned char *shadowMaskBuf;
 
 		bool operator==(const RasterizationState &other) const;
diff --git a/graphics/tinygl/zgl.h b/graphics/tinygl/zgl.h
index 0711a43386..5cd8904c9f 100644
--- a/graphics/tinygl/zgl.h
+++ b/graphics/tinygl/zgl.h
@@ -40,6 +40,7 @@
 #include "graphics/tinygl/zmath.h"
 #include "graphics/tinygl/zblit.h"
 #include "graphics/tinygl/zdirtyrect.h"
+#include "graphics/tinygl/texelbuffer.h"
 
 namespace TinyGL {
 
@@ -174,7 +175,7 @@ struct GLVertex {
 };
 
 struct GLImage {
-	Graphics::PixelBuffer pixmap;
+	Graphics::TexelBuffer *pixmap;
 	int xsize, ysize;
 };
 
@@ -279,6 +280,10 @@ struct GLContext {
 	// textures
 	GLTexture *current_texture;
 	int texture_2d_enabled;
+	int texture_mag_filter;
+	int texture_min_filter;
+	unsigned int texture_wrap_s;
+	unsigned int texture_wrap_t;
 
 	// shared state
 	GLSharedState shared_state;
diff --git a/graphics/tinygl/ztriangle.cpp b/graphics/tinygl/ztriangle.cpp
index d16e92ad4d..620f3d2510 100644
--- a/graphics/tinygl/ztriangle.cpp
+++ b/graphics/tinygl/ztriangle.cpp
@@ -27,6 +27,7 @@
  */
 
 #include "common/endian.h"
+#include "graphics/tinygl/texelbuffer.h"
 #include "graphics/tinygl/zbuffer.h"
 #include "graphics/tinygl/zgl.h"
 
@@ -77,20 +78,12 @@ FORCEINLINE static void putPixelShadow(FrameBuffer *buffer, int buf, unsigned in
 
 template <bool kDepthWrite, bool kLightsMode, bool kSmoothMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending>
 FORCEINLINE static void putPixelTextureMappingPerspective(FrameBuffer *buffer, int buf,
-                        Graphics::PixelFormat &textureFormat, Graphics::PixelBuffer &texture, unsigned int *pz, int _a,
-                        int x, int y, unsigned int &z, unsigned int &t, unsigned int &s, unsigned int &r, unsigned int &g, unsigned int &b, unsigned int &a,
+                        const Graphics::TexelBuffer *texture, unsigned int wrap_s, unsigned int wrap_t, unsigned int *pz, int _a,
+                        int x, int y, unsigned int &z, int &t, int &s, unsigned int &r, unsigned int &g, unsigned int &b, unsigned int &a,
                         int &dzdx, int &dsdx, int &dtdx, int &drdx, int &dgdx, int &dbdx, unsigned int dadx) {
 	if ((!kEnableScissor || !buffer->scissorPixel(x + _a, y)) && buffer->compareDepth(z, pz[_a])) {
-		unsigned sss = (s & buffer->_textureSizeMask) >> ZB_POINT_ST_FRAC_BITS;
-		unsigned ttt = (t & buffer->_textureSizeMask) >> ZB_POINT_ST_FRAC_BITS;
-		int pixel = ttt * buffer->_textureSize + sss;
 		uint8 c_a, c_r, c_g, c_b;
-		uint32 *textureBuffer = (uint32 *)texture.getRawBuffer(pixel);
-		uint32 col = *textureBuffer;
-		c_a = (col >> textureFormat.aShift) & 0xFF;
-		c_r = (col >> textureFormat.rShift) & 0xFF;
-		c_g = (col >> textureFormat.gShift) & 0xFF;
-		c_b = (col >> textureFormat.bShift) & 0xFF;
+		texture->getARGBAt(wrap_s, wrap_t, s, t, c_a, c_r, c_g, c_b);
 		if (kLightsMode) {
 			unsigned int l_a = (a >> (ZB_POINT_ALPHA_BITS - 8));
 			unsigned int l_r = (r >> (ZB_POINT_RED_BITS - 8));
@@ -116,8 +109,7 @@ FORCEINLINE static void putPixelTextureMappingPerspective(FrameBuffer *buffer, i
 
 template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, int kDrawLogic, bool kDepthWrite, bool kAlphaTestEnabled, bool kEnableScissor, bool kBlendingEnabled>
 void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
-	Graphics::PixelBuffer texture;
-	Graphics::PixelFormat textureFormat;
+	const Graphics::TexelBuffer *texture;
 	float fdzdx = 0, fndzdx = 0, ndszdx = 0, ndtzdx = 0;
 
 	ZBufferPoint *tp, *pr1 = 0, *pr2 = 0, *l1 = 0, *l2 = 0;
@@ -270,8 +262,6 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint
 
 	if ((kInterpST || kInterpSTZ) && (kDrawLogic == DRAW_FLAT || kDrawLogic == DRAW_SMOOTH)) {
 		texture = current_texture;
-		textureFormat = texture.getFormat();
-		assert(textureFormat.bytesPerPixel == 4);
 		fdzdx = (float)dzdx;
 		fndzdx = NB_INTERP * fdzdx;
 		ndszdx = NB_INTERP * dszdx;
@@ -514,7 +504,8 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint
 					}
 				} else if (kInterpST || kInterpSTZ) {
 					unsigned int *pz;
-					unsigned int s, t, z, r, g, b, a;
+					int s, t;
+					unsigned int z, r, g, b, a;
 					int n;
 					float sz, tz, fz, zinv;
 					int dsdx, dtdx;
@@ -546,7 +537,7 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint
 							zinv = (float)(1.0 / fz);
 						}
 						for (int _a = 0; _a < NB_INTERP; _a++) {
-							putPixelTextureMappingPerspective<kDepthWrite, kInterpRGB, kDrawLogic == DRAW_SMOOTH, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, textureFormat, texture,
+							putPixelTextureMappingPerspective<kDepthWrite, kInterpRGB, kDrawLogic == DRAW_SMOOTH, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, texture, wrapS, wrapT,
 							                           pz, _a, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx);
 						}
 						pz += NB_INTERP;
@@ -568,7 +559,7 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint
 					}
 
 					while (n >= 0) {
-						putPixelTextureMappingPerspective<kDepthWrite, kInterpRGB, kDrawLogic == DRAW_SMOOTH, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, textureFormat, texture,
+						putPixelTextureMappingPerspective<kDepthWrite, kInterpRGB, kDrawLogic == DRAW_SMOOTH, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, texture, wrapS, wrapT,
 						                           pz, 0, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx);
 						pz += 1;
 						buf += 1;


Commit: 6f8303c2e32b0a3106229fa3c887833b34c02d5c
    https://github.com/scummvm/scummvm/commit/6f8303c2e32b0a3106229fa3c887833b34c02d5c
Author: Vincent Pelletier (plr.vincent at gmail.com)
Date: 2020-11-12T08:16:40+01:00

Commit Message:
MYST3: Use TGL_UNSIGNED_SHORT_5_6_5 texture format in gfx_tinygl

It is now supported by TinyGL.

Changed paths:
    engines/myst3/gfx_tinygl_texture.cpp


diff --git a/engines/myst3/gfx_tinygl_texture.cpp b/engines/myst3/gfx_tinygl_texture.cpp
index 6b8aa139c1..4a78730e9b 100644
--- a/engines/myst3/gfx_tinygl_texture.cpp
+++ b/engines/myst3/gfx_tinygl_texture.cpp
@@ -35,7 +35,7 @@ TinyGLTexture::TinyGLTexture(const Graphics::Surface *surface) {
 		sourceFormat = TGL_UNSIGNED_BYTE;
 	} else if (format.bytesPerPixel == 2) {
 		internalFormat = TGL_RGB;
-		sourceFormat = TGL_UNSIGNED_BYTE; // UNSIGNED_SHORT_5_6_5 not provided
+		sourceFormat = TGL_UNSIGNED_SHORT_5_6_5;
 	} else
 		error("Unknown pixel format");
 


Commit: 02294ee7175ac3e2b400569508a432c19ee2be13
    https://github.com/scummvm/scummvm/commit/02294ee7175ac3e2b400569508a432c19ee2be13
Author: Vincent Pelletier (plr.vincent at gmail.com)
Date: 2020-11-12T08:16:52+01:00

Commit Message:
GRAPHICS: Use memcpy when copying to same-format-no-alpha destination

Accelerates when source format is compatible with destination except for
alpha channel bit-loss. Ex:
  from: 32bits A << 24 | R << 16 | G << 8 | B
  to:   32bits           R << 16 | G << 8 | B

Changed paths:
    graphics/pixelbuffer.cpp


diff --git a/graphics/pixelbuffer.cpp b/graphics/pixelbuffer.cpp
index e762b94215..306cf14cbe 100644
--- a/graphics/pixelbuffer.cpp
+++ b/graphics/pixelbuffer.cpp
@@ -87,7 +87,17 @@ void PixelBuffer::clear(int length) {
 }
 
 void PixelBuffer::copyBuffer(int thisFrom, int otherFrom, int length, const PixelBuffer &buf) {
-	if (buf._format == _format) {
+	if (buf._format.bytesPerPixel == _format.bytesPerPixel &&
+	    buf._format.rShift == _format.rShift &&
+	    buf._format.gShift == _format.gShift &&
+	    buf._format.bShift == _format.bShift &&
+	    buf._format.rLoss == _format.rLoss &&
+	    buf._format.gLoss == _format.gLoss &&
+	    buf._format.bLoss == _format.bLoss && (
+		_format.aLoss = 8 ||
+		buf._format.aLoss == _format.aLoss
+	    )
+	) {
 		memcpy(_buffer + thisFrom * _format.bytesPerPixel, buf._buffer + otherFrom * _format.bytesPerPixel, length * _format.bytesPerPixel);
 	} else {
 		uint8 r, g, b, a;




More information about the Scummvm-git-logs mailing list