瀏覽代碼

better outline matching H3

Laserlicht 3 月之前
父節點
當前提交
e43df04ae1
共有 2 個文件被更改,包括 41 次插入43 次删除
  1. 1 1
      client/renderSDL/RenderHandler.cpp
  2. 40 42
      client/renderSDL/SDL_Extensions.cpp

+ 1 - 1
client/renderSDL/RenderHandler.cpp

@@ -324,7 +324,7 @@ std::shared_ptr<SDLImageShared> RenderHandler::loadScaledImage(const ImageLocato
 		if(isShadow && generateShadow)
 			img = img->drawShadow((*locator.generateShadow) == SharedImageLocator::ShadowMode::SHADOW_SHEAR);
 		if(isOverlay && generateOverlay && (*locator.generateOverlay) == SharedImageLocator::OverlayMode::OVERLAY_OUTLINE)
-			img = img->drawOutline(Colors::WHITE, getScalingFactor());
+			img = img->drawOutline(Colors::WHITE, 1);
 	}
 
 	return img;

+ 40 - 42
client/renderSDL/SDL_Extensions.cpp

@@ -686,70 +686,68 @@ void CSDL_Ext::getClipRect(SDL_Surface * src, Rect & other)
 	other = CSDL_Ext::fromSDL(rect);
 }
 
-SDL_Surface * CSDL_Ext::drawOutline(SDL_Surface * source, const SDL_Color & color, int thickness)
+SDL_Surface* CSDL_Ext::drawOutline(SDL_Surface* source, const SDL_Color& color, int thickness)
 {
-	// ensure format
-	SDL_Surface *sourceSurface = SDL_ConvertSurfaceFormat(source, SDL_PIXELFORMAT_ARGB8888, 0);
-	SDL_Surface *destSurface = newSurface(Point(source->w, source->h));
+	if(thickness < 1)
+		return nullptr;
 
-	// Lock surfaces for direct pixel access
-	if (SDL_MUSTLOCK(sourceSurface)) SDL_LockSurface(sourceSurface);
-	if (SDL_MUSTLOCK(destSurface)) SDL_LockSurface(destSurface);
+	SDL_Surface* sourceSurface = SDL_ConvertSurfaceFormat(source, SDL_PIXELFORMAT_ARGB8888, 0);
+	SDL_Surface* destSurface = newSurface(Point(source->w, source->h));
+
+	if(SDL_MUSTLOCK(sourceSurface)) SDL_LockSurface(sourceSurface);
+	if(SDL_MUSTLOCK(destSurface)) SDL_LockSurface(destSurface);
 
 	int width = sourceSurface->w;
 	int height = sourceSurface->h;
 
-	// Iterate through the pixels of the image
-	for (int y = 0; y < height; y++)
+	// Helper lambda to get alpha
+	auto getAlpha = [&](int x, int y) -> Uint8 {
+		if (x < 0 || x >= width || y < 0 || y >= height)
+			return 0;
+		Uint32 pixel = *((Uint32*)sourceSurface->pixels + y * width + x);
+		Uint8 r, g, b, a;
+		SDL_GetRGBA(pixel, sourceSurface->format, &r, &g, &b, &a);
+		return a;
+	};
+
+	// Go through all transparent pixels and check if they border an opaque region
+	for(int y = 0; y < height; y++)
 	{
-		for (int x = 0; x < width; x++)
+		for(int x = 0; x < width; x++)
 		{
-			Uint8 maxPixel = 0;
-			Uint8 minPixel = 255;
-			int halfThickness = (thickness + 1) / 2;
+			if(getAlpha(x, y) != 0)
+				continue; // Skip opaque pixels
+
+			bool isOutline = false;
 
-			// Loop over the neighborhood around (x, y)
-			for(int offsetY = -halfThickness; offsetY <= halfThickness; offsetY++)
+			for(int dy = -thickness; dy <= thickness && !isOutline; ++dy)
 			{
-				for(int offsetX = -halfThickness; offsetX <= halfThickness; offsetX++)
+				for(int dx = -thickness; dx <= thickness; ++dx)
 				{
-					// Circle instead of rectangle
-					if(offsetX * offsetX + offsetY * offsetY > halfThickness * halfThickness)
+					// circular neighborhood
+					if(dx * dx + dy * dy > thickness * thickness)
 						continue;
 
-					int neighborX = x + offsetX;
-					int neighborY = y + offsetY;
-
-					// Check image bounds
-					if(neighborX >= 0 && neighborX < destSurface->w && neighborY >= 0 && neighborY < destSurface->h)
+					if(getAlpha(x + dx, y + dy) > 0)
 					{
-						// Get the pixel at the neighbor position
-						Uint32 pixel = *((Uint32*)sourceSurface->pixels + neighborY * width + neighborX);
-						Uint8 r;
-						Uint8 g;
-						Uint8 b;
-						Uint8 a;
-						SDL_GetRGBA(pixel, sourceSurface->format, &r, &g, &b, &a);
-						
-						// Compare the pixel alpha value to find the maximum and maximum
-						if(a > maxPixel)
-							maxPixel = a;
-						if(a < minPixel)
-							minPixel = a;
+						isOutline = true;
+						break; // break inner loop only
 					}
 				}
 			}
 
-			Uint32 newPixel = SDL_MapRGBA(destSurface->format, color.r, color.g, color.b, maxPixel - minPixel);
-			*((Uint32*)destSurface->pixels + y * width + x) = newPixel;
+			if(isOutline)
+			{
+				Uint32 newPixel = SDL_MapRGBA(destSurface->format, color.r, color.g, color.b, color.a);
+				*((Uint32*)destSurface->pixels + y * width + x) = newPixel;
+			}
 		}
 	}
 
-	if (SDL_MUSTLOCK(sourceSurface)) SDL_UnlockSurface(sourceSurface);
-	if (SDL_MUSTLOCK(destSurface)) SDL_UnlockSurface(destSurface);
+	if(SDL_MUSTLOCK(sourceSurface)) SDL_UnlockSurface(sourceSurface);
+	if(SDL_MUSTLOCK(destSurface)) SDL_UnlockSurface(destSurface);
 
 	SDL_FreeSurface(sourceSurface);
-
 	return destSurface;
 }
 
@@ -764,7 +762,7 @@ void applyAffineTransform(SDL_Surface* src, SDL_Surface* dst, double a, double b
 
 	// Calculate inverse matrix M_inv for mapping dst -> src
 	double det = a * d - b * c;
-	if (static_cast<int>(det) == 0)
+	if (std::abs(det) < 1e-10)
 		throw std::runtime_error("Singular transform matrix!");
 	double invDet = 1.0 / det;
 	double ia =  d * invDet;