def create_window_texture_set_size(angular_width, z_width, color, color_bg, size_phi, size_z): # this creates a texture of size (size_phi X size_z) in pixels # one subregion of the texture of size (angular_width X z_width) is colored with "color" # the rest of the texture is colored with "color_bg" # generate bar texture image = pcore.PNMImage( size_phi, size_z ) # only 1 degree steps for the width of the window and 0.1 units steps for the height of the window image.fill(color_bg / 255.) for i in range(int(angular_width)): for j in range(int(np.round(z_width / 0.1))): image.setXelA(i, j, color / 255., color / 255., color / 255., 1) for i in range(int(angular_width), size_phi): for j in range(int(np.round(z_width / 0.1))): image.setXelA(i, 0, color_bg / 255., color_bg / 255., color_bg / 255., 1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTLinearMipmapLinear) tex.setBorderColor( pcore.Vec4(color_bg / 255., color_bg / 255., color_bg / 255., 1)) tex.setWrapU(pcore.Texture.WM_border_color) tex.setWrapV(pcore.Texture.WM_border_color) tex.setAnisotropicDegree(16) return tex
def create_circular_window_texture(angular_width, color, color_bg): # generate bar texture image = pcore.PNMImage( 360 * 3, 260 * 2 ) # only 1 degree steps for the width of the window and 0.1 units steps for the height of the window #z_width = (angular_width/360. * 2 * math.pi*10) / 26 * (np.degrees(np.arctan(13/10.)) * 2) z_width = np.radians( angular_width ) * 10 # Kleinwinkelnaeherung / approximation for small angular widths #print z_width image.fill(color_bg / 255.) for i in range(min([360 * 3, int(angular_width) * 3])): for j in range(min([260 * 2, int(np.round(z_width / 0.1 * 2))])): if (i - angular_width / 2. * 3)**2 / ( angular_width / 2. * 3)**2 + (j - z_width / 0.1 / 2. * 2)**2 / (z_width / 0.1 / 2. * 2)**2 <= 1: image.setXelA(i, j, color / 255., color / 255., color / 255., 1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTNearest) tex.setBorderColor( pcore.Vec4(color_bg / 255., color_bg / 255., color_bg / 255., 1)) tex.setWrapU(pcore.Texture.WM_border_color) tex.setWrapV(pcore.Texture.WM_border_color) tex.setAnisotropicDegree(16) return tex
def __load_layer_sheet(self, layer_name, img_file): """ Loads a layer sheet image file and assigns it to the layers dictionary using its layer name """ assert not img_file.empty() # Load the spritesheet img_header = core.PNMImageHeader() assert img_header.read_header(img_file) if sprite_notify.getDebug(): sprite_notify.debug('Loading spritesheet layer: %s' % img_file) image = core.PNMImage() image.read(img_file) assert image.is_valid() size_x = image.get_x_size() size_y = image.get_y_size() assert size_x != 0 assert size_y != 0 assert self._size_x == size_x assert self._size_y == size_y self._layers[layer_name] = image
def create_content_texture(content, color_bg): # this creates a texture of size (360 X 260) in pixels # this correspond to a precision of 1 degree in azimuth and 1mm in the z-axis in arena coordinates # one subregion of the texture gets a given content # the rest is filled with background angular_width, z_width = content.shape # generate bar texture image = pcore.PNMImage( 360, 260 ) # only 1 degree steps for the width of the window and 0.1 units steps for the height of the window image.fill(color_bg / 255.) for i in range(int(angular_width)): for j in range(int(np.round(z_width))): image.setXelA(i, j, content[i, j] / 255., content[i, j] / 255., content[i, j] / 255., 1) #for i in range(int(angular_width), 360): # for j in range(int(np.round(z_width/0.1))): # image.setXelA(i, 0, color_bg/255., color_bg/255., color_bg/255., 1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTLinearMipmapLinear) tex.setBorderColor( pcore.Vec4(color_bg / 255., color_bg / 255., color_bg / 255., 1)) tex.setWrapU(pcore.Texture.WM_border_color) tex.setWrapV(pcore.Texture.WM_border_color) tex.setAnisotropicDegree(16) return tex
def build(self): # configure beamer self.set_arena_mode('greenHDMI') self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder( self.parent.mainNode) self.cylinder.setScale(10, 10, 50) self.cylinder_height = 50 self.cylinder_radius = 10 chess_image = pcore.PNMImage(2, 2) chess_image.setXelA(0, 0, 0, 0, 0, 1) chess_image.setXelA(1, 1, 0, 0, 0, 1) chess_image.setXelA(0, 1, 1, 1, 1, 1) chess_image.setXelA(1, 0, 1, 1, 1, 1) chess_tex = pcore.Texture() chess_tex.load(chess_image) chess_tex.setMagfilter(pcore.Texture.FTNearest) N_vertical = self.cylinder_height / ( 2 * math.pi * self.cylinder_radius / self.N_horizontal ) #1./(2*math.pi/N_horizontal) self.cylinder.setTexScale(pcore.TextureStage.getDefault(), self.N_horizontal, N_vertical) self.cylinder.setTexture(chess_tex) self.v_tex_offset_count = 0 self.h_tex_offset_count = 0 self.fov_right_diff = [0.0, 0.0] self.fov_left_diff = [0.0, 0.0] self.T = self.duration
def create_test_texture(angular_width, z_width, color, color_bg, size_phi, size_z): # generate bar texture image = pcore.PNMImage( size_phi, size_z ) # only 1 degree steps for the width of the window and 0.1 units steps for the height of the window image.fill(color_bg / 255.) # for i in range(0, 20): # for j in range(int(size_z)-20, int(size_z)): # image.setXelA(i,j,color/255.,color/255.,color/255.,1) for i in range(0, size_phi): image.setXelA(i, 0, color_bg / 255., color_bg / 255., color_bg / 255., 1) image.setXelA(i, size_z - 1, color / 255., color / 255., color / 255., 1) for i in range(0, size_z): image.setXelA(0, i, color_bg / 255., color_bg / 255., color_bg / 255., 1) image.setXelA(size_phi - 1, i, color / 255., color / 255., color / 255., 1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTLinearMipmapLinear) tex.setAnisotropicDegree(16) return tex
def create_ellipse_window_texture_transparent_fg(angular_width, z_width, color, color_bg): # analogue to create_circular_window_texture, only width an additional z_width # (used to account for perspective distortions when showing larger angles). # generate bar texture precision = 0.2 image = pcore.PNMImage( 360 * 3, 260 * 2 ) # only 1 degree steps for the width of the window and 0.1 units steps for the height of the window #z_width = (angular_width/360. * 2 * math.pi*10) / 26 * (np.degrees(np.arctan(13/10.)) * 2) #z_width = np.radians(angular_width) * 10 # Kleinwinkelnaeherung / approximation for small angular widths #print z_width image.fill(color_bg / 255.) image.alphaFillVal(255) for i in range(min([360 * 3, int(angular_width) * 3])): for j in range(min([260 * 2, int(np.round(z_width / precision * 2))])): if (i - angular_width / 2. * 3)**2 / ( angular_width / 2. * 3)**2 + (j - z_width / precision / 2. * 2)**2 / ( z_width / precision / 2. * 2)**2 <= 1: image.setXelA(i, j, color / 255., color / 255., color / 255., 0) #image.setAlphaVal(i,j,0.1) print("zwidth") print(z_width) # SHOW BORDERS OF THE LOOP FROM ABOVE #for i in range(0,360*3): # image.setXelA(i,0,color/255.,color/255.,color/255.,1) # image.setXelA(i,1,color/255.,color/255.,color/255.,1) # image.setXelA(i,2,color/255.,color/255.,color/255.,1) # image.setXelA(i,int(np.round(z_width/0.1*2))-1,color/255.,color/255.,color/255.,1) # image.setXelA(i,int(np.round(z_width/0.1*2))-2,color/255.,color/255.,color/255.,1) # image.setXelA(i,int(np.round(z_width/0.1*2))-3,color/255.,color/255.,color/255.,1) #for j in range(0,260*2): # image.setXelA(0,j,color/255.,color/255.,color/255.,1) # image.setXelA(1,j,color/255.,color/255.,color/255.,1) # image.setXelA(2,j,color/255.,color/255.,color/255.,1) # image.setXelA(int(angular_width)*3-1,j,color/255.,color/255.,color/255.,1) # image.setXelA(int(angular_width)*3-2,j,color/255.,color/255.,color/255.,1) # image.setXelA(int(angular_width)*3-3,j,color/255.,color/255.,color/255.,1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTNearest) tex.setBorderColor( pcore.Vec4(color_bg / 255., color_bg / 255., color_bg / 255., 1)) tex.setWrapU(pcore.Texture.WM_border_color) tex.setWrapV(pcore.Texture.WM_border_color) tex.setAnisotropicDegree(16) return tex
def create_plain_texture(color): image = pcore.PNMImage(1, 1) image.setXelA(0, 0, color / 255., color / 255., color / 255., 1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTLinearMipmapLinear) tex.setAnisotropicDegree(16) return tex
def _make_sdf_box(): sdfimg = p3d.PNMImage(_SDF_SIZE, _SDF_SIZE) for imgx in range(_SDF_SIZE): normx = abs((imgx / _SDF_SIZE) * 2.0 - 1.0) for imgy in range(_SDF_SIZE): normy = abs((imgy / _SDF_SIZE) * 2.0 - 1.0) dist = _lin_remap(1 - max(normx, normy), 0, 1, 0.5, 1) sdfimg.setXel(imgx, imgy, dist) sdftex = p3d.Texture() sdftex.load(sdfimg) return sdftex
def create_sine_grating_texture(n, min_value, max_value): # generate grating texture image = pcore.PNMImage(n * 2, 1) for i in range(n * 2): value = (math.sin(float(i) / (2 * n) * 2 * math.pi) + 1) / 2. * (max_value - min_value) + min_value image.setXelA(i, 0, value / 255., value / 255., value / 255., 1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTLinearMipmapLinear) tex.setAnisotropicDegree(16) #image.write(pcore.Filename("test.png")) return tex
def create_bar_texture(angular_width, color, color_bg): # generate bar texture image = pcore.PNMImage(360, 1) # only 1 degree steps for the width of the bar for i in range(int(angular_width)): image.setXelA(i, 0, color / 255., color / 255., color / 255., 1) for i in range(int(angular_width), 360): image.setXelA(i, 0, color_bg / 255., color_bg / 255., color_bg / 255., 1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTLinearMipmapLinear) tex.setAnisotropicDegree(16) return tex
def make_matrix_to_texture(M): # generate bar texture image = pcore.PNMImage( M.shape[0], M.shape[1] ) # only 1 degree steps for the width of the window and 0.1 units steps for the height of the window for i in range(int(M.shape[0])): for j in range(int(M.shape[1])): image.setXelA(i, j, M[i, j] / 255., M[i, j] / 255. * 1, M[i, j] / 255. * 1, 1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTNearest) tex.setAnisotropicDegree(16) return tex
def _make_sdf_circle(): sdfimg = p3d.PNMImage(_SDF_SIZE, _SDF_SIZE) maxneg = -math.sqrt(2) + 1 for imgx in range(_SDF_SIZE): normx = (imgx / (_SDF_SIZE - 1)) * 2.0 - 1.0 for imgy in range(_SDF_SIZE): normy = (imgy / (_SDF_SIZE - 1)) * 2.0 - 1.0 length = normx**2 + normy**2 if length < 1.0: dist = _lin_remap(1 - length, 0, 1, 0.5, 1) else: dist = _lin_remap(-length + 1, maxneg, 0, 0, 0.5) sdfimg.setXel(imgx, imgy, dist) sdftex = p3d.Texture() sdftex.load(sdfimg) return sdftex
def create_grating_texture(n, min_value, max_value): # generate grating texture image = pcore.PNMImage(n * 2, 1) for i in range(n): image.setXelA(i, 0, min_value / 255., min_value / 255., min_value / 255., 1) #if i < 50: # image.setXelA(i,0,50/255.,50/255.,50/255.,1) for i in range(n, n * 2): image.setXelA(i, 0, max_value / 255., max_value / 255., max_value / 255., 1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTLinearMipmapLinear) tex.setAnisotropicDegree(16) #image.write(pcore.Filename("test.png")) return tex
def project(self): # project field of view of beamer N_x = int(self.arena.omega_h * 3) N_y = int(self.arena.omega_v * 3) grid_image = pcore.PNMImage(N_x, N_y) for i in range(N_x - 2): for j in range(N_y - 2): grid_image.setXelA(i + 1, j + 1, 0, 0, 0, 1) for i in range(N_x): grid_image.setXelA(i, 0, 1, 1, 1, 1) grid_image.setXelA(i, int(N_y / 2), 1, 1, 1, 1) grid_image.setXelA(i, N_y - 1, 1, 1, 1, 1) for i in range(N_y): grid_image.setXelA(0, i, 1, 1, 1, 1) grid_image.setXelA(int(N_x / 2), i, 1, 1, 1, 1) grid_image.setXelA(N_x - 1, i, 1, 1, 1, 1) self.tex_grid = pcore.Texture() self.tex_grid.load(grid_image) self.tex_grid.setMagfilter(pcore.Texture.FTNearest) self.proj = render.attachNewNode(pcore.LensNode('proj')) self.proj.node().setLens(self.lens) self.proj.reparentTo(self.beamer) self.ts = pcore.TextureStage('ts_proj') self.ts.setMode(pcore.TextureStage.MBlend) self.ts.setColor( pcore.Vec4(self.color[0], self.color[1], self.color[2], self.color[3])) self.tex_grid.setWrapU(pcore.Texture.WMBorderColor) self.tex_grid.setWrapV(pcore.Texture.WMBorderColor) self.screen.projectTexture(self.ts, self.tex_grid, self.proj) self.proj.node().showFrustum() self.proj.find('frustum').setColor(self.color[0], self.color[1], self.color[2], self.color[3])
def _set_browser_size(self, window=None): if window is None: return if window.is_closed(): self._shutdown_cef() return width = int(round(window.get_x_size() * self._UI_SCALE)) height = int(round(window.get_y_size() * self._UI_SCALE)) # We only want to resize if the window size actually changed. if self._cef_texture.get_x_size( ) != width or self._cef_texture.get_y_size() != height: self._cef_texture.set_x_size(width) self._cef_texture.set_y_size(height) # Clear the texture img = p3d.PNMImage(width, height) img.fill(0, 0, 0) img.alpha_fill(0) self._cef_texture.load(img) self.browser.WasResized()
def gotModel(self, mdl, filename, context): self.currentLoadContext = None if not mdl or mdl.isEmpty(): context.createNextAsset() return # If there's no geomnode, there is no model! if mdl.find("**/+GeomNode").isEmpty(): context.createNextAsset() return mdl.reparentTo(self.render) # Determine a good offset point to take the thumbnail snapshot mins = core.Point3() maxs = core.Point3() mdl.calcTightBounds(mins, maxs) size = maxs - mins center = (mins + maxs) / 2.0 # Choose the longest axis as the radius radius = size.length() / 2 fov = self.lens.getFov() distance = (radius / float(math.tan(core.deg2Rad(min(fov[0], fov[1]) / 2.0)))) # Ensure the far plane is far enough back to see the entire object. idealFarPlane = distance + radius * 1.5 self.lens.setFar(max(self.lens.getDefaultFar(), idealFarPlane)) # And that the near plane is far enough forward. idealNearPlane = distance - radius self.lens.setNear(min(self.lens.getDefaultNear(), idealNearPlane)) self.camera.setPos(center + self.camera.getQuat().xform(core.Vec3.forward() * -distance)) # Render the model to the back buffer self.buffer.setActive(True) base.graphicsEngine.renderFrame() base.graphicsEngine.renderFrame() # Fetch the pixels into a PNMImage image = core.PNMImage() self.buffer.getScreenshot(image) self.buffer.setActive(False) mdl.removeNode() # Store the pixels in a QPixmap qimage = QtGui.QImage(image.getXSize(), image.getYSize(), QtGui.QImage.Format_RGB888) for x in range(image.getXSize()): for y in range(image.getYSize()): col = CIGlobals.vec3LinearToGamma(image.getXelA(x, y)) qimage.setPixelColor( x, y, QtGui.QColor(int(col[0] * 255), int(col[1] * 255), int(col[2] * 255), int(col[3] * 255))) pixmap = QtGui.QPixmap.fromImage(qimage) icon = QtGui.QIcon(pixmap) self.modelThumbnails[filename] = icon context.addAssetItem(icon, filename) context.createNextAsset()
def build(self): #, old_geometry): # configure beamer self.set_arena_mode('greenHDMI') #new_geometry = [] self.off_center = self.parent.mainNode.attachNewNode("off_center") self.off_center.setPos(205, 0, 0) # define cylinder 1 self.cylinder1_height = 10 self.cylinder1_radius = 200 self.cylinder1 = tools.create_cylinder_parts(self.parent.mainNode, 1, 360) self.cylinder1.reparentTo(self.off_center) self.cylinder1.setPos(0, 0, 0) self.cylinder1.setScale(self.cylinder1_radius, self.cylinder1_radius, self.cylinder1_height) self.cylinder1.setHpr(0, 0, 0) self.cylinder1.setAttrib( pcore.CullFaceAttrib.make( pcore.CullFaceAttrib.MCullCounterClockwise)) # define cylinder 2 self.cylinder2_height = 10 self.cylinder2_radius = 210 self.cylinder2 = tools.create_cylinder_parts(self.parent.mainNode, 1, 360) self.cylinder2.reparentTo(self.off_center) self.cylinder2.setPos(0, 0, 0) self.cylinder2.setScale(self.cylinder2_radius, self.cylinder2_radius, self.cylinder2_height) self.cylinder2.setHpr(0, 0, 0) # define top cm = pcore.CardMaker('top') self.top = self.off_center.attachNewNode(cm.generate()) self.top.setPos(-220, 220, 5) self.top.setHpr(0, 90, 0) self.top.setScale(440, 1, 440) # define bottom self.bottom = self.off_center.attachNewNode(cm.generate()) self.bottom.setPos(-220, -220, -5) self.bottom.setHpr(0, -90, 0) self.bottom.setScale(440, 1, 440) # load wall textures N_vertical = 1. N_horizontal = self.cylinder1_radius * 2 * math.pi / self.cylinder1_height self.cylinder1.setTexScale(pcore.TextureStage.getDefault(), N_horizontal, N_vertical) self.cylinder2.setTexScale(pcore.TextureStage.getDefault(), N_horizontal, N_vertical) baum_file = tools.make_panda3d_path(self.shared.arena_path, "stimuli/default/baum.jpg") baum_tex = loader.loadTexture(baum_file) self.cylinder1.setTexture(baum_tex) berg_file = tools.make_panda3d_path(self.shared.arena_path, "stimuli/default/baum.jpg") berg_tex = loader.loadTexture(berg_file) self.cylinder2.setTexture(berg_tex) # load top texture sky_file = tools.make_panda3d_path(self.shared.arena_path, "stimuli/default/sky.jpg") sky_tex = loader.loadTexture(sky_file) self.top.setTexture(sky_tex) self.top.setTexScale(pcore.TextureStage.getDefault(), 220, 220) # generate chessboard texture / bottom texture chess_image = pcore.PNMImage(2, 2) chess_image.setXelA(0, 0, 0, 0, 0, 1) chess_image.setXelA(1, 1, 0, 0, 0, 1) chess_image.setXelA(0, 1, 1, 1, 1, 1) chess_image.setXelA(1, 0, 1, 1, 1, 1) chess_tex = pcore.Texture() chess_tex.load(chess_image) chess_tex.setMagfilter(pcore.Texture.FTNearest) # set bottom texture self.bottom.setTexScale(pcore.TextureStage.getDefault(), 220, 220) self.bottom.setTexture(chess_tex)
def init_terrain(self, entity): component = entity[Terrain] noise = core.StackedPerlinNoise2() scaled_size = int(component.size * component.resolution) heightmap_size = scaled_size # + 1 print(f"Terrain complexity: {scaled_size}") max_mag = 0.0 for mag, scale in component.octaves: if mag > max_mag: max_mag = mag for mag, scale in component.octaves: scale /= component.size noise.add_level( core.PerlinNoise2(scale, scale, 256, component.seed), mag / max_mag) heightfield = core.PNMImage(heightmap_size, heightmap_size, 1) heightfield.set_maxval(0xffff) #heightfield.perlin_noise_fill(noise) status = heightfield.read( core.Filename.expand_from( '$MAIN_DIR/assets/textures/heightmap.png')) assert status, "Could not read heightmap" #heightfield.make_grayscale() #assert heightfield.is_grayscale() # We use GeoMipTerrain just for determining the normals at the moment. heightfield2 = core.PNMImage(heightmap_size + 1, heightmap_size + 1, 1) heightfield2.set_maxval(0xffff) heightfield2.copy_sub_image(heightfield, 0, 0) terrain = core.GeoMipTerrain(entity._uid.name) terrain.set_heightfield(heightfield2) terrain.set_bruteforce(True) terrain.set_block_size(min(32, scaled_size)) #terrain.set_color_map(heightfield) # Store both height and normal in the same texture. nimg = core.PNMImage(heightmap_size, heightmap_size, 4, color_space=core.CS_linear) for x in range(heightmap_size): for y in range(heightmap_size): normal = terrain.get_normal(x, y) normal.x *= component.resolution normal.y *= component.resolution normal.z /= max_mag normal.normalize() nimg.set_xel(x, y, normal * 0.5 + 0.5) #nimg.set_alpha(x, y, terrain.get_elevation(x, y)) nimg.set_alpha(x, y, heightfield.get_gray(x, y)) ntex = core.Texture("normal") ntex.load(nimg) ntex.wrap_u = core.SamplerState.WM_repeat ntex.wrap_v = core.SamplerState.WM_repeat ntex.set_keep_ram_image(True) component._peeker = ntex.peek() root = terrain.get_root() root.set_scale(1.0 / component.resolution, 1.0 / component.resolution, max_mag) #root.reparent_to(base.render) #root.set_texture(htex) #terrain.generate() mat = core.Material() #mat.base_color = (0.16, 0.223, 0.076, 1) mat.base_color = (0.4, 0.6, 0.4, 1) mat.base_color = (41.6 / 255.0, 73.7 / 255.0, 29.0 / 255.0, 1) #print(mat.base_color) mat.roughness = 1 #root.set_material(mat) simg = core.PNMImage(64, 64, 1) simg.fill(1) component._sat_img = simg component._sat_tex = core.Texture() component._sat_tex.load(simg) component._scale = core.VBase3(component.resolution / scaled_size, component.resolution / scaled_size, max_mag) component._wind_map = loader.load_texture("assets/textures/wind.png") component._wind_sound = loader.load_sfx("assets/sfx/wind-low.ogg") component._wind_sound.set_loop(True) grass_root = render.attach_new_node("grass") grass_root.set_shader( core.Shader.load(core.Shader.SL_GLSL, "assets/shaders/grass.vert", "assets/shaders/grass.frag"), 20) render.set_shader_input("scale", component.resolution / scaled_size, component.resolution / scaled_size, max_mag) grass_root.set_shader_input("terrainmap", ntex) render.set_shader_input("windmap", component._wind_map) grass_root.set_material(mat) grass_root.set_shader_input("player", 0, 0, 0) render.set_shader_input("satmap", component._sat_tex) #grass_root.node().set_bounds(core.BoundingSphere()) #grass_root.node().set_final(True) grass_root.set_bin('background', 10) if base.quality == 0: patch = loader.load_model("assets/models/patch-potato.bam") elif base.quality == 1: patch = loader.load_model("assets/models/patch-low.bam") else: patch = loader.load_model("assets/models/patch.bam") patch_size = int(patch.get_tag('patch_size')) self._r_build_grass_octree(grass_root, patch, patch_size, component.size * 2) grass_root.set_pos(-0.5 * component.size, -0.5 * component.size, 8) component._grass_root = grass_root
def __load_base_sheet(self, img_file): """ Loads the base sprite sheet from the VFS and performs the required math for display """ # Load the spritesheet img_header = core.PNMImageHeader() assert img_header.read_header(img_file) if sprite_notify.getDebug(): sprite_notify.debug('Loading spritesheet base: %s' % img_file) image = core.PNMImage() image.read(img_file) assert image.is_valid() size_x = image.get_x_size() size_y = image.get_y_size() assert size_x != 0 assert size_y != 0 if self._size_x != 0: assert self._size_x == size_x if self._size_y != 0: assert self._size_y == size_y self._size_x = size_x self._size_y = size_y self._img_file = img_file assert not self._img_file.empty() self._frames = [] for row_idx in range(self._rows): for col_idx in range(self._cols): self._frames.append(SpriteCell(col_idx, row_idx)) # We need to find the power of two size for the another PNMImage # so that the texture thats loaded on the geometry won't have artifacts texture_size_x = self._next_size(self._size_x) texture_size_y = self._next_size(self._size_y) # The actual size of the texture in memory self._real_size_x = texture_size_x self._real_size_y = texture_size_y self._padded_img = core.PNMImage(texture_size_x, texture_size_y) if image.has_alpha: self._padded_img.alpha_fill(0) self._padded_img.blend_sub_image(image, 0, 0) image.clear() # The pixel sizes for each cell self._col_size = self._size_x / self._cols self._row_size = self._size_y / self._rows # How much padding the texture has self._padding_x = texture_size_x - self._size_x self._padding_y = texture_size_y - self._size_y # Set UV padding self._u_pad = float(self._padding_x / texture_size_x) self._v_pad = float(self._padding_y / texture_size_y) # The UV dimensions for each cell self._u_size = (1.0 - self._u_pad) / self._cols self._v_size = (1.0 - self._v_pad) / self._rows
def optimize_geom(gnode, gi): state = gnode.get_geom_state(gi) changed = False if gnode.get_geom(gi).bounds_type != core.BoundingVolume.BT_box: gnode.modify_geom(gi).bounds_type = core.BoundingVolume.BT_box changed = True tex_attrib = state.get_attrib(core.TextureAttrib) if not tex_attrib or tex_attrib.get_num_on_stages() == 0: # Nothing to optimize. return changed stage = tex_attrib.get_on_stage(0) tex = tex_attrib.get_on_texture(stage) if tex.wrap_u == core.SamplerState.WM_repeat: tex.wrap_u = core.SamplerState.WM_clamp changed = True if tex.wrap_v == core.SamplerState.WM_repeat: tex.wrap_v = core.SamplerState.WM_clamp changed = True img = core.PNMImage() img.set_color_space(core.CS_sRGB) tex.store(img) # Does the image have alpha? transp = state.get_attrib(core.TransparencyAttrib) if not img.has_alpha(): if transp and transp.mode != core.TransparencyAttrib.M_off: print(f"{tex.name}: turning off TransparencyAttrib") state = state.set_attrib( core.TransparencyAttrib.make(core.TransparencyAttrib.M_off)) gnode.set_geom_state(gi, state) return True else: # Nothing else to do. return changed # Crop the image. width, height = img.size crop_l = 0 for x in range(width): if any(img.get_alpha_val(x, y) > 0 for y in range(height)): crop_l = x break crop_r = width for x in reversed(range(crop_l, width)): if any(img.get_alpha_val(x, y) > 0 for y in range(height)): crop_r = x + 1 break crop_t = 0 for y in range(height): if any(img.get_alpha_val(x, y) > 0 for x in range(crop_l, crop_r)): crop_t = y break crop_b = height for y in reversed(range(crop_t, height)): if any(img.get_alpha_val(x, y) > 0 for x in range(crop_l, crop_r)): crop_b = y + 1 break # No cropping to be done. Is the image fully opaque, perhaps? if crop_l == 0 and crop_r == width and crop_t == 0 and crop_b == height: if is_image_fully_opaque(img): print(f"{tex.name}: fully opaque, removing alpha channel") img.remove_alpha() tex.load(img) tex.format = core.Texture.F_srgb tex.wrap_u = core.SamplerState.WM_clamp tex.wrap_v = core.SamplerState.WM_clamp tex.wrap_w = core.SamplerState.WM_clamp if transp and transp.mode != core.TransparencyAttrib.M_off: state = state.set_attrib( core.TransparencyAttrib.make( core.TransparencyAttrib.M_off)) gnode.set_geom_state(gi, state) return True # Premultiply alpha for higher-quality blending. transp = state.get_attrib(core.TransparencyAttrib) if transp and transp.mode == core.TransparencyAttrib.M_alpha: img.premultiply_alpha() prev_format = tex.format prev_sampler = core.SamplerState(tex.default_sampler) tex.load(img) tex.default_sampler = prev_sampler tex.format = prev_format # Check if this has binary alpha. if is_image_alpha_binary(img): print(f"{tex.name}: premultiplying alpha and setting to binary") state = state.set_attrib( core.TransparencyAttrib.make(core.TransparencyAttrib.M_binary)) else: print(f"{tex.name}: premultiplying alpha and setting to dual") #XXX there is no M_premultiplied_dual; this will have to suffice. state = state.set_attrib( core.TransparencyAttrib.make(core.TransparencyAttrib.M_dual)) gnode.set_geom_state(gi, state) changed = True # Make sure that the crop region is power-of-two, because why not. crop_w = crop_r - crop_l #pad_x = core.Texture.up_to_power_2(crop_w) - crop_w #pad_l = pad_x // 2 #pad_r = pad_x - pad_l #crop_l -= pad_l #crop_r += pad_r #if crop_l < 0: # crop_r += -crop_l # crop_l = 0 #crop_w = crop_r - crop_l #assert core.Texture.up_to_power_2(crop_w) == crop_w crop_h = crop_b - crop_t #pad_y = core.Texture.up_to_power_2(crop_h) - crop_h #pad_t = pad_y // 2 #pad_b = pad_y - pad_t #crop_t -= pad_t #crop_b += pad_b #crop_h = crop_b - crop_t #if crop_t < 0: # crop_b += -crop_t # crop_t = 0 #assert core.Texture.up_to_power_2(crop_h) == crop_h # Make sure the cropped region isn't bigger than the original image. if crop_w * crop_h >= width * height: print( f"{tex.name}: no need to crop, {width}×{height} is already its optimal size" ) return changed print( f"{tex.name}: cropping to a {crop_w}×{crop_h} region starting at {crop_l}×{crop_t}" ) new_img = core.PNMImage(crop_w, crop_h, img.num_channels, img.maxval, color_space=core.CS_sRGB) new_img.fill(0, 0, 0) if new_img.has_alpha(): new_img.alpha_fill(0) new_img.copy_sub_image(img, 0, 0, crop_l, crop_t, crop_w, crop_h) prev_sampler = core.SamplerState(tex.default_sampler) if is_image_fully_opaque(new_img): print(f"{tex.name}: fully opaque after crop, removing alpha channel") new_img.remove_alpha() tex.load(new_img) tex.format = core.Texture.F_srgb else: prev_format = tex.format tex.load(new_img) tex.format = prev_format tex.default_sampler = prev_sampler if crop_w < width: tex.wrap_u = core.SamplerState.WM_border_color elif tex.wrap_u == core.SamplerState.WM_repeat: tex.wrap_u = core.SamplerState.WM_clamp if crop_h < height: tex.wrap_v = core.SamplerState.WM_border_color elif tex.wrap_v == core.SamplerState.WM_repeat: tex.wrap_v = core.SamplerState.WM_clamp tex.border_color = (0, 0, 0, 0) assert tex.x_size == crop_w assert tex.y_size == crop_h # Now we need to either move the vertices or transform the UVs in order to # compensate for the cropped image. uv_pos = core.Vec2(crop_l / (width - 1.0), (height - crop_b) / (height - 1.0)) uv_scale = core.Vec2((crop_w - 1.0) / (width - 1.0), (crop_h - 1.0) / (height - 1.0)) vertex_data = gnode.modify_geom(gi).modify_vertex_data() uv_to_vtx = {} vtx_reader = core.GeomVertexReader(vertex_data, 'vertex') uv_reader = core.GeomVertexReader(vertex_data, stage.texcoord_name) while not vtx_reader.is_at_end() and not uv_reader.is_at_end(): uv = uv_reader.get_data2() vtx = core.LPoint3(vtx_reader.get_data3()) uv_to_vtx[tuple(uv)] = vtx vtx_reader = None uv_reader = None if (0, 0) in uv_to_vtx and (1, 1) in uv_to_vtx: # Crop the card itself, making it smaller, reducing overdraw. card_pos = uv_to_vtx[(0, 0)] card_size = uv_to_vtx[(1, 1)] - uv_to_vtx[(0, 0)] rewriter = core.GeomVertexRewriter(vertex_data, 'vertex') uv_reader = core.GeomVertexReader(vertex_data, stage.texcoord_name) while not rewriter.is_at_end() and not uv_reader.is_at_end(): vtx = rewriter.get_data3() uv = core.Point2(uv_reader.get_data2()) uv.componentwise_mult(uv_scale) uv += uv_pos rewriter.set_data3(uv[0] * card_size[0] + card_pos[0], uv[1] * card_size[1] + card_pos[1], vtx.z) rewriter = None # We can remove transparency if we cropped it to the opaque part. if tex.format == core.Texture.F_srgb: print("Removing transparency") state = state.set_attrib( core.TransparencyAttrib.make(core.TransparencyAttrib.M_off)) gnode.set_geom_state(gi, state) else: # Transform the UVs. rewriter = core.GeomVertexRewriter( gnode.modify_geom(gi).modify_vertex_data(), stage.get_texcoord_name()) while not rewriter.is_at_end(): uv = core.Point2(rewriter.get_data2()) uv -= uv_pos uv.x /= uv_scale.x uv.y /= uv_scale.y rewriter.set_data2(uv) rewriter = None return True
def OnPopupSize(self, **kwargs): #pylint: disable=invalid-name rect = kwargs['rect_out'] self.popup_pos = (rect[0], rect[1]) self.popup_img = p3d.PNMImage(rect[2], rect[3]) self.popup_img.add_alpha()
def __init__(self, texture): self.texture = texture self.popup_img = p3d.PNMImage(0, 0) self.popup_pos = [0, 0] self.popup_show = False
def create_ellipse_annulus_texture(angular_width, z_width, center_width, color, color_bg, color_annulus): # analogue to create_ellipse_window_texture: # # center_width gives the width of the center part # color gives the color of the center part # color_bg gives the color of the background # color_annulus gives the color of the annulus center_width_z = z_width / float( angular_width) * center_width # same dphi/dz ratio for the center precision = 0.2 image = pcore.PNMImage( 360 * 3, 260 * 2 ) # only 1 degree steps for the width of the window and 0.1 units steps for the height of the window #z_width = (angular_width/360. * 2 * math.pi*10) / 26 * (np.degrees(np.arctan(13/10.)) * 2) #z_width = np.radians(angular_width) * 10 # Kleinwinkelnaeherung / approximation for small angular widths #print z_width image.fill(color_bg / 255.) for i in range(min([360 * 3, int(angular_width) * 3])): for j in range(min([260 * 2, int(np.round(z_width / precision * 2))])): # big circle if (i - angular_width / 2. * 3)**2 / ( angular_width / 2. * 3)**2 + (j - z_width / precision / 2. * 2)**2 / ( z_width / precision / 2. * 2)**2 <= 1: image.setXelA(i, j, color_annulus / 255., color_annulus / 255., color_annulus / 255., 1) # center circle if (i - angular_width / 2. * 3)**2 / (center_width / 2. * 3)**2 + ( j - z_width / precision / 2. * 2)**2 / ( center_width_z / precision / 2. * 2)**2 <= 1: image.setXelA(i, j, color / 255., color / 255., color / 255., 1) #print "color annulu" #print color_annulus #print "color center" #print color # SHOW BORDERS OF THE LOOP FROM ABOVE #for i in range(0,360*3): # image.setXelA(i,0,color/255.,color/255.,color/255.,1) # image.setXelA(i,1,color/255.,color/255.,color/255.,1) # image.setXelA(i,2,color/255.,color/255.,color/255.,1) # image.setXelA(i,int(np.round(z_width/0.1*2))-1,color/255.,color/255.,color/255.,1) # image.setXelA(i,int(np.round(z_width/0.1*2))-2,color/255.,color/255.,color/255.,1) # image.setXelA(i,int(np.round(z_width/0.1*2))-3,color/255.,color/255.,color/255.,1) #for j in range(0,260*2): # image.setXelA(0,j,color/255.,color/255.,color/255.,1) # image.setXelA(1,j,color/255.,color/255.,color/255.,1) # image.setXelA(2,j,color/255.,color/255.,color/255.,1) # image.setXelA(int(angular_width)*3-1,j,color/255.,color/255.,color/255.,1) # image.setXelA(int(angular_width)*3-2,j,color/255.,color/255.,color/255.,1) # image.setXelA(int(angular_width)*3-3,j,color/255.,color/255.,color/255.,1) tex = pcore.Texture() tex.load(image) tex.setMagfilter(pcore.Texture.FTNearest) tex.setBorderColor( pcore.Vec4(color_bg / 255., color_bg / 255., color_bg / 255., 1)) tex.setWrapU(pcore.Texture.WM_border_color) tex.setWrapV(pcore.Texture.WM_border_color) tex.setAnisotropicDegree(16) return tex
def write_image(filename, channels): img = core.PNMImage(1, 1, channels) img.set_xel_a(0, 0, (0.0, 0.25, 0.5, 0.75)) assert img.write(filename)
def __init__(self): super().__init__(self) # MSAA just for making thinkgs look good self.render.set_antialias(p3d.AntialiasAttrib.M_multisample) # ShaderTerrainMesh used for terrain self.terrain_node = p3d.ShaderTerrainMesh() heightfield = self.loader.load_texture( '../../models/texture/terrain/terrain_height.png') self.terrain_node.heightfield = heightfield # self.terrain_node.target_triangle_width = 10.0 self.terrain_node.generate() self.terrain = self.render.attach_new_node(self.terrain_node) self.terrain.set_scale(512, 512, 100) self.terrain.set_pos(-256, -256, -30) self.terrain.set_shader( p3d.Shader.load(GLSL, 'shaders/terrain_v.glsl', 'shaders/terrain_f.glsl'), 1) # load terrain textures grass = self.loader.load_texture( '../../models/texture/terrain/grass_c.png', minfilter=FT_MIPMAP, magfilter=FT_LINEAR) rock = self.loader.load_texture( '../../models/texture/terrain/rock_c.png', minfilter=FT_MIPMAP, magfilter=FT_LINEAR) snow = self.loader.load_texture( '../../models/texture/terrain/snow_c.png', minfilter=FT_MIPMAP, magfilter=FT_LINEAR) attribute = self.loader.load_texture( '../../models/texture/terrain/terrain_atr.png') # make sure textures are sRGB if p3d.ConfigVariableBool('framebuffer-srgb').get_value(): grass.set_format(F_SRGB) rock.set_format(F_SRGB) snow.set_format(F_SRGB) attribute.set_format(F_SRGB) self.terrain.set_shader_input('grass_map', grass) self.terrain.set_shader_input('rock_map', rock) self.terrain.set_shader_input('snow_map', snow) self.terrain.set_shader_input('attribute_map', attribute) self.terrain.set_shader_input('camera', self.camera) # make the grass map more gpu friendly: grass_map = p3d.PNMImage() grass_map.read('../../models/texture/terrain/terrain_grass.png') grass_list = [] x_size = grass_map.get_read_x_size() y_size = grass_map.get_read_y_size() for x in range(x_size): for y in range(y_size): if grass_map.get_bright(x, y) > 0.5: # terrain_node.uv_to_world() will give as the position of the grass # but we need to flip the y because OpenGL UVs... # we also want to add a bit of random to avoid 'grass grid' uv_x = x / x_size uv_y = 1.0 - y / y_size uv_x += random.uniform(-0.001, 0.001) uv_y += random.uniform(-0.001, 0.001) uv_x = max(0.0, min(1.0, uv_x)) uv_y = max(0.0, min(1.0, uv_y)) grass_list.append(self.terrain_node.uv_to_world( uv_x, uv_y)) # pack the grass_list into a buffer_texture grass_buf_tex = p3d.Texture('texbuffer') grass_buf_tex.setup_buffer_texture( len(grass_list) + 1, p3d.Texture.T_float, p3d.Texture.F_rgb32, p3d.GeomEnums.UH_static) image = memoryview(grass_buf_tex.modify_ram_image()) for i, pos in enumerate(grass_list): off = i * 12 image[off:off + 12] = struct.pack('fff', pos[0], pos[1], pos[2]) # load the grass model grass_model = self.loader.load_model('../../models/grass') # fix texture for srgb if p3d.ConfigVariableBool('framebuffer-srgb').get_value(): for tex_stage in grass_model.find_all_texture_stages(): tex = grass_model.find_texture(tex_stage) if tex: tex.set_format(F_SRGBA) grass_model.set_texture(tex_stage, tex, 1) grass_model.set_shader( p3d.Shader.load(GLSL, 'shaders/grass_v.glsl', 'shaders/grass_f.glsl'), 1) grass_model.set_shader_input('grass_buf_tex', grass_buf_tex) grass_model.set_shader_input('clip_distance', 125.0) grass_model.set_instance_count(len(grass_list)) grass_model.reparent_to(self.render) # alpha testing will be done in the shader grass_model.set_transparency(p3d.TransparencyAttrib.M_none, 1) # set the bounds so it stays visible grass_model.node().set_bounds( p3d.BoundingBox((0, 0, 0), max(grass_list, key=itemgetter(1)))) grass_model.node().set_final(1) #make skybox self.sky_box = self.loader.load_model('../../models//box') self.sky_box.reparent_to(self.render) self.sky_box.set_scale(10) self.sky_box.set_shader( p3d.Shader.load(GLSL, 'shaders/skybox_v.glsl', 'shaders/skybox_f.glsl'), 1) self.sky_box.set_shader_input('blur', 0.0) self.sky_box.set_bin('background', 100) self.sky_box.set_depth_test(False) self.sky_box.set_depth_write(False) self.render.set_shader_input("camera", self.cam) self.render.set_shader_input( 'env_map', self.loader.load_texture( '../../models/texture/cubemap/qwantani.txo')) #add a task to update the skybox self.taskMgr.add(self.update, 'update')