用sdl2绘制轮廓圆
Draw outline circle with sdl2
TL;DR: 使用 (py)sdl2,我试图绘制一个内部透明的圆形轮廓,从而显示在其后面绘制的对象。基本上,我需要找到一种方法来擦除实心圆内部的像素(或将它们绘制到 with/set 上,恢复为透明像素)。我想尽可能使用纹理而不是表面。
我正在努力实现一些在概念上看起来非常简单的事情,但我就是无法实现它。
我想在python中用sdl2画一个圆形轮廓。当然,这个用sdl2gfx函数circleRGBA()
实现起来很简单,但是只能画出1px线宽的轮廓。画粗线的圆似乎是完全不可能的。
我之前使用透明色键 (inspired by this method) 使用 pygame 表面做过类似的事情,我知道 SDL2 中也可以使用表面,但 警告 是我试图坚持使用更快的纹理,它们不提供颜色键机制。
为了在视觉上更好地解释事情:我想要实现的是:
一个大于 1px 宽的圆(圆环),其内部是透明的,这样画在圆后面的项目将在内部可见。
我过去使用的一个技巧是只绘制 2 个实心圆圈,其中第二个较小的圆圈与背景颜色相同。但是,这会掩盖圆圈后面的所有内容(在本例中为白线)。下面是一个使用这种方法的函数示例:
@to_texture
def draw_circle(self, x, y, r, color, opacity=1.0, fill=True, aa=False, penwidth=1):
# Make sure all spatial parameters are ints
x, y, r = int(x), int(y), int(r)
# convert color parameter to sdl2 understandable values
color = sdl2.ext.convert_to_color(color)
# convert possible opacity values to the right scale
opacity = self.opacity(opacity)
# Get background color set for this texture
bgcolor = self.__bgcolor
# Check for invalid penwidth values, and make sure the value is an int
if penwidth != 1:
if penwidth < 1:
raise ValueError("Penwidth cannot be smaller than 1")
if penwidth > 1:
penwidth = int(penwidth)
# if the circle needs to be filled, it's easy
if fill:
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If penwidth is 1, simple use sdl2gfx own functions
if penwidth == 1:
if aa:
sdlgfx.aacircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
sdlgfx.circleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If the penwidth is larger than 1, things become a bit more complex.
outer_r = int(r+penwidth*.5)
inner_r = int(r-penwidth*.5)
# Draw outer circle
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y,
outer_r, color.r, color.g, color.b, opacity)
# Draw inner circle
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y,
inner_r, bgcolor.r, bgcolor.g, bgcolor.b, 255)
return self
导致:
我也试过各种混合模式,这是我能得到的最好结果:
@to_texture
def draw_circle(self, x, y, r, color, opacity=1.0, fill=True, aa=False, penwidth=1):
# ... omitted for brevity
else:
# If the penwidth is larger than 1, things become a bit more complex.
# To ensure that the interior of the circle is transparent, we will
# have to work with multiple textures and blending.
outer_r = int(r+penwidth*.5)
inner_r = int(r-penwidth*.5)
# Calculate the required dimensions of the separate texture we are
# going to draw the circle on. Add 1 pixel to account for division
# inaccuracies (i.e. dividing an odd number of pixels)
(c_width, c_height) = (outer_r*2+1, outer_r*2+1)
# Create the circle texture, and make sure it can be a rendering
# target by setting the correct access flag.
circle_texture = self.environment.texture_factory.create_sprite(
size=(c_width, c_height),
access=sdl2.SDL_TEXTUREACCESS_TARGET
)
# Set renderer target to the circle texture
if sdl2.SDL_SetRenderTarget(self.sdl_renderer, circle_texture.texture) != 0:
raise Exception("Could not set circle texture as rendering"
" target: {}".format(sdl2.SDL_GetError()))
# Draw the annulus:
# as the reference point is the circle center, outer_r
# can be used for the circles x and y coordinates.
sdlgfx.filledCircleRGBA(self.sdl_renderer, outer_r, outer_r,
outer_r, color.r, color.g, color.b, opacity)
# Draw the hole
sdlgfx.filledCircleRGBA(self.sdl_renderer, outer_r, outer_r,
inner_r, 0, 0, 0, 255)
# Set renderer target back to the FrameBuffer texture
if sdl2.SDL_SetRenderTarget(self.sdl_renderer, self.surface.texture) != 0:
raise Exception("Could not unset circle texture as rendering"
" target: {}".format(sdl2.SDL_GetError()))
# Use additive blending when blitting the circle texture on the main texture
sdl2.SDL_SetTextureBlendMode(circle_texture.texture, sdl2.SDL_BLENDMODE_ADD)
# Perform the blitting operation
self.renderer.copy( circle_texture, dstrect=(x-int(c_width/2),
y-int(c_height/2), c_width, c_height) )
return self
这导致:
接近,但没有雪茄,因为这条线现在看起来 在圆的前面 而不是在圆的后面,据我所知 additive/screen 混合,这是预期的行为。
我知道还有函数 SDL_SetRenderDrawBlendMode,但 sdl2gfx 绘图函数似乎忽略了您使用此函数设置的任何内容。
有没有比我更有经验的人以前做过这样的事情,谁能给我指明正确的方向来应对这个挑战?
我认为你必须创建一个 SDL_Surface
,为其创建一个软件渲染器,在其上绘制,使用 SDL_ColorKey()
去除内部颜色,然后将其转换回 SDL_Texture
。也许这不是最快的方法,但它确实有效。您始终可以创建透明的 PNG 图像并从中加载。
import sys
import ctypes
from sdl2 import *
import sdl2.sdlgfx as sdlgfx
if __name__ == "__main__":
SDL_Init(SDL_INIT_VIDEO)
window = SDL_CreateWindow("Test",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
200, 200, SDL_WINDOW_SHOWN)
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED)
############################################################
surface = SDL_CreateRGBSurface(0, 200, 200, 32,
0xff000000, # r mask
0x00ff0000, # g mask
0x0000ff00, # b mask
0x000000ff) # a mask
soft_renderer = SDL_CreateSoftwareRenderer(surface)
SDL_SetRenderDrawColor(soft_renderer, 255, 255, 0, 255) #yellow background
SDL_SetRenderDrawBlendMode(soft_renderer, SDL_BLENDMODE_NONE)
SDL_RenderClear(soft_renderer)
sdlgfx.filledCircleRGBA(soft_renderer, 100, 100, 100, 0, 255, 255, 255)
sdlgfx.filledCircleRGBA(soft_renderer, 100, 100, 80, 255, 255, 0, 255) #yellow
SDL_SetColorKey(surface, SDL_TRUE, 0xffff00ff) #yellow colorkey
circ = SDL_CreateTextureFromSurface(renderer, surface)
SDL_DestroyRenderer(soft_renderer)
SDL_FreeSurface(surface)
############################################################
running = True
event = SDL_Event()
while running:
# Event loop
while SDL_PollEvent(ctypes.byref(event)) != 0:
if event.type == SDL_QUIT:
running = False
break
# Rendering
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
SDL_RenderClear(renderer)
sdlgfx.thickLineRGBA(renderer, 200, 0, 0, 200, 10, 255, 255, 255, 255)
SDL_RenderCopy(renderer, circ, None, None)
SDL_RenderPresent(renderer);
SDL_DestroyTexture(circ)
SDL_DestroyRenderer(renderer)
SDL_DestroyWindow(window)
SDL_Quit()
@tntxtnt 先于我,但我自己以类似的方式解决了这个问题。我的解决方案也不满足仅使用纹理的需求,而是退回到使用表面。我不知道是否可以只使用纹理来解决这个问题,或者使用表面是否会对性能产生很大的影响,但至少这是可行的。
@tntxtnt 解决方案非常好,但我也会在这里添加我的解决方案,因为我的方法略有不同,更多地依赖于 pysdl2 的实用函数:
class FrameBuffer(object):
# ... omitted for brevity
@to_texture
def draw_circle(self, x, y, r, color, opacity=1.0, fill=True, aa=False, penwidth=1):
# Make sure all spatial parameters are ints
x, y, r = int(x), int(y), int(r)
# convert color parameter to sdl2 understandable values
color = sdl2.ext.convert_to_color(color)
# convert possible opacity values to the right scale
opacity = self.opacity(opacity)
# Check for invalid penwidth values, and make sure the value is an int
if penwidth != 1:
if penwidth < 1:
raise ValueError("Penwidth cannot be smaller than 1")
if penwidth > 1:
penwidth = int(penwidth)
# if only a filled circle needs to be drawn, it's easy
if fill:
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If penwidth is 1, simply use sdl2gfx's own functions
if penwidth == 1:
if aa:
sdlgfx.aacircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
sdlgfx.circleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If the penwidth is larger than 1, things become a bit more complex.
# To ensure that the interior of the circle is transparent, we will
# have to work with multiple textures and blending.
outer_r, inner_r = int(r+penwidth*.5), int(r-penwidth*.5)
# Calculate the required dimensions of the extra texture we are
# going to draw the circle on. Add 1 pixel to account for division
# errors (i.e. dividing an odd number of pixels)
c_width, c_height = outer_r*2+1, outer_r*2+1
# Create the circle texture, and make sure it can be a rendering
# target by setting the correct access flag.
circle_sprite = self.environment.texture_factory.create_software_sprite(
size=(c_width, c_height),
)
# Create a renderer to draw to the circle sprite
sprite_renderer = sdl2.ext.Renderer(circle_sprite)
# Determine the optimal color key to use for this operation
colorkey_color = self.determine_optimal_colorkey(color, self.background_color)
# Clear the sprite with the colorkey color
sprite_renderer.clear(colorkey_color)
# Draw the annulus:
sdlgfx.filledCircleRGBA(sprite_renderer.sdlrenderer, outer_r, outer_r,
outer_r, color.r, color.g, color.b, 255)
# Antialias if desired
if aa:
for i in range(-1,1):
for j in range(2):
sdlgfx.aacircleRGBA(sprite_renderer.sdlrenderer, outer_r,
outer_r, outer_r+i, color.r, color.g, color.b, 255)
# Draw the hole
sdlgfx.filledCircleRGBA(sprite_renderer.sdlrenderer, outer_r, outer_r,
inner_r, colorkey_color.r, colorkey_color.g, colorkey_color.b, 255)
# Antialias if desired
if aa:
for i in range(0,2):
for j in range(2):
sdlgfx.aacircleRGBA(sprite_renderer.sdlrenderer, outer_r,
outer_r, inner_r+i, color.r, color.g, color.b, 255)
# Optimize drawing of transparent pixels
sdl2.SDL_SetSurfaceRLE(circle_sprite.surface, 1)
# Convert the colorkey to a format understandable by the
# SDL_SetColorKey function
colorkey = sdl2.SDL_MapRGB(circle_sprite.surface.format,
colorkey_color.r, colorkey_color.g, colorkey_color.b)
# Set transparency color key
sdl2.SDL_SetColorKey(circle_sprite.surface, sdl2.SDL_TRUE, colorkey)
# Create a texture from the circle sprite
circle_texture = self.environment.texture_factory.from_surface(
circle_sprite.surface
)
# Set the desired transparency value to the texture
sdl2.SDL_SetTextureAlphaMod(circle_texture.texture, opacity)
# Perform the blitting operation
self.renderer.copy( circle_texture, dstrect=(x-int(c_width/2),
y-int(c_height/2), c_width, c_height) )
# Cleanup
del(circle_sprite)
del(sprite_renderer)
return self
def determine_optimal_colorkey(self, drawing_color, dev_offset=5):
""" Determines the optimal color to use for the transparent color key."""
# If foreground and background colors are not identical, simply return
# the background color
if drawing_color != self.background_color:
return self.background_color
if not 1 <= dev_offset <= 25:
raise ValueError("dev_offset should be a value between 1 and 25")
# Create offset_color
offset_color = sdl2.ext.Color(dev_offset, dev_offset, dev_offset, 0)
# Create white_color
white = sdl2.ext.Color(255,255,255,255)
color_key = self.background_color + offset_color
if color_key != white:
return color_key
else:
return self.background_color - offset_color
def opacity(self, value):
""" Convert float values to opacity range between 0 and 255. """
if type(value) == float and 0.0 <= value <= 1.0:
# This is maybe a bit iffy, because it does not allow opacity values
# in the 0 to 255 range between 0 and 1 (it maybe undesiredly converts
# it to value*255).
# TODO: Think about a solution for this
return int(value*255)
elif type(value) in [int, float]:
if 0 <= value <= 255:
return int(value)
else:
raise ValueError("Invalid opacity value")
else:
raise TypeError("Incorrect type or value passed for opacity.")
# ... ommitted for brevity
TL;DR: 使用 (py)sdl2,我试图绘制一个内部透明的圆形轮廓,从而显示在其后面绘制的对象。基本上,我需要找到一种方法来擦除实心圆内部的像素(或将它们绘制到 with/set 上,恢复为透明像素)。我想尽可能使用纹理而不是表面。
我正在努力实现一些在概念上看起来非常简单的事情,但我就是无法实现它。
我想在python中用sdl2画一个圆形轮廓。当然,这个用sdl2gfx函数circleRGBA()
实现起来很简单,但是只能画出1px线宽的轮廓。画粗线的圆似乎是完全不可能的。
我之前使用透明色键 (inspired by this method) 使用 pygame 表面做过类似的事情,我知道 SDL2 中也可以使用表面,但 警告 是我试图坚持使用更快的纹理,它们不提供颜色键机制。
为了在视觉上更好地解释事情:我想要实现的是:
一个大于 1px 宽的圆(圆环),其内部是透明的,这样画在圆后面的项目将在内部可见。
我过去使用的一个技巧是只绘制 2 个实心圆圈,其中第二个较小的圆圈与背景颜色相同。但是,这会掩盖圆圈后面的所有内容(在本例中为白线)。下面是一个使用这种方法的函数示例:
@to_texture
def draw_circle(self, x, y, r, color, opacity=1.0, fill=True, aa=False, penwidth=1):
# Make sure all spatial parameters are ints
x, y, r = int(x), int(y), int(r)
# convert color parameter to sdl2 understandable values
color = sdl2.ext.convert_to_color(color)
# convert possible opacity values to the right scale
opacity = self.opacity(opacity)
# Get background color set for this texture
bgcolor = self.__bgcolor
# Check for invalid penwidth values, and make sure the value is an int
if penwidth != 1:
if penwidth < 1:
raise ValueError("Penwidth cannot be smaller than 1")
if penwidth > 1:
penwidth = int(penwidth)
# if the circle needs to be filled, it's easy
if fill:
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If penwidth is 1, simple use sdl2gfx own functions
if penwidth == 1:
if aa:
sdlgfx.aacircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
sdlgfx.circleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If the penwidth is larger than 1, things become a bit more complex.
outer_r = int(r+penwidth*.5)
inner_r = int(r-penwidth*.5)
# Draw outer circle
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y,
outer_r, color.r, color.g, color.b, opacity)
# Draw inner circle
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y,
inner_r, bgcolor.r, bgcolor.g, bgcolor.b, 255)
return self
导致:
我也试过各种混合模式,这是我能得到的最好结果:
@to_texture
def draw_circle(self, x, y, r, color, opacity=1.0, fill=True, aa=False, penwidth=1):
# ... omitted for brevity
else:
# If the penwidth is larger than 1, things become a bit more complex.
# To ensure that the interior of the circle is transparent, we will
# have to work with multiple textures and blending.
outer_r = int(r+penwidth*.5)
inner_r = int(r-penwidth*.5)
# Calculate the required dimensions of the separate texture we are
# going to draw the circle on. Add 1 pixel to account for division
# inaccuracies (i.e. dividing an odd number of pixels)
(c_width, c_height) = (outer_r*2+1, outer_r*2+1)
# Create the circle texture, and make sure it can be a rendering
# target by setting the correct access flag.
circle_texture = self.environment.texture_factory.create_sprite(
size=(c_width, c_height),
access=sdl2.SDL_TEXTUREACCESS_TARGET
)
# Set renderer target to the circle texture
if sdl2.SDL_SetRenderTarget(self.sdl_renderer, circle_texture.texture) != 0:
raise Exception("Could not set circle texture as rendering"
" target: {}".format(sdl2.SDL_GetError()))
# Draw the annulus:
# as the reference point is the circle center, outer_r
# can be used for the circles x and y coordinates.
sdlgfx.filledCircleRGBA(self.sdl_renderer, outer_r, outer_r,
outer_r, color.r, color.g, color.b, opacity)
# Draw the hole
sdlgfx.filledCircleRGBA(self.sdl_renderer, outer_r, outer_r,
inner_r, 0, 0, 0, 255)
# Set renderer target back to the FrameBuffer texture
if sdl2.SDL_SetRenderTarget(self.sdl_renderer, self.surface.texture) != 0:
raise Exception("Could not unset circle texture as rendering"
" target: {}".format(sdl2.SDL_GetError()))
# Use additive blending when blitting the circle texture on the main texture
sdl2.SDL_SetTextureBlendMode(circle_texture.texture, sdl2.SDL_BLENDMODE_ADD)
# Perform the blitting operation
self.renderer.copy( circle_texture, dstrect=(x-int(c_width/2),
y-int(c_height/2), c_width, c_height) )
return self
这导致:
接近,但没有雪茄,因为这条线现在看起来 在圆的前面 而不是在圆的后面,据我所知 additive/screen 混合,这是预期的行为。
我知道还有函数 SDL_SetRenderDrawBlendMode,但 sdl2gfx 绘图函数似乎忽略了您使用此函数设置的任何内容。
有没有比我更有经验的人以前做过这样的事情,谁能给我指明正确的方向来应对这个挑战?
我认为你必须创建一个 SDL_Surface
,为其创建一个软件渲染器,在其上绘制,使用 SDL_ColorKey()
去除内部颜色,然后将其转换回 SDL_Texture
。也许这不是最快的方法,但它确实有效。您始终可以创建透明的 PNG 图像并从中加载。
import sys
import ctypes
from sdl2 import *
import sdl2.sdlgfx as sdlgfx
if __name__ == "__main__":
SDL_Init(SDL_INIT_VIDEO)
window = SDL_CreateWindow("Test",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
200, 200, SDL_WINDOW_SHOWN)
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED)
############################################################
surface = SDL_CreateRGBSurface(0, 200, 200, 32,
0xff000000, # r mask
0x00ff0000, # g mask
0x0000ff00, # b mask
0x000000ff) # a mask
soft_renderer = SDL_CreateSoftwareRenderer(surface)
SDL_SetRenderDrawColor(soft_renderer, 255, 255, 0, 255) #yellow background
SDL_SetRenderDrawBlendMode(soft_renderer, SDL_BLENDMODE_NONE)
SDL_RenderClear(soft_renderer)
sdlgfx.filledCircleRGBA(soft_renderer, 100, 100, 100, 0, 255, 255, 255)
sdlgfx.filledCircleRGBA(soft_renderer, 100, 100, 80, 255, 255, 0, 255) #yellow
SDL_SetColorKey(surface, SDL_TRUE, 0xffff00ff) #yellow colorkey
circ = SDL_CreateTextureFromSurface(renderer, surface)
SDL_DestroyRenderer(soft_renderer)
SDL_FreeSurface(surface)
############################################################
running = True
event = SDL_Event()
while running:
# Event loop
while SDL_PollEvent(ctypes.byref(event)) != 0:
if event.type == SDL_QUIT:
running = False
break
# Rendering
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
SDL_RenderClear(renderer)
sdlgfx.thickLineRGBA(renderer, 200, 0, 0, 200, 10, 255, 255, 255, 255)
SDL_RenderCopy(renderer, circ, None, None)
SDL_RenderPresent(renderer);
SDL_DestroyTexture(circ)
SDL_DestroyRenderer(renderer)
SDL_DestroyWindow(window)
SDL_Quit()
@tntxtnt 先于我,但我自己以类似的方式解决了这个问题。我的解决方案也不满足仅使用纹理的需求,而是退回到使用表面。我不知道是否可以只使用纹理来解决这个问题,或者使用表面是否会对性能产生很大的影响,但至少这是可行的。
@tntxtnt 解决方案非常好,但我也会在这里添加我的解决方案,因为我的方法略有不同,更多地依赖于 pysdl2 的实用函数:
class FrameBuffer(object):
# ... omitted for brevity
@to_texture
def draw_circle(self, x, y, r, color, opacity=1.0, fill=True, aa=False, penwidth=1):
# Make sure all spatial parameters are ints
x, y, r = int(x), int(y), int(r)
# convert color parameter to sdl2 understandable values
color = sdl2.ext.convert_to_color(color)
# convert possible opacity values to the right scale
opacity = self.opacity(opacity)
# Check for invalid penwidth values, and make sure the value is an int
if penwidth != 1:
if penwidth < 1:
raise ValueError("Penwidth cannot be smaller than 1")
if penwidth > 1:
penwidth = int(penwidth)
# if only a filled circle needs to be drawn, it's easy
if fill:
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If penwidth is 1, simply use sdl2gfx's own functions
if penwidth == 1:
if aa:
sdlgfx.aacircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
sdlgfx.circleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If the penwidth is larger than 1, things become a bit more complex.
# To ensure that the interior of the circle is transparent, we will
# have to work with multiple textures and blending.
outer_r, inner_r = int(r+penwidth*.5), int(r-penwidth*.5)
# Calculate the required dimensions of the extra texture we are
# going to draw the circle on. Add 1 pixel to account for division
# errors (i.e. dividing an odd number of pixels)
c_width, c_height = outer_r*2+1, outer_r*2+1
# Create the circle texture, and make sure it can be a rendering
# target by setting the correct access flag.
circle_sprite = self.environment.texture_factory.create_software_sprite(
size=(c_width, c_height),
)
# Create a renderer to draw to the circle sprite
sprite_renderer = sdl2.ext.Renderer(circle_sprite)
# Determine the optimal color key to use for this operation
colorkey_color = self.determine_optimal_colorkey(color, self.background_color)
# Clear the sprite with the colorkey color
sprite_renderer.clear(colorkey_color)
# Draw the annulus:
sdlgfx.filledCircleRGBA(sprite_renderer.sdlrenderer, outer_r, outer_r,
outer_r, color.r, color.g, color.b, 255)
# Antialias if desired
if aa:
for i in range(-1,1):
for j in range(2):
sdlgfx.aacircleRGBA(sprite_renderer.sdlrenderer, outer_r,
outer_r, outer_r+i, color.r, color.g, color.b, 255)
# Draw the hole
sdlgfx.filledCircleRGBA(sprite_renderer.sdlrenderer, outer_r, outer_r,
inner_r, colorkey_color.r, colorkey_color.g, colorkey_color.b, 255)
# Antialias if desired
if aa:
for i in range(0,2):
for j in range(2):
sdlgfx.aacircleRGBA(sprite_renderer.sdlrenderer, outer_r,
outer_r, inner_r+i, color.r, color.g, color.b, 255)
# Optimize drawing of transparent pixels
sdl2.SDL_SetSurfaceRLE(circle_sprite.surface, 1)
# Convert the colorkey to a format understandable by the
# SDL_SetColorKey function
colorkey = sdl2.SDL_MapRGB(circle_sprite.surface.format,
colorkey_color.r, colorkey_color.g, colorkey_color.b)
# Set transparency color key
sdl2.SDL_SetColorKey(circle_sprite.surface, sdl2.SDL_TRUE, colorkey)
# Create a texture from the circle sprite
circle_texture = self.environment.texture_factory.from_surface(
circle_sprite.surface
)
# Set the desired transparency value to the texture
sdl2.SDL_SetTextureAlphaMod(circle_texture.texture, opacity)
# Perform the blitting operation
self.renderer.copy( circle_texture, dstrect=(x-int(c_width/2),
y-int(c_height/2), c_width, c_height) )
# Cleanup
del(circle_sprite)
del(sprite_renderer)
return self
def determine_optimal_colorkey(self, drawing_color, dev_offset=5):
""" Determines the optimal color to use for the transparent color key."""
# If foreground and background colors are not identical, simply return
# the background color
if drawing_color != self.background_color:
return self.background_color
if not 1 <= dev_offset <= 25:
raise ValueError("dev_offset should be a value between 1 and 25")
# Create offset_color
offset_color = sdl2.ext.Color(dev_offset, dev_offset, dev_offset, 0)
# Create white_color
white = sdl2.ext.Color(255,255,255,255)
color_key = self.background_color + offset_color
if color_key != white:
return color_key
else:
return self.background_color - offset_color
def opacity(self, value):
""" Convert float values to opacity range between 0 and 255. """
if type(value) == float and 0.0 <= value <= 1.0:
# This is maybe a bit iffy, because it does not allow opacity values
# in the 0 to 255 range between 0 and 1 (it maybe undesiredly converts
# it to value*255).
# TODO: Think about a solution for this
return int(value*255)
elif type(value) in [int, float]:
if 0 <= value <= 255:
return int(value)
else:
raise ValueError("Invalid opacity value")
else:
raise TypeError("Incorrect type or value passed for opacity.")
# ... ommitted for brevity