def _createMapTextureCard(self):
        mapImage = PNMImage(MAP_RESOLUTION, MAP_RESOLUTION)
        mapImage.fill(*self._bgColor)
        fgColor = VBase4D(*self._fgColor)
        for x in range(self._mazeHeight):
            for y in range(self._mazeWidth):
                if self._mazeCollTable[y][x] == 1:
                    ax = float(x) / self._mazeWidth * MAP_RESOLUTION
                    invertedY = self._mazeHeight - 1 - y
                    ay = float(invertedY) / self._mazeHeight * MAP_RESOLUTION
                    self._drawSquare(mapImage, int(ax), int(ay), 10, fgColor)

        mapTexture = Texture('mapTexture')
        mapTexture.setupTexture(Texture.TT2dTexture, self._maskResolution,
                                self._maskResolution, 1, Texture.TUnsignedByte,
                                Texture.FRgba)
        mapTexture.setMinfilter(Texture.FTLinear)
        mapTexture.load(mapImage)
        mapTexture.setWrapU(Texture.WMClamp)
        mapTexture.setWrapV(Texture.WMClamp)
        mapImage.clear()
        del mapImage
        cm = CardMaker('map_cardMaker')
        cm.setFrame(-1.0, 1.0, -1.0, 1.0)
        map = self.attachNewNode(cm.generate())
        map.setTexture(mapTexture, 1)
        return map
 def setupBackgroundImage(self):    
   
   image_file = Filename(TestGameBase.__BACKGROUND_IMAGE_PATH__)
   
   # check if image can be loaded
   img_head = PNMImageHeader()
   if not img_head.readHeader(image_file ):
       raise IOError("PNMImageHeader could not read file %s. Try using absolute filepaths"%(image_file.c_str()))
       sys.exit()
       
   # Load the image with a PNMImage
   w = img_head.getXSize()
   h = img_head.getYSize()
   img = PNMImage(w,h)
   #img.alphaFill(0)
   img.read(image_file) 
   
   texture = Texture()        
   texture.setXSize(w)
   texture.setYSize(h)
   texture.setZSize(1)    
   texture.load(img)
   texture.setWrapU(Texture.WM_border_color) # gets rid of odd black edges around image
   texture.setWrapV(Texture.WM_border_color)
   texture.setBorderColor(LColor(0,0,0,0))
   
   # creating CardMaker to hold the texture
   cm = CardMaker('background')
   cm.setFrame(-0.5*w,0.5*w,-0.5*h,0.5*h)  # This configuration places the image's topleft corner at the origin (left, right, bottom, top)
   background_np = NodePath(cm.generate())            
   background_np.setTexture(texture)
   
   background_np.reparentTo(self.render)
   background_np.setPos(TestGameBase.__BACKGROUND_POSITION__)
   background_np.setScale(TestGameBase.__BACKGROUND_SCALE__)
Exemple #3
0
    def _createMapTextureCard(self):
        mapImage = PNMImage(MAP_RESOLUTION, MAP_RESOLUTION)
        mapImage.fill(*self._bgColor)
        fgColor = VBase4D(*self._fgColor)
        for x in xrange(self._mazeHeight):
            for y in xrange(self._mazeWidth):
                if self._mazeCollTable[y][x] == 1:
                    ax = float(x) / self._mazeWidth * MAP_RESOLUTION
                    invertedY = self._mazeHeight - 1 - y
                    ay = float(invertedY) / self._mazeHeight * MAP_RESOLUTION
                    self._drawSquare(mapImage, int(ax), int(ay), 10, fgColor)

        mapTexture = Texture('mapTexture')
        mapTexture.setupTexture(Texture.TT2dTexture, self._maskResolution, self._maskResolution, 1, Texture.TUnsignedByte, Texture.FRgba)
        mapTexture.setMinfilter(Texture.FTLinear)
        mapTexture.load(mapImage)
        mapTexture.setWrapU(Texture.WMClamp)
        mapTexture.setWrapV(Texture.WMClamp)
        mapImage.clear()
        del mapImage
        cm = CardMaker('map_cardMaker')
        cm.setFrame(-1.0, 1.0, -1.0, 1.0)
        map = self.attachNewNode(cm.generate())
        map.setTexture(mapTexture, 1)
        return map
 def makeTextureMap(self):
     '''Citymania function that generates and sets the 4 channel texture map'''
     self.colorTextures = []
     for terrain in self.terrains:
         terrain.getRoot().clearTexture()
         heightmap = terrain.heightfield()
         colormap = PNMImage(heightmap.getXSize()-1, heightmap.getYSize()-1)
         colormap.addAlpha()
         slopemap = terrain.makeSlopeImage()
         for x in range(0, colormap.getXSize()):
             for y in range(0, colormap.getYSize()):
                 # Else if statements used to make sure one channel is used per pixel
                 # Also for some optimization
                 # Snow. We do things funky here as alpha will be 1 already.
                 if heightmap.getGrayVal(x, y) < 200:
                     colormap.setAlpha(x, y, 0)
                 else:
                     colormap.setAlpha(x, y, 1)
                 # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data
                 if heightmap.getGrayVal(x,y) < 62:
                     colormap.setBlue(x, y, 1)
                 # Rock
                 elif slopemap.getGrayVal(x, y) > 170:
                     colormap.setRed(x, y, 1)
                 else:
                     colormap.setGreen(x, y, 1)
         colorTexture = Texture()
         colorTexture.load(colormap)
         colorTS = TextureStage('color')
         colorTS.setSort(0)
         colorTS.setPriority(1)
         self.colorTextures.append((colorTexture, colorTS))
    def __init__(self):
        load_prc_file_data("", """
            textures-power-2 none
            window-type offscreen
            win-size 100 100
            gl-coordinate-system default
            notify-level-display error
            print-pipe-types #f
        """)

        ShowBase.__init__(self)

        dest_tex = Texture()
        dest_tex.setup_2d_texture(2048, 2048, Texture.T_unsigned_byte, Texture.F_rgba8)
        cshader = Shader.load_compute(Shader.SL_GLSL, "grain.compute.glsl")
        node = NodePath("")
        node.set_shader(cshader)
        node.set_shader_input("DestTex", dest_tex)
        attr = node.get_attrib(ShaderAttrib)
        self.graphicsEngine.dispatch_compute(
            (2048 // 16, 2048 // 16, 1), attr, self.win.get_gsg())

        base.graphicsEngine.extract_texture_data(dest_tex, base.win.get_gsg())

        # Convert to single channel
        img = PNMImage(2048, 2048, 1, 255)
        dest_tex.store(img)
        img.set_num_channels(1)

        tex = Texture()
        tex.load(img)
        tex.write("grain.txo.pz")
Exemple #6
0
class VideoWall(object):
    res = 256
    def __init__(self, loader, parentNodePath):
        w = loader.loadModel("plane")
        w.reparentTo(parentNodePath)
        size = 6
        w.setPos(3.5, 15, size / 2 - 3)
        w.setColor(1,0,0)
        w.setHpr(0, 180, 0)
        w.setScale(size, 1, size / 1.33)
        w.setTwoSided(True)
        
        self.tx = Texture("video")
        self.tx.setup2dTexture(self.res, self.res, Texture.TUnsignedByte, Texture.FRgb8)

        # this makes some important setup call
        self.tx.load(PNMImage(self.res, self.res))

        w.setTexture(self.tx)

        m = Material("vid")
        m.setTwoside(True)
        m.setEmission(VBase4(1,1,1,1))
        w.setMaterial(m)

        w.setFogOff()

    def updateFromPixbuf(self, pb):
        scaled = pb.scale_simple(self.res, self.res, gtk.gdk.INTERP_BILINEAR)

        # about 3ms
        n = numpy.fromstring(scaled.get_pixels(), dtype=numpy.uint8).reshape((-1,3))
        flipped = numpy.fliplr(n).tostring()
        
        self.tx.setRamImage(flipped)
Exemple #7
0
    def __init__(self):
        load_prc_file_data(
            "", """
            textures-power-2 none
            window-type offscreen
            win-size 100 100
            gl-coordinate-system default
            notify-level-display error
            print-pipe-types #f
        """)

        ShowBase.__init__(self)

        dest_tex = Texture()
        dest_tex.setup_2d_texture(2048, 2048, Texture.T_unsigned_byte,
                                  Texture.F_rgba8)
        cshader = Shader.load_compute(Shader.SL_GLSL, "grain.compute.glsl")
        node = NodePath("")
        node.set_shader(cshader)
        node.set_shader_input("DestTex", dest_tex)
        attr = node.get_attrib(ShaderAttrib)
        self.graphicsEngine.dispatch_compute((2048 // 16, 2048 // 16, 1), attr,
                                             self.win.get_gsg())

        base.graphicsEngine.extract_texture_data(dest_tex, base.win.get_gsg())

        # Convert to single channel
        img = PNMImage(2048, 2048, 1, 255)
        dest_tex.store(img)
        img.set_num_channels(1)

        tex = Texture()
        tex.load(img)
        tex.write("grain.txo.pz")
 def makeTextureMap(self):
     '''Citymania function that generates and sets the 4 channel texture map'''
     self.colorTextures = []
     for terrain in self.terrains:
         terrain.getRoot().clearTexture()
         heightmap = terrain.heightfield()
         colormap = PNMImage(heightmap.getXSize() - 1,
                             heightmap.getYSize() - 1)
         colormap.addAlpha()
         slopemap = terrain.makeSlopeImage()
         for x in range(0, colormap.getXSize()):
             for y in range(0, colormap.getYSize()):
                 # Else if statements used to make sure one channel is used per pixel
                 # Also for some optimization
                 # Snow. We do things funky here as alpha will be 1 already.
                 if heightmap.getGrayVal(x, y) < 200:
                     colormap.setAlpha(x, y, 0)
                 else:
                     colormap.setAlpha(x, y, 1)
                 # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data
                 if heightmap.getGrayVal(x, y) < 62:
                     colormap.setBlue(x, y, 1)
                 # Rock
                 elif slopemap.getGrayVal(x, y) > 170:
                     colormap.setRed(x, y, 1)
                 else:
                     colormap.setGreen(x, y, 1)
         colorTexture = Texture()
         colorTexture.load(colormap)
         colorTS = TextureStage('color')
         colorTS.setSort(0)
         colorTS.setPriority(1)
         self.colorTextures.append((colorTexture, colorTS))
class MatPlotLibDemo(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.setFrameRateMeter(True)

        m = loader.loadModel("models/smiley")
        m.reparent_to(render)
        m.set_pos(0, 5, 0)

        x_size, y_size = 640, 480
        xy_ratio = float(y_size) / float(x_size)
        self.plot = Plot(x_size, y_size)

        self.input_img = PNMImage(x_size, y_size)
        self.input_tex = Texture()
        self.input_tex.load(self.input_img)

        self.card = CardMaker('pygame_card')
        self.card.setUvRange(Point2(0, 1),  # ll
                             Point2(1, 1),  # lr
                             Point2(1, 0),  # ur
                             Point2(0, 0))  # ul
        self.screen = render.attach_new_node(self.card.generate())
        self.screen.set_scale(1, 1, xy_ratio)
        self.screen.set_pos(-0.5, 2, -0.5 * xy_ratio)
        self.screen.setTexture(self.input_tex)
        # FIXME: Apparently mpl's print_to_buffer() doesn't write
        # alpha values properly. 
        self.screen.setTransparency(TransparencyAttrib.MAlpha)

        taskMgr.add(self.update, "update plot")

    def update(self, task):
        self.input_tex.set_ram_image_as(self.plot.draw(), "RGBA")
        return task.cont
Exemple #10
0
def to_textures(
    images: list,
    name_mask: str = None,
    image_sizes: LPoint2 = None,
    texture_filter: SamplerState = None,
) -> list:
    """Convert provided list of PNMImage objects into Texture objects"""
    # doing it like that to enable ez override in get_textures()
    name_mask = name_mask or "sprite"
    textures = []

    # without name mask, this may seem like it returns empty sequence, but its not
    for num, item in enumerate(images):
        # this is how we turn image into texture
        texture = Texture(f"{name_mask}_{num}")
        texture.load(item)
        if texture_filter is not None:
            texture.set_magfilter(texture_filter)
            texture.set_minfilter(texture_filter)
        if image_sizes:
            texture.set_orig_file_size(*image_sizes, 1)
        textures.append(texture)

    log.debug(f"Got following textures: {textures}")
    return textures
 def cardmaker_debug(self):
     for node in render2d.find_all_matches("pfm"):
         node.remove_node()
     for text in base.a2dBottomLeft.find_all_matches("*"):
         text.remove_node()
     width = 0.2  # render2d coordinates range: [-1..1]
     # Pseudo-normalize our PfmFile for better contrast.
     normalized_pfm = PfmFile(self.RotorPFM)
     max_p = LVector3()
     normalized_pfm.calc_min_max(LVector3(), max_p)
     normalized_pfm *= 1.0 / max_p.x
     # Put it in a texture
     tex = Texture()
     tex.load(normalized_pfm)
     # Apply the texture to a quad and put it in the lower left corner.
     cm = CardMaker("pfm")
     cm.set_frame(0, width, 0,
         width / normalized_pfm.get_x_size() * normalized_pfm.get_y_size())
     card = base.render2d.attach_new_node(cm.generate())
     card.set_pos(-1, 0, -1)        
     card.set_texture(tex)
     # Display max value text
     self.genLabelText(-3,
                       "Max value: {:.3f} == {:.2f}m".format(max_p.x,
                         max_p.x * self.terrain_scale.z),
                       parent="a2dBottomLeft")
Exemple #12
0
 def loadFlatQuad(self, fullFilename):
     cm = CardMaker('cm-%s' % fullFilename)
     cm.setColor(1.0, 1.0, 1.0, 1.0)
     aspect = base.camLens.getAspectRatio()
     htmlWidth = 2.0 * aspect * WEB_WIDTH_PIXELS / float(WIN_WIDTH)
     htmlHeight = 2.0 * float(WEB_HEIGHT_PIXELS) / float(WIN_HEIGHT)
     cm.setFrame(-htmlWidth / 2.0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0)
     bottomRightX = WEB_WIDTH_PIXELS / float(WEB_WIDTH + 1)
     bottomRightY = WEB_HEIGHT_PIXELS / float(WEB_HEIGHT + 1)
     cm.setUvRange(Point2(0, 1 - bottomRightY), Point2(bottomRightX, 1))
     card = cm.generate()
     quad = NodePath(card)
     jpgFile = PNMImage(WEB_WIDTH, WEB_HEIGHT)
     smallerJpgFile = PNMImage()
     readFile = smallerJpgFile.read(Filename(fullFilename))
     if readFile:
         jpgFile.copySubImage(smallerJpgFile, 0, 0)
         guiTex = Texture('guiTex')
         guiTex.setupTexture(Texture.TT2dTexture, WEB_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba)
         guiTex.setMinfilter(Texture.FTLinear)
         guiTex.load(jpgFile)
         guiTex.setWrapU(Texture.WMClamp)
         guiTex.setWrapV(Texture.WMClamp)
         ts = TextureStage('webTS')
         quad.setTexture(ts, guiTex)
         quad.setTransparency(0)
         quad.setTwoSided(True)
         quad.setColor(1.0, 1.0, 1.0, 1.0)
         result = quad
     else:
         result = None
     Texture.setTexturesPower2(1)
     return result
 def loadFlatQuad(self, fullFilename):
     cm = CardMaker('cm-%s' % fullFilename)
     cm.setColor(1.0, 1.0, 1.0, 1.0)
     aspect = base.camLens.getAspectRatio()
     htmlWidth = 2.0 * aspect * WEB_WIDTH_PIXELS / float(WIN_WIDTH)
     htmlHeight = 2.0 * float(WEB_HEIGHT_PIXELS) / float(WIN_HEIGHT)
     cm.setFrame(-htmlWidth / 2.0, htmlWidth / 2.0, -htmlHeight / 2.0,
                 htmlHeight / 2.0)
     bottomRightX = WEB_WIDTH_PIXELS / float(WEB_WIDTH + 1)
     bottomRightY = WEB_HEIGHT_PIXELS / float(WEB_HEIGHT + 1)
     cm.setUvRange(Point2(0, 1 - bottomRightY), Point2(bottomRightX, 1))
     card = cm.generate()
     quad = NodePath(card)
     jpgFile = PNMImage(WEB_WIDTH, WEB_HEIGHT)
     smallerJpgFile = PNMImage()
     readFile = smallerJpgFile.read(Filename(fullFilename))
     if readFile:
         jpgFile.copySubImage(smallerJpgFile, 0, 0)
         guiTex = Texture('guiTex')
         guiTex.setupTexture(Texture.TT2dTexture, WEB_WIDTH, WEB_HEIGHT, 1,
                             Texture.TUnsignedByte, Texture.FRgba)
         guiTex.setMinfilter(Texture.FTLinear)
         guiTex.load(jpgFile)
         guiTex.setWrapU(Texture.WMClamp)
         guiTex.setWrapV(Texture.WMClamp)
         ts = TextureStage('webTS')
         quad.setTexture(ts, guiTex)
         quad.setTransparency(0)
         quad.setTwoSided(True)
         quad.setColor(1.0, 1.0, 1.0, 1.0)
         result = quad
     else:
         result = None
     Texture.setTexturesPower2(1)
     return result
Exemple #14
0
    def __chooseHue(self):
        for x in xrange(self.image.getXSize()):
            for y in xrange(self.image.getYSize()):
                self.image.setXel(x, y, colorsys.hsv_to_rgb(self.slider['value'], x / 100.0 + self.minSat, y / 100.0 + self.minVal))

        texture = Texture()
        texture.load(self.image)
        self.button['image'] = texture
 def _load_noise_tex(self):
     """ Loads the default 4x4 noise tex """
     random.seed(42)
     img = PNMImage(4, 4, 3)
     for x in range(16):
         img.set_xel(x%4, x//4, random.random(), random.random(), random.random())
     tex = Texture("Random4x4")
     tex.load(img)
     self._pipeline.stage_mgr.add_input("Noise4x4", tex)
Exemple #16
0
    def new(size, color=(255,255,255)):
        img = PNMImage(*size)
        if len(color) == 4:
            img.addAlpha()

        img.fill(*color)
        panda_tex = PandaTexture('texture')
        panda_tex.load(img)
        return Texture(panda_tex)
Exemple #17
0
 def create_noise_textures(self):
     # Always generate the same random textures
     seed(42)
     img = PNMImage(4, 4, 3)
     for x in range(4):
         for y in range(4):
             img.set_xel(x, y, random(), random(), random())
     tex = Texture("Rand4x4")
     tex.load(img)
     self._target.set_shader_input("Noise4x4", tex)
Exemple #18
0
 def __apply_Textures(self, recipe, tex_dict):
     for i, ter_dict in enumerate(recipe['terrains']):
         tex_img = PNMImage()
         tex_img.read(Filename("{}/tex/{}".format(recipe['planet_path'], ter_dict['texture'])))
         tex = Texture()
         tex.load(tex_img)
         tex.setMinfilter(Texture.FTLinear)
         ts = TextureStage(str(i))
         ts.setSort(i)
         self.NP.setTexture(ts, tex, i*10)
Exemple #19
0
 def __apply_Textures(self, recipe, tex_dict):
     for i, ter_dict in enumerate(recipe['terrains']):
         tex_img = PNMImage()
         tex_img.read(Filename("{}/tex/{}".format(recipe['planet_path'], ter_dict['texture'])))
         tex = Texture()
         tex.load(tex_img)
         tex.setMinfilter(Texture.FTLinear)
         ts = TextureStage(str(i))
         ts.setSort(i)
         self.NP.setTexture(ts, tex, i*10)
Exemple #20
0
def getTextureFromImage(pnmImage):
    print("myImage.getNumChannels(): ", pnmImage.getNumChannels())
    print("myImage.getXSize(): ", pnmImage.getXSize())
    print("myImage.getYSize(): ", pnmImage.getYSize())
    print("myImage.hasAlpha(): ", pnmImage.hasAlpha())

    # assign the PNMImage to a Texture (load PNMImage to Texture, opposite of store)
    myTexture = Texture()
    myTexture.load(pnmImage)
    return myTexture
Exemple #21
0
 def setOwnerTextures(self):
     self.ownerview = True
     root = self.terrain.getRoot()
     root.clearShader()
     root.clearTexture()
     cityTexture = Texture()
     cityTexture.load(self.citymap)
     cityTS = TextureStage('citymap')
     cityTS.setSort(0)
     root.setTexture( self.gridTS, self.gridTexture ) 
     root.setTexScale(self.gridTS, self.terrain.xchunks, self.terrain.ychunks)
     root.setTexture(cityTS, cityTexture, 1)
Exemple #22
0
 def setOwnerTextures(self):
     self.ownerview = True
     root = self.terrain.getRoot()
     root.clearShader()
     root.clearTexture()
     cityTexture = Texture()
     cityTexture.load(self.citymap)
     cityTS = TextureStage('citymap')
     cityTS.setSort(0)
     root.setTexture(self.gridTS, self.gridTexture)
     root.setTexScale(self.gridTS, self.terrain.xchunks,
                      self.terrain.ychunks)
     root.setTexture(cityTS, cityTexture, 1)
Exemple #23
0
 def __get_Texture(self, ref_img):
     # Convert ref_img into texture.
     with TimeIt() as prep_timer:
         ref_tex = Texture()
         # Ensure ref image has an alpha channel.
         if not ref_img.hasAlpha():
             ref_img.addAlpha()
             ref_img.alphaFill(1.0)
         # Load tex and set format
         ref_tex.load(ref_img)
         ref_tex.setFormat(self.img_format)
     self.prepare_time += round(prep_timer.total_time, 3)
     return ref_tex
Exemple #24
0
 def __Call(self, func_name, **kwargs):
     """Receive python call and redirect request to relevant
     function in image shader library; return modified image."""
     
     # Copy self.__Lines (need to keep orig for further calls) and
     # add "#define" statement to top to trigger compilation of
     # relevant "#ifdef/def" function block in shader.
     
     lines = list(self.__LINES)
     lines.insert(2, "#define {}".format(func_name))
     
     # Assemble lines into shader str and compile.
     shader_str = "".join(lines)
     self.__NP.setShader(Shader.makeCompute(Shader.SL_GLSL, shader_str))
     
     # Set block size from workgroup size.
     block_x = int(self.x_size/self.workgroup_size.x)
     block_y = int(self.y_size/self.workgroup_size.y)
     block_z = int(self.z_size/self.workgroup_size.z)
     block_size = LVector3i(block_x,block_y,block_z)
     
     # Create mod_tex for GPU.
     with TimeIt() as prep_timer:
         mod_img = PNMImage(self.x_size, self.y_size, 4)
         mod_tex = Texture()
         mod_tex.load(mod_img)
         mod_tex.setMinfilter(Texture.FTLinear)
         mod_tex.setFormat(self.img_format)
     self.prepare_time += prep_timer.total_time
     
     # Pass textures to shader.
     self.__NP.setShaderInput("ref_tex", self.__ref_tex)
     self.__NP.setShaderInput("mod_tex", mod_tex)
     
     # Set any additional required inputs for this function.
     for input_name, input_val in list(kwargs.items()):
         if type(input_val) == PNMImage:
             input_val = self.__get_Texture(input_val)
         self.__NP.setShaderInput(input_name, input_val)
     
     # Call function in shader library.
     shader_attrib = self.__NP.getAttrib(ShaderAttrib)
     with TimeIt() as proc_timer:
         base.graphicsEngine.dispatch_compute(block_size, shader_attrib, self.__gsg)
     self.process_time += proc_timer.total_time
     
     # Extract modified texture from GPU.
     with TimeIt() as extract_timer: 
         base.graphicsEngine.extractTextureData(mod_tex, self.__gsg)
     self.extract_time += extract_timer.total_time
     return mod_tex
Exemple #25
0
def make_star(name='star', scale=1, color=Vec3(1), texture_size=64, debug=False):
    card_maker = CardMaker(name)
    card_maker.set_frame(-1, 1, -1, 1)
    node_path = NodePath(name)
    node = card_maker.generate()
    final_node_path = node_path.attach_new_node(node)
    final_node_path.set_billboard_point_eye()
    from panda3d.core import Filename
    shaders = Shader.load(Shader.SL_GLSL,
                          Filename('Shader/Star/vertex.glsl'),
                          Filename('Shader/Star/fragment.glsl'),
                          Filename(''),
                          Filename(''),
                          Filename(''))
    if not shaders:
        print("WARNING. STAR SHADER FAILED TO LOAD", type(shaders))
    else:
        final_node_path.set_shader_input('cameraSpherePos', 1, 1, 1)
        final_node_path.set_shader_input('sphereRadius', 1.0)
        final_node_path.set_shader_input('myCamera', base.camera)
        final_node_path.set_shader(shaders)
        final_node_path.set_shader_input('blackbody', color)
    material = Material()
    material.set_emission(VBase4(color, 1.0))
    final_node_path.set_material(material)
    xn = PerlinNoise3(0.5, 0.5, 0.5)
    #yn = PerlinNoise3(0.5, 0.5, 0.5)
    texture = Texture('star')
    texture.setup_3d_texture()
    for z in range(texture_size):
        p = PNMImage(texture_size, texture_size)
        for y in range(texture_size):
            for x in range(texture_size):
                p.set_gray(x, y, abs(xn.noise(x, y, z)))
        texture.load(p, z, 0)
    diffuse = texture
    diffuse.setMinfilter(Texture.FTLinearMipmapLinear)
    diffuse.setAnisotropicDegree(4)
    final_node_path.set_texture(diffuse)
    normal = sandbox.base.loader.loadTexture('data/empty_textures/empty_normal.png')
    normalts = TextureStage('normalts')
    final_node_path.set_texture(normalts, normal)
    specular = sandbox.base.loader.loadTexture('data/empty_textures/empty_specular.png')
    spects = TextureStage('spects')
    final_node_path.set_texture(spects, specular)
    roughness = sandbox.base.loader.loadTexture('data/empty_textures/empty_roughness.png')
    roughts= TextureStage('roughts')
    final_node_path.set_texture(roughts, roughness)
    return final_node_path
Exemple #26
0
def create_texture(image: Image) -> Texture:
    """Create a Panda3D Texture from a PIL Image."""
    bytes_io = BytesIO()
    image.save(bytes_io, format='PNG')
    bytes_io.seek(0)
    stream = StringStream()
    stream.set_data(bytes_io.read())
    bytes_io.close()
    pnm_image = PNMImage()
    pnm_image.read(stream)
    stream.clear_data()
    texture = Texture()
    texture.load(pnm_image)
    pnm_image.clear()
    return texture
Exemple #27
0
 def apply(self, shape, owner):
     if self.texture is None:
         if self.image is None:
             self.image = self.sprite.generate()
         texture = Texture()
         texture.load(self.image)
         self.texture = TransparentTexture(DirectTextureSource(texture), blend=TransparencyBlend.TB_PremultipliedAlpha)
         self.texture.set_tex_matrix(False)
     shape.instance.setTexGen(TextureStage.getDefault(), TexGenAttrib.MPointSprite)
     self.texture.apply(shape)
     shape.instance.set_depth_write(False)
     if self.background is not None:
         shape.instance.setBin('background', settings.deep_space_depth)
     owner.shader.apply(shape, self)
     shape.instance_ready = True
Exemple #28
0
class ZMap(DirectObject):
    COLORS = [
        VBase3D(0.7, 0.7, 0.9),  # AIR
        VBase3D(0.4, 0.5, 0.1),  # DIRT
        VBase3D(0.6, 0.6, 0.6)  # STONE
    ]

    def __init__(self, world, app):
        self.world = world

        self.image = PNMImage(self.world.width, 256)

        for z in self.world.zlevels():
            for x in range(self.world.height):
                mix = sum([
                    ZMap.COLORS[self.world.get_block(x, y, z).substance]
                    for y in range(self.world.height)
                ], VBase3D(0.0))
                color_block = mix / float(self.world.height)
                #print(color_block)
                #self.image.setXel(int(x), int(z), mix / float(self.world.height))
                self.image.setXel(
                    int(x), int(z),
                    LRGBColorf(color_block[0], color_block[1], color_block[2]))

        self.texture = Texture()
        self.texture.load(self.image)
        self.texture.setMagfilter(Texture.FTNearest)
        self.texture.setMinfilter(Texture.FTNearest)

        cm = CardMaker('zmap')
        cm.setFrame(0.95, 1, -1, 1)
        cm.setUvRange(Point2(1.0, 1.0),
                      Point2(0.0, 1.0 - self.world.depth / 256.0))
        self.zcard = app.render2d.attachNewNode(cm.generate())
        self.zcard.setTexture(self.texture)

        cm = CardMaker('zpointer')
        cm.setFrame(0, 0.05, 0, 1.0 / self.world.depth)
        self.zpointer = app.render2d.attachNewNode(cm.generate())
        self.zpointer.setColorScale(1.0, 0.0, 0.0, 0.4)

        self.accept('slice-changed', self.slice_changed)

    def slice_changed(self, slice, explore):
        self.zpointer.setPos(0.95, 0.0, slice * 2.0 / self.world.depth - 1.0)
Exemple #29
0
 def do_load_texture_array(self, textures):
     tex = Texture()
     tex.setup_2d_texture_array(len(textures))
     for (page, texture) in enumerate(textures):
         filename = texture.source.texture_filename(None)
         if filename is not None:
             panda_filename = Filename.from_os_specific(filename)
             tex.read(fullpath=panda_filename,
                      z=page,
                      n=0,
                      read_pages=False,
                      read_mipmaps=False)
         else:
             print("Could not find", texture.source.texture_name(None))
             image = texture.create_default_image()
             tex.load(image, z=page, n=0)
     return tex
Exemple #30
0
class GenPointSprite(PointObject):
    def __init__(self, size=64):
        self.size = size
        self.half_size = size / 2.0
        self.texture = None
        self.image = None

    def generate(self):
        return None

    def apply(self, instance):
        if self.texture is None:
            if self.image is None:
                self.image = self.generate()
            self.texture = Texture()
            self.texture.load(self.image)
        instance.setTexGen(TextureStage.getDefault(), TexGenAttrib.MPointSprite)
        instance.setTransparency(TransparencyAttrib.MAlpha, 1)
        instance.setTexture(TextureStage('ts'), self.texture, 1)
def make_star(name='star', scale=1, color=Vec3(1), texture_size=64, debug=False):
    card_maker = CardMaker(name)
    card_maker.set_frame(-1, 1, -1, 1)
    node_path = NodePath(name)
    node = card_maker.generate()
    final_node_path = node_path.attach_new_node(node)
    final_node_path.set_billboard_point_eye()
    shaders = Shader.load(Shader.SLGLSL,
                          'Shader/Star/vertex.glsl',
                          'Shader/Star/fragment.glsl')
    final_node_path.set_shader_input(b'cameraSpherePos', 1, 1, 1)
    final_node_path.set_shader_input(b'sphereRadius', 1.0)
    final_node_path.set_shader_input(b'myCamera', base.camera)
    final_node_path.set_shader(shaders)
    final_node_path.set_shader_input(b'blackbody', color)
    material = Material()
    material.set_emission(VBase4(color, 1.0))
    final_node_path.set_material(material)
    xn = PerlinNoise3(0.5, 0.5, 0.5)
    #yn = PerlinNoise3(0.5, 0.5, 0.5)
    texture = Texture('star')
    texture.setup_3d_texture()
    for z in range(texture_size):
        p = PNMImage(texture_size, texture_size)
        for y in range(texture_size):
            for x in range(texture_size):
                p.set_gray(x, y, abs(xn.noise(x, y, z)))
        texture.load(p, z, 0)
    diffuse = texture
    diffuse.setMinfilter(Texture.FTLinearMipmapLinear)
    diffuse.setAnisotropicDegree(4)
    final_node_path.set_texture(diffuse)
    normal = base.loader.loadTexture('Data/Textures/EmptyNormalTexture.png')
    normalts = TextureStage('normalts')
    final_node_path.set_texture(normalts, normal)
    specular = base.loader.loadTexture('Data/Textures/EmptySpecularTexture.png')
    spects = TextureStage('spects')
    final_node_path.set_texture(spects, specular)
    roughness = base.loader.loadTexture('Data/Textures/EmptyRoughnessTexture.png')
    roughts= TextureStage('roughts')
    final_node_path.set_texture(roughts, roughness)
    return final_node_path
Exemple #32
0
class TerrainNormalMap(TextureSource):
    cached = True

    def __init__(self, terrain, radius, height_scale):
        TextureSource.__init__(self)
        self.terrain = terrain
        self.loaded = False
        self.texture = None
        perimeter = 2.0 * pi * radius
        self.x_scale = (terrain.width / perimeter) * height_scale
        self.y_scale = (terrain.height / perimeter) * height_scale

    def load(self, patch, grayscale=False):
        if not self.loaded:
            image = self.terrain.make_terrain_normal(self.x_scale,
                                                     self.y_scale)
            self.texture = Texture()
            self.texture.load(image)
            self.loaded = True
        return (self.texture, 0, 0)
Exemple #33
0
def textureFromData(image_data, filename=""):
    tex = None

    if image_data:
        myTexture = Texture()

        myImage = PNMImage()
        success = myImage.read(StringStream(image_data), filename)

        if success == 1:
            #PNMImage can handle most texture formats
            myTexture.load(myImage)
        else:
            #Except for DDS, which PNMImage.read will return 0, so try to load as DDS
            success = myTexture.readDds(StringStream(image_data))

        if success != 0:
            tex = myTexture
            tex.setMinfilter(Texture.FTLinearMipmapLinear)

    return tex
def textureFromData(image_data, filename=""):
    tex = None
    
    if image_data:
        myTexture = Texture()
        
        myImage = PNMImage()
        success = myImage.read(StringStream(image_data), filename)
        
        if success == 1:
            #PNMImage can handle most texture formats
            myTexture.load(myImage)
        else:
            #Except for DDS, which PNMImage.read will return 0, so try to load as DDS
            success = myTexture.readDds(StringStream(image_data))
            
        if success != 0:
            tex = myTexture
            tex.setMinfilter(Texture.FTLinearMipmapLinear)
            
    return tex
class PygameCard(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.game = Game()
        self.camLens.setFov(120)
        self.input_img = PNMImage(self.game.res[0], self.game.res[1])
        self.input_tex = Texture()
        self.input_tex.load(self.input_img)

        self.card = CardMaker('pygame_card')
        self.screen = render.attach_new_node(self.card.generate())
        self.screen.setPos(-0.5,2,-0.5)
        self.screen.setTexture(self.input_tex)

        self.game_ram_image = self.game.surface.get_view("0")
        taskMgr.add(self.update, "update pygame_card")

    def update(self, task):
        self.game.update()
        self.input_tex.set_ram_image_as(self.game_ram_image, "RGBA")
        return task.cont
Exemple #36
0
class CameraTexture:
    def __init__(self, pipe=PIPE_FILE):
        self.tex = Texture("CameraTexture")
        self.pipe = pipe
        self.redis = Redis()
        self.redis.delete("camera-lock")
        self.image = None
        self.thread = thread.start_new_thread(self.readImage, ())

    def readImage(self):
        while True:
            with self.redis.lock("camera-lock"):
                newImage = PNMImage(self.pipe)
                self.image = newImage
            time.sleep(0.06)

    def update(self):
        if self.image:
            self.tex.load(self.image)

    def getTexture(self):
        return self.tex
Exemple #37
0
class PygameCard(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.game = Game()
        self.camLens.setFov(120)
        self.input_img = PNMImage(self.game.res[0], self.game.res[1])
        self.input_tex = Texture()
        self.input_tex.load(self.input_img)

        self.card = CardMaker('pygame_card')
        self.screen = render.attach_new_node(self.card.generate())
        self.screen.setPos(-0.5, 2, -0.5)
        self.screen.setTexture(self.input_tex)

        self.game_ram_image = self.game.surface.get_view("0")
        taskMgr.add(self.update, "update pygame_card")

    def update(self, task):
        self.game.update()
        self.input_tex.set_ram_image_as(self.game_ram_image, "RGBA")
        return task.cont
Exemple #38
0
class VideoWall(object):
    res = 256

    def __init__(self, loader, parentNodePath):
        w = loader.loadModel("plane")
        w.reparentTo(parentNodePath)
        size = 6
        w.setPos(3.5, 15, size / 2 - 3)
        w.setColor(1, 0, 0)
        w.setHpr(0, 180, 0)
        w.setScale(size, 1, size / 1.33)
        w.setTwoSided(True)

        self.tx = Texture("video")
        self.tx.setup2dTexture(self.res, self.res, Texture.TUnsignedByte,
                               Texture.FRgb8)

        # this makes some important setup call
        self.tx.load(PNMImage(self.res, self.res))

        w.setTexture(self.tx)

        m = Material("vid")
        m.setTwoside(True)
        m.setEmission(VBase4(1, 1, 1, 1))
        w.setMaterial(m)

        w.setFogOff()

    def updateFromPixbuf(self, pb):
        scaled = pb.scale_simple(self.res, self.res, gtk.gdk.INTERP_BILINEAR)

        # about 3ms
        n = numpy.fromstring(scaled.get_pixels(), dtype=numpy.uint8).reshape(
            (-1, 3))
        flipped = numpy.fliplr(n).tostring()

        self.tx.setRamImage(flipped)
  def createSequenceNode(self,name,img,cols,rows,scale_x,scale_y,frame_rate):
    
    seq = SequenceNode(name)
    w = int(img.getXSize()/cols)
    h = int(img.getYSize()/rows)

    counter = 0
    for i in range(0,cols):
      for j in range(0,rows):
        sub_img = PNMImage(w,h)
        sub_img.addAlpha()
        sub_img.alphaFill(0)
        sub_img.fill(1,1,1)
        sub_img.copySubImage(img ,0 ,0 ,i*w ,j*h ,w ,h)

        # Load the image onto the texture
        texture = Texture()        
        texture.setXSize(w)
        texture.setYSize(h)
        texture.setZSize(1)    
        texture.load(sub_img)
        texture.setWrapU(Texture.WM_border_color) # gets rid of odd black edges around image
        texture.setWrapV(Texture.WM_border_color)
        texture.setBorderColor(LColor(0,0,0,0))

        cm = CardMaker(name + '_' + str(counter))
        cm.setFrame(-0.5*scale_x,0.5*scale_x,-0.5*scale_y,0.5*scale_y)
        card = NodePath(cm.generate())
        seq.addChild(card.node(),counter)
        card.setTexture(texture)
        sub_img.clear()
        counter+=1
    
    seq.setFrameRate(frame_rate)
    print "Sequence Node %s contains %i frames of size %s"%(name,seq.getNumFrames(),str((w,h)))
    return seq   
class MatPlotLibDemo(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.setFrameRateMeter(True)

        m = loader.loadModel("models/smiley")
        m.reparent_to(render)
        m.set_pos(0, 5, 0)

        x_size, y_size = 640, 480
        xy_ratio = float(y_size) / float(x_size)
        self.plot = Plot(x_size, y_size)

        self.input_img = PNMImage(x_size, y_size)
        self.input_tex = Texture()
        self.input_tex.load(self.input_img)

        self.card = CardMaker('pygame_card')
        self.card.setUvRange(
            Point2(0, 1),  # ll
            Point2(1, 1),  # lr
            Point2(1, 0),  # ur
            Point2(0, 0))  # ul
        self.screen = render.attach_new_node(self.card.generate())
        self.screen.set_scale(1, 1, xy_ratio)
        self.screen.set_pos(-0.5, 2, -0.5 * xy_ratio)
        self.screen.setTexture(self.input_tex)
        # FIXME: Apparently mpl's print_to_buffer() doesn't write
        # alpha values properly.
        self.screen.setTransparency(TransparencyAttrib.MAlpha)

        taskMgr.add(self.update, "update plot")

    def update(self, task):
        self.input_tex.set_ram_image_as(self.plot.draw(), "RGBA")
        return task.cont
Exemple #41
0
 def mapSelection(self, maps):
     """
     Generate a window with list and thumbnails of region maps availiable.
     Provide two options, load map or, if there is no local version, save local version
     """
     self.mapDialog = DirectWindow(title = "Select Map")
     mapList = []
     m = [""]
     import base64
     for mapName in maps:
         heightmap = maps[mapName]
         image = PNMImage()
         image.read(StringStream(heightmap))      
         thumbnail = PNMImage(64, 64)
         thumbnail.gaussianFilterFrom(1, image)
         heightTexture = Texture()
         heightTexture.load(image)
         label = DirectRadioButton(text=mapName, image=heightTexture, variable=m, value=[mapName])
         mapList.append(label)
     for button in mapList:
         button.setOthers(mapList)
     self.mapDialog.addScrolledList(mapList)
     okButton = DirectButton(text = self.getText('TXT_UI_OK'), command = self.selectMap, extraArgs=m)
     self.mapDialog.addVertical([okButton])
Exemple #42
0
class Typist(object):

    TARGETS = { 'paper': {
            'model': 'paper',
            'textureRoot': 'Front',
            'scale': Point3(0.85, 0.85, 1),
            'hpr' : Point3(0, 0, 0),
        }
    }

    def __init__(self, base, typewriterNP, underDeskClip, sounds):
        self.base = base
        self.sounds = sounds
        self.underDeskClip = underDeskClip
        self.typeIndex = 0

        self.typewriterNP = typewriterNP
        self.rollerAssemblyNP = typewriterNP.find("**/roller assembly")
        assert self.rollerAssemblyNP
        self.rollerNP = typewriterNP.find("**/roller")
        assert self.rollerNP
        self.carriageNP = typewriterNP.find("**/carriage")
        assert self.carriageNP
        self.baseCarriagePos = self.carriageNP.getPos()
        self.carriageBounds = self.carriageNP.getTightBounds()

        self.font = base.loader.loadFont('Harting.ttf', pointSize=32)
        self.pnmFont = PNMTextMaker(self.font)
        self.fontCharSize, _, _ = fonts.measureFont(self.pnmFont, 32)
        print "font char size: ",self.fontCharSize

        self.pixelsPerLine = int(round(self.pnmFont.getLineHeight()))

        self.target = None
        """ panda3d.core.NodePath """
        self.targetRoot = None
        """ panda3d.core.NodePath """
        self.paperY = 0.0
        """ range from 0 to 1 """
        self.paperX = 0.0
        """ range from 0 to 1 """

        self.createRollerBase()

        self.tex = None
        self.texImage = None
        self.setupTexture()

        self.scheduler = Scheduler()
        task = self.base.taskMgr.add(self.tick, 'timerTask')
        task.setDelay(0.01)

    def tick(self, task):
        self.scheduler.tick(globalClock.getRealTime())
        return task.cont

    def setupTexture(self):
        """
        This is the overlay/decal/etc. which contains the typed characters.

        The texture size and the font size are currently tied together.
        :return:
        """
        self.texImage = PNMImage(1024, 1024)
        self.texImage.addAlpha()
        self.texImage.fill(1.0)
        self.texImage.alphaFill(1.0)

        self.tex = Texture('typing')
        self.tex.setMagfilter(Texture.FTLinear)
        self.tex.setMinfilter(Texture.FTLinear)

        self.typingStage = TextureStage('typing')
        self.typingStage.setMode(TextureStage.MModulate)

        self.tex.load(self.texImage)

        # ensure we can quickly update subimages
        self.tex.setKeepRamImage(True)

        # temp for drawing chars
        self.chImage = PNMImage(*self.fontCharSize)


    def drawCharacter(self, ch, px, py):
        """
        Draw a character onto the texture
        :param ch:
        :param px: paperX
        :param py: paperY
        :return: the paper-relative size of the character
        """

        h = self.fontCharSize[1]

        if ch != ' ':

            # position -> pixel, applying margins
            x = int(self.tex.getXSize() * (px * 0.8 + 0.1))
            y = int(self.tex.getYSize() * (py * 0.8 + 0.1))

            # always draw onto the paper, to capture
            # incremental character overstrikes
            self.pnmFont.generateInto(ch, self.texImage, x, y)

            if False:
                #print ch,"to",x,y,"w=",g.getWidth()
                self.tex.load(self.texImage)

            else:
                # copy an area (presumably) encompassing the character
                g = self.pnmFont.getGlyph(ord(ch))
                cx, cy = self.fontCharSize

                # a glyph is minimally sized and "moves around" in its text box
                # (think ' vs. ,), so it has been drawn somewhere relative to
                # the 'x' and 'y' we wanted.
                x += g.getLeft()
                y -= g.getTop()

                self.chImage.copySubImage(
                        self.texImage,
                        0, 0,  # from
                        x, y,  # to
                        cx,  cy  # size
                )

                self.tex.loadSubImage(self.chImage, x, y)

            # toggle for a typewriter that uses non-proportional spacing
            #w = self.paperCharWidth(g.getWidth())
            w = self.paperCharWidth()

        else:

            w = self.paperCharWidth()

        return w, h

    def start(self):
        self.target = None
        self.setTarget('paper')

        self.hookKeyboard()


    def createRollerBase(self):
        """ The paper moves such that it is tangent to the roller.

        This nodepath keeps a coordinate space relative to that, so that
        the paper can be positioned from (0,0,0) to (0,0,1) to "roll" it
        along the roller.
        """
        bb = self.rollerNP.getTightBounds()

        #self.rollerNP.showTightBounds()
        self.paperRollerBase = self.rollerAssemblyNP.attachNewNode('rollerBase')
        self.paperRollerBase.setHpr(0, -20, 0)

        print "roller:",bb
        rad = abs(bb[0].y - bb[1].y) / 2
        center = Vec3(-(bb[0].x+bb[1].x)/2 - 0.03,
                      (bb[0].y-bb[1].y)/2,
                      (bb[0].z+bb[1].z)/2)
        self.paperRollerBase.setPos(center)

    def setTarget(self, name):
        if self.target:
            self.target.removeNode()

        # load and transform the model
        target = self.TARGETS[name]
        self.target = self.base.loader.loadModel(target['model'])
        #self.target.setScale(target['scale'])
        self.target.setHpr(target['hpr'])

        # put it in the world
        self.target.reparentTo(self.paperRollerBase)

        rbb = self.rollerNP.getTightBounds()
        tbb = self.target.getTightBounds()

        rs = (rbb[1] - rbb[0])
        ts = (tbb[1] - tbb[0])

        self.target.setScale(rs.x / ts.x, 1, 1)

        # apply the texture
        self.targetRoot = self.target
        if 'textureRoot' in target:
            self.targetRoot = self.target.find("**/" + target['textureRoot'])
            assert self.targetRoot

        self.targetRoot.setTexture(self.typingStage, self.tex)

        #self.setupTargetClip()

        # reset
        self.paperX = self.paperY = 0.
        newPos = self.calcPaperPos(self.paperY)
        self.target.setPos(newPos)

        self.moveCarriage()

    def setupTargetClip(self):
        """
        The target is fed in to the typewriter but until we invent "geom curling",
        it shouldn't be visible under the typewriter under the desk.

        The @underDeskClip node has a world-relative bounding box, which
        we can convert to the target-relative bounding box, and pass to a
        shader that can clip the nodes.

        """
        shader = Shader.make(
                Shader.SLGLSL,
            """
#version 120

attribute vec4 p3d_MultiTexCoord0;
attribute vec4 p3d_MultiTexCoord1;

void main() {
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_TexCoord[0] = p3d_MultiTexCoord0;
    gl_TexCoord[1] = p3d_MultiTexCoord1;
}

            """,

                """
#version 120

uniform sampler2D baseTex;
uniform sampler2D charTex;
const vec4 zero = vec4(0, 0, 0, 0);
const vec4 one = vec4(1, 1, 1, 1);
const vec4 half = vec4(0.5, 0.5, 0.5, 0);

void main() {
    vec4 baseColor = texture2D(baseTex, gl_TexCoord[0].st);
    vec4 typeColor = texture2D(charTex, gl_TexCoord[1].st);
    gl_FragColor = baseColor * typeColor;

}"""
        )

        self.target.setShader(shader)

        baseTex = self.targetRoot.getTexture()
        print "Base Texture:",baseTex
        self.target.setShaderInput("baseTex", baseTex)

        self.target.setShaderInput("charTex", self.tex)

    def hookKeyboard(self):
        """
        Hook events so we can respond to keypresses.
        """
        self.base.buttonThrowers[0].node().setKeystrokeEvent('keystroke')
        self.base.accept('keystroke', self.schedTypeCharacter)
        self.base.accept('backspace', self.schedBackspace)

        self.base.accept('arrow_up', lambda: self.schedAdjustPaper(-5))
        self.base.accept('arrow_up-repeat', lambda: self.schedAdjustPaper(-1))
        self.base.accept('arrow_down', lambda:self.schedAdjustPaper(5))
        self.base.accept('arrow_down-repeat', lambda:self.schedAdjustPaper(1))

        self.base.accept('arrow_left', lambda: self.schedAdjustCarriage(-1))
        self.base.accept('arrow_left-repeat', lambda: self.schedAdjustCarriage(-1))
        self.base.accept('arrow_right', lambda:self.schedAdjustCarriage(1))
        self.base.accept('arrow_right-repeat', lambda:self.schedAdjustCarriage(1))

    def paperCharWidth(self, pixels=None):
        if not pixels:
            pixels = self.fontCharSize[0]
        return float(pixels) / self.tex.getXSize()

    def paperLineHeight(self):
        return float(self.fontCharSize[1] * 1.2) / self.tex.getYSize()

    def schedScroll(self):
        if self.scheduler.isQueueEmpty():
            self.schedRollPaper(1)
            self.schedResetCarriage()

    def schedBackspace(self):
        if self.scheduler.isQueueEmpty():
            def doit():
                if self.paperX > 0:
                    self.schedAdjustCarriage(-1)

            self.scheduler.schedule(0.01, doit)


    def createMoveCarriageInterval(self, newX, curX=None):
        if curX is None:
            curX = self.paperX
        here = self.calcCarriage(curX)
        there = self.calcCarriage(newX)

        posInterval = LerpPosInterval(
                self.carriageNP, abs(newX - curX),
                there,
                startPos = here,
                blendType='easeIn')

        posInterval.setDoneEvent('carriageReset')

        def isReset():
            self.paperX = newX

        self.base.acceptOnce('carriageReset', isReset)
        return posInterval

    def schedResetCarriage(self):
        if self.paperX > 0.1:
            self.sounds['pullback'].play()

        invl = self.createMoveCarriageInterval(0)

        self.scheduler.scheduleInterval(0, invl)

    def calcCarriage(self, paperX):
        """
        Calculate where the carriage should be offset based
        on the position on the paper
        :param paperX: 0...1
        :return: pos for self.carriageNP
        """
        x = (0.5 - paperX) * 0.69 * 0.8 + 0.01

        bb = self.carriageBounds
        return self.baseCarriagePos + Point3(x * (bb[1].x-bb[0].x), 0, 0)

    def moveCarriage(self):
        pos = self.calcCarriage(self.paperX)
        self.carriageNP.setPos(pos)


    def schedMoveCarriage(self, curX, newX):
        if self.scheduler.isQueueEmpty():
            #self.scheduler.schedule(0.1, self.moveCarriage)
            invl = self.createMoveCarriageInterval(newX, curX=curX)
            invl.start()

    def schedAdjustCarriage(self, bx):
        if self.scheduler.isQueueEmpty():
            def doit():
                self.paperX = max(0.0, min(1.0, self.paperX + bx * self.paperCharWidth()))
                self.moveCarriage()

            self.scheduler.schedule(0.1, doit)


    def calcPaperPos(self, paperY):
        # center over roller, peek out a little
        z = paperY * 0.8 - 0.5 + 0.175

        bb = self.target.getTightBounds()

        return Point3(-0.5, 0, z * (bb[1].z-bb[0].z))

    def createMovePaperInterval(self, newY):
        here = self.calcPaperPos(self.paperY)
        there = self.calcPaperPos(newY)

        posInterval = LerpPosInterval(
                self.target, abs(newY - self.paperY),
                there,
                startPos = here,
                blendType='easeInOut')

        posInterval.setDoneEvent('scrollDone')

        def isDone():
            self.paperY = newY

        self.base.acceptOnce('scrollDone', isDone)
        return posInterval

    def schedAdjustPaper(self, by):
        if self.scheduler.isQueueEmpty():
            def doit():
                self.schedRollPaper(by)

            self.scheduler.schedule(0.1, doit)

    def schedRollPaper(self, by):
        """
        Position the paper such that @percent of it is rolled over roller
        :param percent:
        :return:
        """

        def doit():
            self.sounds['scroll'].play()

            newY = min(1.0, max(0.0, self.paperY + self.paperLineHeight() * by))

            invl = self.createMovePaperInterval(newY)
            invl.start()

        self.scheduler.schedule(0.1, doit)

    def schedTypeCharacter(self, keyname):
        # filter for visibility
        if ord(keyname) == 13:
            self.schedScroll()

        elif ord(keyname) >= 32 and ord(keyname) != 127:
            if self.scheduler.isQueueEmpty():
                curX, curY = self.paperX, self.paperY
                self.typeCharacter(keyname, curX, curY)

    def typeCharacter(self, ch, curX, curY):

        newX = curX

        w, h = self.drawCharacter(ch, curX, curY)

        newX += w


        if ch != ' ':
            # alternate typing sound
            #self.typeIndex = (self.typeIndex+1) % 3
            self.typeIndex = random.randint(0, 2)
            self.sounds['type' + str(self.typeIndex+1)].play()

        else:
            self.sounds['advance'].play()


        if newX >= 1:
            self.sounds['bell'].play()
            newX = 1


        self.schedMoveCarriage(self.paperX, newX)

        # move first, to avoid overtype
        self.paperX = newX
Exemple #43
0
    val = 0
    for o in range(octs):
        val += 0.5**o * noise(x*2**o, y*2**o, per*2**o)
    return val

size, freq, octs, data = 128, 1/32.0, 5, []


p = PNMImage(128, 128)
for y in range(size):
    for x in range(size):
        #data.append(fBm(x*freq, y*freq, int(size*freq), octs))
        p.setXel(x, y, fBm(x*freq, y*freq, int(size*freq), octs))

#skysphere.setTexGen(TextureStage.getDefault(), TexGenAttrib.MEyeSphereMap)
tex.load(p)
skysphere.setTexture(tex)
'''skysphere.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldPosition)
skysphere.setTexProjector(TextureStage.getDefault(), sandbox.base.render, skysphere)
skysphere.setTexPos(TextureStage.getDefault(), 0.5, 0.5, 0.5)
skysphere.setTexScale(TextureStage.getDefault(), 0.2)

''''''mesh = sandbox.base.loader.loadModel('ships/hyperion/hyperion')
mesh.setScale(0.001)
mesh.reparentTo(sandbox.base.render)''''''

#noise = PerlinNoise3(32, 32, 32, 256, 1)
noise = StackedPerlinNoise3(16, 16, 16, 3, 1, 0.5, 256, 1)
#noise = PerlinNoise3(32, 32, 32, 256)
#noise = PerlinNoise3()
Exemple #44
0
    def __init__(self, mesh_path, progressive_texture_path):

        resolutions = []
        f = tarfile.open(progressive_texture_path)
        for resolution_name in f.getnames():
            toset = {
                'size': resolution_name[:-4],
                'contents': f.extractfile(resolution_name).read()
            }
            texpnm = PNMImage()
            texpnm.read(StringStream(toset['contents']), 'something.jpg')
            newtex = Texture()
            newtex.load(texpnm)
            toset['texture'] = newtex
            resolutions.append(toset)

        self.resolutions = resolutions

        def aux_loader(fname):
            return resolutions[0]['contents']

        mesh = collada.Collada(mesh_path, aux_file_loader=aux_loader)

        scene_members = getSceneMembers(mesh)

        base = ShowBase()

        rotateNode = GeomNode("rotater")
        rotatePath = render.attachNewNode(rotateNode)
        matrix = numpy.identity(4)
        if mesh.assetInfo.upaxis == collada.asset.UP_AXIS.X_UP:
            r = collada.scene.RotateTransform(0, 1, 0, 90)
            matrix = r.matrix
        elif mesh.assetInfo.upaxis == collada.asset.UP_AXIS.Y_UP:
            r = collada.scene.RotateTransform(1, 0, 0, 90)
            matrix = r.matrix
        rotatePath.setMat(Mat4(*matrix.T.flatten().tolist()))

        geom, renderstate, mat4 = scene_members[0]
        node = GeomNode("primitive")
        node.addGeom(geom)
        if renderstate is not None:
            node.setGeomState(0, renderstate)
        self.geomPath = rotatePath.attachNewNode(node)
        self.geomPath.setMat(mat4)

        wrappedNode = ensureCameraAt(self.geomPath, base.camera)
        base.disableMouse()
        attachLights(render)
        render.setShaderAuto()
        render.setTransparency(TransparencyAttrib.MDual, 1)

        base.render.analyze()
        KeyboardMovement()
        MouseDrag(wrappedNode)
        MouseScaleZoom(wrappedNode)
        MouseCamera()

        num_resolutions = len(resolutions) - 1
        self.slider = DirectSlider(range=(0, num_resolutions),
                                   value=0,
                                   pageSize=1,
                                   command=self.sliderMoved,
                                   pos=(0, 0, -.9),
                                   scale=1)
        for key, val in uiArgs.iteritems():
            self.slider.thumb[key] = val

        self.triText = OnscreenText(text="",
                                    pos=(-1, 0.85),
                                    scale=0.15,
                                    fg=(1, 0.5, 0.5, 1),
                                    align=TextNode.ALeft,
                                    mayChange=1)

        base.run()
Exemple #45
0
class GPUFFT(DebugObject):

    """ This is a collection of compute shaders to generate the inverse
    fft efficiently on the gpu, with butterfly FFT and precomputed weights """

    def __init__(self, N, sourceTex, normalizationFactor):
        """ Creates a new fft instance. The source texture has to specified
        from the begining, as the shaderAttributes are pregenerated for
        performance reasons """
        DebugObject.__init__(self, "GPU-FFT")

        self.size = N
        self.log2Size = int(math.log(N, 2))
        self.normalizationFactor = normalizationFactor

        # Create a ping and a pong texture, because we can't write to the
        # same texture while reading to it (that would lead to unexpected
        # behaviour, we could solve that by using an appropriate thread size,
        # but it works fine so far)
        self.pingTexture = Texture("FFTPing")
        self.pingTexture.setup2dTexture(
            self.size, self.size, Texture.TFloat, Texture.FRgba32)
        self.pongTexture = Texture("FFTPong")
        self.pongTexture.setup2dTexture(
            self.size, self.size, Texture.TFloat, Texture.FRgba32)
        self.sourceTex = sourceTex

        for tex in [self.pingTexture, self.pongTexture, sourceTex]:
            tex.setMinfilter(Texture.FTNearest)
            tex.setMagfilter(Texture.FTNearest)
            tex.setWrapU(Texture.WMClamp)
            tex.setWrapV(Texture.WMClamp)

        # Pregenerate weights & indices for the shaders
        self._computeWeighting()

        # Pre generate the shaders, we have 2 passes: Horizontal and Vertical
        # which both execute log2(N) times with varying radii
        self.horizontalFFTShader = BetterShader.loadCompute(
            "Shader/Water/HorizontalFFT.compute")
        self.horizontalFFT = NodePath("HorizontalFFT")
        self.horizontalFFT.setShader(self.horizontalFFTShader)
        self.horizontalFFT.setShaderInput(
            "precomputedWeights", self.weightsLookupTex)
        self.horizontalFFT.setShaderInput("N", LVecBase2i(self.size))

        self.verticalFFTShader = BetterShader.loadCompute(
            "Shader/Water/VerticalFFT.compute")
        self.verticalFFT = NodePath("VerticalFFT")
        self.verticalFFT.setShader(self.verticalFFTShader)
        self.verticalFFT.setShaderInput(
            "precomputedWeights", self.weightsLookupTex)
        self.verticalFFT.setShaderInput("N", LVecBase2i(self.size))

        # Create a texture where the result is stored
        self.resultTexture = Texture("Result")
        self.resultTexture.setup2dTexture(
            self.size, self.size, Texture.TFloat, Texture.FRgba16)
        self.resultTexture.setMinfilter(Texture.FTLinear)
        self.resultTexture.setMagfilter(Texture.FTLinear)

        # Prepare the shader attributes, so we don't have to regenerate them
        # every frame -> That is VERY slow (3ms per fft instance)
        self._prepareAttributes()

    def getResultTexture(self):
        """ Returns the result texture, only contains valid data after execute
        was called at least once """
        return self.resultTexture

    def _generateIndices(self, storageA, storageB):
        """ This method generates the precompute indices, see
        http://cnx.org/content/m12012/latest/image1.png """
        numIter = self.size
        offset = 1
        step = 0
        for i in xrange(self.log2Size):
            numIter = numIter >> 1
            step = offset
            for j in xrange(self.size):
                goLeft = (j / step) % 2 == 1
                indexA, indexB = 0, 0
                if goLeft:
                    indexA, indexB = j - step, j
                else:
                    indexA, indexB = j, j + step

                storageA[i][j] = indexA
                storageB[i][j] = indexB
            offset = offset << 1

    def _generateWeights(self, storage):
        """ This method generates the precomputed weights """

        # Using a custom pi variable should force the calculations to use
        # high precision (I hope so)
        pi = 3.141592653589793238462643383
        numIter = self.size / 2
        numK = 1
        resolutionFloat = float(self.size)
        for i in xrange(self.log2Size):
            start = 0
            end = 2 * numK
            for b in xrange(numIter):
                K = 0
                for k in xrange(start, end, 2):
                    fK = float(K)
                    fNumIter = float(numIter)
                    weightA = Vec2(
                        math.cos(2.0 * pi * fK * fNumIter / resolutionFloat),
                        -math.sin(2.0 * pi * fK * fNumIter / resolutionFloat))
                    weightB = Vec2(
                        -math.cos(2.0 * pi * fK * fNumIter / resolutionFloat),
                        math.sin(2.0 * pi * fK * fNumIter / resolutionFloat))
                    storage[i][k / 2] = weightA
                    storage[i][k / 2 + numK] = weightB
                    K += 1
                start += 4 * numK
                end = start + 2 * numK
            numIter = numIter >> 1
            numK = numK << 1

    def _reverseRow(self, indices):
        """ Reverses the bits in the given row. This is required for inverse
        fft (actually we perform a normal fft, but reversing the bits gives
        us an inverse fft) """
        mask = 0x1
        for j in xrange(self.size):
            val = 0x0
            temp = int(indices[j])  # Int is required, for making a copy
            for i in xrange(self.log2Size):
                t = mask & temp
                val = (val << 1) | t
                temp = temp >> 1
            indices[j] = val

    def _computeWeighting(self):
        """ Precomputes the weights & indices, and stores them in a texture """
        indicesA = [[0 for i in xrange(self.size)]
                    for k in xrange(self.log2Size)]
        indicesB = [[0 for i in xrange(self.size)]
                    for k in xrange(self.log2Size)]
        weights = [[Vec2(0.0) for i in xrange(self.size)]
                   for k in xrange(self.log2Size)]

        self.debug("Pre-Generating indices ..")
        self._generateIndices(indicesA, indicesB)
        self._reverseRow(indicesA[0])
        self._reverseRow(indicesB[0])

        self.debug("Pre-Generating weights ..")
        self._generateWeights(weights)

        # Create storage for the weights & indices
        self.weightsLookup = PNMImage(self.size, self.log2Size, 4)
        self.weightsLookup.setMaxval((2 ** 16) - 1)
        self.weightsLookup.fill(0.0)

        # Populate storage
        for x in xrange(self.size):
            for y in xrange(self.log2Size):
                indexA = indicesA[y][x]
                indexB = indicesB[y][x]
                weight = weights[y][x]

                self.weightsLookup.setRed(x, y, indexA / float(self.size))
                self.weightsLookup.setGreen(x, y, indexB / float(self.size))
                self.weightsLookup.setBlue(x, y, weight.x * 0.5 + 0.5)
                self.weightsLookup.setAlpha(x, y, weight.y * 0.5 + 0.5)

        # Convert storage to texture so we can use it in a shader
        self.weightsLookupTex = Texture("Weights Lookup")
        self.weightsLookupTex.load(self.weightsLookup)
        self.weightsLookupTex.setFormat(Texture.FRgba16)
        self.weightsLookupTex.setMinfilter(Texture.FTNearest)
        self.weightsLookupTex.setMagfilter(Texture.FTNearest)
        self.weightsLookupTex.setWrapU(Texture.WMClamp)
        self.weightsLookupTex.setWrapV(Texture.WMClamp)

    def _prepareAttributes(self):
        """ Prepares all shaderAttributes, so that we have a list of
        ShaderAttributes we can simply walk through in the update method,
        that is MUCH faster than using setShaderInput, as each call to
        setShaderInput forces the generation of a new ShaderAttrib """
        self.attributes = []
        textures = [self.pingTexture, self.pongTexture]

        currentIndex = 0
        firstPass = True

        # Horizontal
        for step in xrange(self.log2Size):
            source = textures[currentIndex]
            dest = textures[1 - currentIndex]

            if firstPass:
                source = self.sourceTex
                firstPass = False

            index = self.log2Size - step - 1
            self.horizontalFFT.setShaderInput("source", source)
            self.horizontalFFT.setShaderInput("dest", dest)
            self.horizontalFFT.setShaderInput(
                "butterflyIndex", LVecBase2i(index))
            self._queueShader(self.horizontalFFT)
            currentIndex = 1 - currentIndex

        # Vertical
        for step in xrange(self.log2Size):
            source = textures[currentIndex]
            dest = textures[1 - currentIndex]
            isLastPass = step == self.log2Size - 1
            if isLastPass:
                dest = self.resultTexture
            index = self.log2Size - step - 1
            self.verticalFFT.setShaderInput("source", source)
            self.verticalFFT.setShaderInput("dest", dest)
            self.verticalFFT.setShaderInput(
                "isLastPass", isLastPass)
            self.verticalFFT.setShaderInput(
                "normalizationFactor", self.normalizationFactor)
            self.verticalFFT.setShaderInput(
                "butterflyIndex", LVecBase2i(index))
            self._queueShader(self.verticalFFT)

            currentIndex = 1 - currentIndex

    def execute(self):
        """ Executes the inverse fft once """
        for attr in self.attributes:
            self._executeShader(attr)

    def _queueShader(self, node):
        """ Internal method to fetch the ShaderAttrib of a node and store it
        in the update queue """
        sattr = node.getAttrib(ShaderAttrib)
        self.attributes.append(sattr)

    def _executeShader(self, sattr):
        """ Internal method to execute a shader by a given ShaderAttrib """
        Globals.base.graphicsEngine.dispatch_compute(
            (self.size / 16, self.size / 16, 1), sattr,
            Globals.base.win.get_gsg())
class IESLoader(DebugObject):

    """ This class manages the loading of IES Profiles and combining them into
    a texture so they can be used in a shader """
       

    # All supported IES Profile versions
    IESVersionTable = {
        'IESNA:LM-63-1986': 1986,
        'IESNA:LM-63-1991': 1991,
        'IESNA91':          1991,
        'IESNA:LM-63-1995': 1995,
        'IESNA:LM-63-2002': 2002,

        # Seems they have their own format
        "ERCO Leuchten GmbH  BY: ERCO/LUM650/8701": 2003,
        "ERCO Leuchten GmbH": 2003,
    }

    # Controls the size of the precomputed ies tables. Bigger values mean more
    # precision but also more storage required
    IESTableResolution = 256

    def __init__(self):
        """ Creates a new IES Loader """
        DebugObject.__init__(self, "IESLoader")
        self.storage = Texture("IESProfiles")
        self.storage.setup2dTextureArray(self.IESTableResolution, 1, 64, Texture.TFloat, Texture.FRgba16)
        self.storage.setMinfilter(SamplerState.FTLinear)
        self.storage.setMagfilter(SamplerState.FTLinear)
        self.storage.setWrapU(SamplerState.WMClamp)
        self.storage.setWrapV(SamplerState.WMClamp)
        self.storage.setWrapW(SamplerState.WMClamp)

        self.profileNames = []

    def getIESProfileStorageTex(self):
        """ Returns the texture array where all ies profiles are stored in """
        return self.storage

    def getIESProfileIndexByName(self, name):
        """ Returns the ies profile index if loaded so far, or -1 if no ies
        profile with that name exists so far """
        if name in self.profileNames:
            return self.profileNames.index(name)
        return -1

    def loadIESProfiles(self, directory):
        """ Loads all ies profiles from a given directory """
        self.debug("Loading IES Profiles from", directory)

        files = listdir(directory)

        for entry in files:
            if entry.lower().endswith(".ies"):
                combinedPath = os.path.join(directory, entry)
                self._loadIESProfile(entry.split(".")[0], combinedPath)


    def _storeIESProfile(self, name, lampRadialGradientData, lampGradientData):
        """ Internal method to convert the array of data into a texture to load
        into the texture array """

        def interpolateValue(dataset, percentageVal):
            """ Interpolates over an array, accepting float values from 0.0 to 1.0 """
            percentageValClamped = max(0.0, min(0.99999, percentageVal))
            scaledVal = percentageValClamped * len(dataset)
            index = int(scaledVal)
            indexBy1 = min(index + 1, len(dataset) -1)
            lerpFactor = scaledVal % 1.0
            return dataset[indexBy1] * lerpFactor + dataset[index] * (1.0 - lerpFactor)

        # Add profile name to the list of loaded profiles
        if name in self.profileNames:
            # self.error("Cannot register profile",name,"twice")
            return False
        profileIndex = len(self.profileNames)
        self.profileNames.append(name)

        # Generate gradient texture
        img = PNMImage(self.IESTableResolution, 1, 4, 2 ** 16 - 1)

        for offset in xrange(self.IESTableResolution):
            radialGradientValR = interpolateValue(lampRadialGradientData,
                (offset + 5.0) / float(self.IESTableResolution))
            radialGradientValG = interpolateValue(lampRadialGradientData,
                offset / float(self.IESTableResolution))
            radialGradientValB = interpolateValue(lampRadialGradientData,
                (offset - 5.0) / float(self.IESTableResolution))

            gradientVal = interpolateValue(lampGradientData, offset / float(self.IESTableResolution))

            img.setXelA(offset, 0, radialGradientValR, radialGradientValG, radialGradientValB, gradientVal)

        # Store gradient texture
        self.storage.load(img, profileIndex, 0)

    def _loadIESProfile(self, name, filename):
        """ Internal method to load an ies profile. Adapted from
        https://gist.githubusercontent.com/AngryLoki/4364512/raw/ies2cycles.py """
        # self.debug("Loading ies profile", filename, "as",len(self.profileNames))

        profileMultiplier = 1.0

        # Open the IES file
        with open(filename, 'r') as handle:
            content = handle.read()

        # Extract and check version string
        versionString, content = content.split('\n', 1)
        versionString = versionString.strip()

        if versionString in self.IESVersionTable:
            version = self.IESVersionTable[versionString]
        else:
            self.warn("No supported IES version found:",versionString)
            version = None

        # Extract IES properties
        keywords = dict()
        while content and not content.startswith('TILT='):
            key, content = content.split('\n', 1)
            if key.startswith('['):
                endbracket = key.find(']')
                if endbracket != -1:
                    keywords[key[1:endbracket]] = key[endbracket + 1:].strip()

        # After all properties, the tile keyword should follow
        keyword, content = content.split('\n', 1)

        if not keyword.startswith('TILT'):
            self.warn("TILT keyword not found")
            return False

        # Strip data
        fileData = content.replace(',', ' ').split()

        # Property 0 is the amount of lamps
        numLamps = int(fileData[0])
        if numLamps != 1:
            self.warn("Only 1 lamp is supported,", numLamps, "found:",name)

        # Extract further properties
        lumensPerLamp = float(fileData[1])
        candelaMultiplier = float(fileData[2])
        numVerticalAngles = int(fileData[3])
        numHorizontalAngles = int(fileData[4])

        # Check if everything went right so far
        if not numVerticalAngles or not numHorizontalAngles:
            self.error("Error during property extract")
            return False

        # Extract further properties
        photometricType = int(fileData[5])
        unitType = int(fileData[6])

        # Determine the unit type, either feet or meters
        if unitType not in [1, 2]:
            self.warn("Unkown unity type:", unitType)

        # Extract data size
        width, length, height = map(float, fileData[7:10])
        ballastFactor = float(fileData[10])

        futureUse = float(fileData[11])
        if futureUse != 1.0:
            self.warn("Invalid future use field")

        inputWatts = float(fileData[12])

        # Extract the actual data
        verticalAngles = [float(s) for s in fileData[13:13 + numVerticalAngles]]
        horizontalAngles = [float(s) for s in fileData[13 + numVerticalAngles:
                                              13 + numVerticalAngles + numHorizontalAngles]]

        # Determine the vertical light cone type. There are 90 and 180 degree cone types.
        if verticalAngles[0] == 0 and verticalAngles[-1] == 90:
            lampConeType = 'TYPE90'
        elif verticalAngles[0] == 0 and verticalAngles[-1] == 180:
            lampConeType = 'TYPE180'
        else:
            self.warn("Unsupported angles: ", verticalAngles[0], "-", verticalAngles[-1])
            lampConeType = 'TYPE180'

        # Determine the horizontal light cone type
        if len(horizontalAngles) == 1 or abs(horizontalAngles[0] - horizontalAngles[-1]) == 360:
            lampHorizontalConeType = 'TYPE360'
        elif abs(horizontalAngles[0] - horizontalAngles[-1]) == 180:
            lampHorizontalConeType = 'TYPE180'
        elif abs(horizontalAngles[0] - horizontalAngles[-1]) == 90:
            lampHorizontalConeType = 'TYPE90'
        else:
            self.warn("Unsupported horizontal angles: ", horizontalAngles[0], "-", horizontalAngles[-1])
            lampHorizontalConeType = 'TYPE360'
            
        # Read the candela values
        offset = 13 + len(verticalAngles) + len(horizontalAngles)
        candelaIndex = len(verticalAngles) * len(horizontalAngles)
        candelaValues = [float(s) for s in fileData[offset:offset + candelaIndex]]

        # Convert the 1d candela array to 2d array
        candela2D = list(zip(*[iter(candelaValues)] * len(verticalAngles)))

        # Compute the fallof gradient
        lampGradientData = [x / verticalAngles[-1] for x in verticalAngles]
       
        # Compute the radial gradient
        radialGradientData = [sum(x) / len(x) for x in zip(*candela2D)]
        radialGradientDataMax = max(radialGradientData)
        
        # Normalize the radial gradient by dividing by the maximum value
        radialGradientData = [val / radialGradientDataMax for val in radialGradientData]

        # Finally register the profile
        self._storeIESProfile(name, radialGradientData, lampGradientData)
        return True
Exemple #47
0
class IESLoader(DebugObject):
    """ This class manages the loading of IES Profiles and combining them into
    a texture so they can be used in a shader """

    # All supported IES Profile versions
    IESVersionTable = {
        'IESNA:LM-63-1986': 1986,
        'IESNA:LM-63-1991': 1991,
        'IESNA91': 1991,
        'IESNA:LM-63-1995': 1995,
        'IESNA:LM-63-2002': 2002,

        # Seems they have their own format
        "ERCO Leuchten GmbH  BY: ERCO/LUM650/8701": 2003,
        "ERCO Leuchten GmbH": 2003,
    }

    # Controls the size of the precomputed ies tables. Bigger values mean more
    # precision but also more storage required
    IESTableResolution = 256

    def __init__(self):
        """ Creates a new IES Loader """
        DebugObject.__init__(self, "IESLoader")
        self.storage = Texture("IESProfiles")
        self.storage.setup2dTextureArray(self.IESTableResolution, 1, 64,
                                         Texture.TFloat, Texture.FRgba16)
        self.storage.setMinfilter(SamplerState.FTLinear)
        self.storage.setMagfilter(SamplerState.FTLinear)
        self.storage.setWrapU(SamplerState.WMClamp)
        self.storage.setWrapV(SamplerState.WMClamp)
        self.storage.setWrapW(SamplerState.WMClamp)

        self.profileNames = []

    def getIESProfileStorageTex(self):
        """ Returns the texture array where all ies profiles are stored in """
        return self.storage

    def getIESProfileIndexByName(self, name):
        """ Returns the ies profile index if loaded so far, or -1 if no ies
        profile with that name exists so far """
        if name in self.profileNames:
            return self.profileNames.index(name)
        return -1

    def loadIESProfiles(self, directory):
        """ Loads all ies profiles from a given directory """
        self.debug("Loading IES Profiles from", directory)

        files = listdir(directory)

        for entry in files:
            if entry.lower().endswith(".ies"):
                combinedPath = os.path.join(directory, entry)
                self._loadIESProfile(entry.split(".")[0], combinedPath)

    def _storeIESProfile(self, name, lampRadialGradientData, lampGradientData):
        """ Internal method to convert the array of data into a texture to load
        into the texture array """
        def interpolateValue(dataset, percentageVal):
            """ Interpolates over an array, accepting float values from 0.0 to 1.0 """
            percentageValClamped = max(0.0, min(0.99999, percentageVal))
            scaledVal = percentageValClamped * len(dataset)
            index = int(scaledVal)
            indexBy1 = min(index + 1, len(dataset) - 1)
            lerpFactor = scaledVal % 1.0
            return dataset[indexBy1] * lerpFactor + dataset[index] * (
                1.0 - lerpFactor)

        # Add profile name to the list of loaded profiles
        if name in self.profileNames:
            # self.error("Cannot register profile",name,"twice")
            return False
        profileIndex = len(self.profileNames)
        self.profileNames.append(name)

        # Generate gradient texture
        img = PNMImage(self.IESTableResolution, 1, 4, 2**16 - 1)

        for offset in xrange(self.IESTableResolution):
            radialGradientValR = interpolateValue(
                lampRadialGradientData,
                (offset + 5.0) / float(self.IESTableResolution))
            radialGradientValG = interpolateValue(
                lampRadialGradientData,
                offset / float(self.IESTableResolution))
            radialGradientValB = interpolateValue(
                lampRadialGradientData,
                (offset - 5.0) / float(self.IESTableResolution))

            gradientVal = interpolateValue(
                lampGradientData, offset / float(self.IESTableResolution))

            img.setXelA(offset, 0, radialGradientValR, radialGradientValG,
                        radialGradientValB, gradientVal)

        # Store gradient texture
        self.storage.load(img, profileIndex, 0)

    def _loadIESProfile(self, name, filename):
        """ Internal method to load an ies profile. Adapted from
        https://gist.githubusercontent.com/AngryLoki/4364512/raw/ies2cycles.py """
        # self.debug("Loading ies profile", filename, "as",len(self.profileNames))

        profileMultiplier = 1.0

        # Open the IES file
        with open(filename, 'r') as handle:
            content = handle.read()

        # Extract and check version string
        versionString, content = content.split('\n', 1)
        versionString = versionString.strip()

        if versionString in self.IESVersionTable:
            version = self.IESVersionTable[versionString]
        else:
            self.warn("No supported IES version found:", versionString)
            version = None

        # Extract IES properties
        keywords = dict()
        while content and not content.startswith('TILT='):
            key, content = content.split('\n', 1)
            if key.startswith('['):
                endbracket = key.find(']')
                if endbracket != -1:
                    keywords[key[1:endbracket]] = key[endbracket + 1:].strip()

        # After all properties, the tile keyword should follow
        keyword, content = content.split('\n', 1)

        if not keyword.startswith('TILT'):
            self.warn("TILT keyword not found")
            return False

        # Strip data
        fileData = content.replace(',', ' ').split()

        # Property 0 is the amount of lamps
        numLamps = int(fileData[0])
        if numLamps != 1:
            self.warn("Only 1 lamp is supported,", numLamps, "found:", name)

        # Extract further properties
        lumensPerLamp = float(fileData[1])
        candelaMultiplier = float(fileData[2])
        numVerticalAngles = int(fileData[3])
        numHorizontalAngles = int(fileData[4])

        # Check if everything went right so far
        if not numVerticalAngles or not numHorizontalAngles:
            self.error("Error during property extract")
            return False

        # Extract further properties
        photometricType = int(fileData[5])
        unitType = int(fileData[6])

        # Determine the unit type, either feet or meters
        if unitType not in [1, 2]:
            self.warn("Unkown unity type:", unitType)

        # Extract data size
        width, length, height = map(float, fileData[7:10])
        ballastFactor = float(fileData[10])

        futureUse = float(fileData[11])
        if futureUse != 1.0:
            self.warn("Invalid future use field")

        inputWatts = float(fileData[12])

        # Extract the actual data
        verticalAngles = [
            float(s) for s in fileData[13:13 + numVerticalAngles]
        ]
        horizontalAngles = [
            float(s) for s in fileData[13 + numVerticalAngles:13 +
                                       numVerticalAngles + numHorizontalAngles]
        ]

        # Determine the vertical light cone type. There are 90 and 180 degree cone types.
        if verticalAngles[0] == 0 and verticalAngles[-1] == 90:
            lampConeType = 'TYPE90'
        elif verticalAngles[0] == 0 and verticalAngles[-1] == 180:
            lampConeType = 'TYPE180'
        else:
            self.warn("Unsupported angles: ", verticalAngles[0], "-",
                      verticalAngles[-1])
            lampConeType = 'TYPE180'

        # Determine the horizontal light cone type
        if len(horizontalAngles) == 1 or abs(horizontalAngles[0] -
                                             horizontalAngles[-1]) == 360:
            lampHorizontalConeType = 'TYPE360'
        elif abs(horizontalAngles[0] - horizontalAngles[-1]) == 180:
            lampHorizontalConeType = 'TYPE180'
        elif abs(horizontalAngles[0] - horizontalAngles[-1]) == 90:
            lampHorizontalConeType = 'TYPE90'
        else:
            self.warn("Unsupported horizontal angles: ", horizontalAngles[0],
                      "-", horizontalAngles[-1])
            lampHorizontalConeType = 'TYPE360'

        # Read the candela values
        offset = 13 + len(verticalAngles) + len(horizontalAngles)
        candelaIndex = len(verticalAngles) * len(horizontalAngles)
        candelaValues = [
            float(s) for s in fileData[offset:offset + candelaIndex]
        ]

        # Convert the 1d candela array to 2d array
        candela2D = list(zip(*[iter(candelaValues)] * len(verticalAngles)))

        # Compute the fallof gradient
        lampGradientData = [x / verticalAngles[-1] for x in verticalAngles]

        # Compute the radial gradient
        radialGradientData = [sum(x) / len(x) for x in zip(*candela2D)]
        radialGradientDataMax = max(radialGradientData)

        # Normalize the radial gradient by dividing by the maximum value
        radialGradientData = [
            val / radialGradientDataMax for val in radialGradientData
        ]

        # Finally register the profile
        self._storeIESProfile(name, radialGradientData, lampGradientData)
        return True
Exemple #48
0
class MazeMapGui(DirectFrame):
    notify = directNotify.newCategory('MazeMapGui')

    def __init__(self, mazeCollTable, maskResolution = None, radiusRatio = None, bgColor = (0.8, 0.8, 0.8), fgColor = (0.5, 0.5, 0.5, 1.0)):
        DirectFrame.__init__(self, relief=None, state=DGG.NORMAL, sortOrder=DGG.BACKGROUND_SORT_INDEX)
        self.hide()
        self._bgColor = bgColor
        self._fgColor = fgColor
        self._mazeCollTable = mazeCollTable
        self._mazeWidth = len(self._mazeCollTable[0])
        self._mazeHeight = len(self._mazeCollTable)
        self._maskResolution = maskResolution or DEFAULT_MASK_RESOLUTION
        if radiusRatio is None:
            self._radius = self._maskResolution * DEFAULT_RADIUS_RATIO
        else:
            self._radius = self._maskResolution * radiusRatio
        self._revealedCells = []
        for y in xrange(self._mazeHeight):
            self._revealedCells.append([])
            for u in xrange(self._mazeWidth):
                self._revealedCells[y].append(False)

        self._revealFunctions = {MazeRevealType.SmoothCircle: self._revealSmoothCircle,
         MazeRevealType.HardCircle: self._revealHardCircle,
         MazeRevealType.Square: self._revealSquare}
        self._revealFunction = MAZE_REVEAL_TYPE
        self.map = self._createMapTextureCard()
        self.map.reparentTo(self)
        self.maskedLayer = self.attachNewNode('maskedLayer')
        self.mask = self._createMaskTextureCard()
        self.mask.reparentTo(self)
        self.visibleLayer = self.attachNewNode('visibleLayer')
        self._laffMeterModel = loader.loadModel('phase_3/models/gui/laff_o_meter')
        self._toon2marker = {}
        return

    def _createMapTextureCard(self):
        mapImage = PNMImage(MAP_RESOLUTION, MAP_RESOLUTION)
        mapImage.fill(*self._bgColor)
        fgColor = VBase4D(*self._fgColor)
        for x in xrange(self._mazeHeight):
            for y in xrange(self._mazeWidth):
                if self._mazeCollTable[y][x] == 1:
                    ax = float(x) / self._mazeWidth * MAP_RESOLUTION
                    invertedY = self._mazeHeight - 1 - y
                    ay = float(invertedY) / self._mazeHeight * MAP_RESOLUTION
                    self._drawSquare(mapImage, int(ax), int(ay), 10, fgColor)

        mapTexture = Texture('mapTexture')
        mapTexture.setupTexture(Texture.TT2dTexture, self._maskResolution, self._maskResolution, 1, Texture.TUnsignedByte, Texture.FRgba)
        mapTexture.setMinfilter(Texture.FTLinear)
        mapTexture.load(mapImage)
        mapTexture.setWrapU(Texture.WMClamp)
        mapTexture.setWrapV(Texture.WMClamp)
        mapImage.clear()
        del mapImage
        cm = CardMaker('map_cardMaker')
        cm.setFrame(-1.0, 1.0, -1.0, 1.0)
        map = self.attachNewNode(cm.generate())
        map.setTexture(mapTexture, 1)
        return map

    def _createMaskTextureCard(self):
        self._maskImage = PNMImage(self._maskResolution, self._maskResolution, 4)
        for x in xrange(self._maskResolution):
            for y in xrange(self._maskResolution):
                self._maskImage.setXelA(x, y, 0, 0, 0, 1)

        self.maskTexture = Texture('maskTexture')
        self.maskTexture.setupTexture(Texture.TT2dTexture, self._maskResolution, self._maskResolution, 1, Texture.TUnsignedByte, Texture.FRgba)
        self.maskTexture.setMinfilter(Texture.FTLinear)
        self.maskTexture.setWrapU(Texture.WMClamp)
        self.maskTexture.setWrapV(Texture.WMClamp)
        self.maskTexture.load(self._maskImage)
        base.graphicsEngine.renderFrame()
        cm = CardMaker('mask_cardMaker')
        cm.setFrame(-1.1, 1.1, -1.1, 1.1)
        mask = self.attachNewNode(cm.generate())
        mask.setTexture(self.maskTexture, 1)
        mask.setTransparency(1)
        return mask

    def _drawSquare(self, image, ulx, uly, size, color):
        x = int(ulx)
        while x <= ulx + size:
            y = int(uly)
            while y <= uly + size:
                if x > 0 and y > 0 and x < image.getXSize() and y < image.getYSize():
                    image.setXelA(x, y, color)
                y += 1

            x += 1

    def destroy(self):
        del self._mazeCollTable
        del self._maskResolution
        del self._radius
        del self._revealedCells
        del self._revealFunctions
        del self._revealFunction
        self.map.removeNode()
        del self.map
        self.mask.removeNode()
        del self.mask
        self.maskedLayer.removeNode()
        del self.maskedLayer
        self.visibleLayer.removeNode()
        del self.visibleLayer
        self._maskImage.clear()
        del self._maskImage
        self.maskTexture.clear()
        del self.maskTexture
        self._laffMeterModel.removeNode()
        del self._laffMeterModel
        DirectFrame.destroy(self)

    def _revealSmoothCircle(self, x, y, center):
        length = (Vec2(x, y) - center).length()
        goalAlpha = max(0.0, length / float(self._radius) - 0.5)
        self._maskImage.setXelA(x, y, VBase4D(0.0, 0.0, 0.0, min(self._maskImage.getAlpha(x, y), goalAlpha * 2.0)))

    def _revealHardCircle(self, x, y, center):
        length = (Vec2(x, y) - center).length()
        if length <= self._radius:
            self._maskImage.setXelA(x, y, VBase4D(0, 0, 0, 0))

    def _revealSquare(self, x, y, center):
        self._maskImage.setXelA(x, y, VBase4D(0, 0, 0, 0))

    def _drawHole(self, x, y):
        center = Vec2(x, y)
        ul = center - Vec2(self._radius, self._radius)
        lr = center + Vec2(self._radius, self._radius)
        x = int(ul[0])
        while x <= lr[0]:
            y = int(ul[1])
            while y <= lr[1]:
                if x > 0 and y > 0 and x < self._maskResolution and y < self._maskResolution:
                    self._revealFunctions[self._revealFunction](x, y, center)
                y += 1

            x += 1

        self.maskTexture.load(self._maskImage)
        self.mask.setTexture(self.maskTexture, 1)

    def _createSimpleMarker(self, size, color = (1, 1, 1)):
        halfSize = size * 0.5
        cm = CardMaker('mazemap_simple_marker')
        cm.setFrame(-halfSize, halfSize, -halfSize, halfSize)
        markerNP = self.maskedLayer.attachNewNode(cm.generate())
        markerNP.setColor(*color)
        return markerNP

    def tile2gui(self, x, y):
        y = self._mazeHeight - y
        cellWidth = self._maskResolution / self._mazeWidth
        cellHeight = self._maskResolution / self._mazeHeight
        ax = float(x) / self._mazeWidth * self._maskResolution
        ax += cellWidth
        ay = float(y) / self._mazeHeight * self._maskResolution
        ay += cellHeight
        return (ax, ay)

    def gui2pos(self, x, y):
        return (x / self._maskResolution * 2.0 - 0.97, 0, y / self._maskResolution * -2.0 + 1.02)

    def _getToonMarker(self, toon):
        hType = toon.style.getType()
        if hType == 'rabbit':
            hType = 'bunny'
        return self._laffMeterModel.find('**/' + hType + 'head')

    def addToon(self, toon, tX, tY):
        marker = NodePath('toon_marker-%i' % toon.doId)
        marker.reparentTo(self)
        self._getToonMarker(toon).copyTo(marker)
        marker.setColor(toon.style.getHeadColor())
        if toon.isLocal():
            marker.setScale(0.07)
        else:
            marker.setScale(0.05)
        marker.flattenStrong()
        marker.setPos(*self.gui2pos(*self.tile2gui(tX, tY)))
        self._toon2marker[toon] = marker

    def removeToon(self, toon):
        if toon not in self._toon2marker:
            return
        self._toon2marker[toon].removeNode()
        del self._toon2marker[toon]

    def updateToon(self, toon, tX, tY):
        if toon not in self._toon2marker:
            return
        x, y = self.tile2gui(tX, tY)
        self._toon2marker[toon].setPos(*self.gui2pos(x, y))
        if tY < 0 or tY >= len(self._revealedCells):
            self.notify.warning('updateToon earlying out:')
            self.notify.warning('(tX, tY): (%s, %s)' % (tX, tY))
            self.notify.warning('len(_revealedCells): %s' % (len(self._revealedCells),))
            if len(self._revealedCells) > 0:
                self.notify.warning('len(_revealedCells[0]): %s' % (len(self._revealedCells[0]),))
            return
        if tX < 0 or tX >= len(self._revealedCells[tY]):
            self.notify.warning('updateToon earlying out:')
            self.notify.warning('(tX, tY): (%s, %s)' % (tX, tY))
            self.notify.warning('len(_revealedCells): %s' % (len(self._revealedCells),))
            if tY < len(self._revealedCells):
                self.notify.warning('len(_revealedCells[tY]): %s' % (len(self._revealedCells[tY]),))
            elif len(self._revealedCells) > 0:
                self.notify.warning('len(_revealedCells[0]): %s' % (len(self._revealedCells[0]),))
            return
        if not self._revealedCells[tY][tX]:
            self._drawHole(x, y)
            self._revealedCells[tY][tX] = True

    def revealCell(self, x, y):
        ax, ay = self.tile2gui(x, y)
        if not self._revealedCells[y][x]:
            self._drawHole(ax, ay)
            self._revealedCells[y][x] = True

    def revealAll(self):
        for x in xrange(self._maskResolution):
            for y in xrange(self._maskResolution):
                self._maskImage.setXelA(x, y, 0, 0, 0, 0)

        self.revealCell(0, 0)

    def reset(self):
        for x in xrange(self._maskResolution):
            for y in xrange(self._maskResolution):
                self._maskImage.setXelA(x, y, 0, 0, 0, 1)
Exemple #49
0
class PlayerBase(DirectObject):
    def __init__(self):
        # Player Model setup
        self.player = Actor("Player",
                            {"Run":"Player-Run",
                            "Sidestep":"Player-Sidestep",
                            "Idle":"Player-Idle"})
        self.player.setBlend(frameBlend = True)
        self.player.setPos(0, 0, 0)
        self.player.pose("Idle", 0)
        self.player.reparentTo(render)
        self.player.hide()

        self.footstep = base.audio3d.loadSfx('footstep.ogg')
        self.footstep.setLoop(True)
        base.audio3d.attachSoundToObject(self.footstep, self.player)

        # Create a brush to paint on the texture
        splat = PNMImage("../data/Splat.png")
        self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1)

        CamMask = BitMask32.bit(0)
        AvBufMask = BitMask32.bit(1)
        self.avbuf = None
        if base.win:
            self.avbufTex = Texture('avbuf')
            self.avbuf = base.win.makeTextureBuffer('avbuf', 256, 256, self.avbufTex, True)
            cam = Camera('avbuf')
            cam.setLens(base.camNode.getLens())
            self.avbufCam = base.cam.attachNewNode(cam)
            dr = self.avbuf.makeDisplayRegion()
            dr.setCamera(self.avbufCam)
            self.avbuf.setActive(False)
            self.avbuf.setClearColor((1, 0, 0, 1))
            cam.setCameraMask(AvBufMask)
            base.camNode.setCameraMask(CamMask)

            # avbuf renders everything it sees with the gradient texture.
            tex = loader.loadTexture('gradient.png')
            np = NodePath('np')
            np.setTexture(tex, 100)
            np.setColor((1, 1, 1, 1), 100)
            np.setColorScaleOff(100)
            np.setTransparency(TransparencyAttrib.MNone, 100)
            np.setLightOff(100)
            cam.setInitialState(np.getState())
            #render.hide(AvBufMask)

        # Setup a texture stage to paint on the player
        self.paintTs = TextureStage('paintTs')
        self.paintTs.setMode(TextureStage.MDecal)
        self.paintTs.setSort(10)
        self.paintTs.setPriority(10)

        self.tex = Texture('paint_av_%s'%id(self))

        # Setup a PNMImage that will hold the paintable texture of the player
        self.imageSizeX = 64
        self.imageSizeY = 64
        self.p = PNMImage(self.imageSizeX, self.imageSizeY, 4)
        self.p.fill(1)
        self.p.alphaFill(0)
        self.tex.load(self.p)
        self.tex.setWrapU(self.tex.WMClamp)
        self.tex.setWrapV(self.tex.WMClamp)

        # Apply the paintable texture to the avatar
        self.player.setTexture(self.paintTs, self.tex)

        # team
        self.playerTeam = ""
        # A lable that will display the players team
        self.lblTeam = DirectLabel(
            scale = 1,
            pos = (0, 0, 3),
            frameColor = (0, 0, 0, 0),
            text = "TEAM",
            text_align = TextNode.ACenter,
            text_fg = (0,0,0,1))
        self.lblTeam.reparentTo(self.player)
        self.lblTeam.setBillboardPointEye()

        # basic player values
        self.maxHits = 3
        self.currentHits = 0
        self.isOut = False

        self.TorsorControl = self.player.controlJoint(None,"modelRoot","Torsor")

        # setup the collision detection
        # wall and object collision
        self.playerSphere = CollisionSphere(0, 0, 1, 1)
        self.playerCollision = self.player.attachNewNode(CollisionNode("playerCollision%d"%id(self)))
        self.playerCollision.node().addSolid(self.playerSphere)
        base.pusher.addCollider(self.playerCollision, self.player)
        base.cTrav.addCollider(self.playerCollision, base.pusher)
        # foot (walk) collision
        self.playerFootRay = self.player.attachNewNode(CollisionNode("playerFootCollision%d"%id(self)))
        self.playerFootRay.node().addSolid(CollisionRay(0, 0, 2, 0, 0, -1))
        self.playerFootRay.node().setIntoCollideMask(0)
        self.lifter = CollisionHandlerFloor()
        self.lifter.addCollider(self.playerFootRay, self.player)
        base.cTrav.addCollider(self.playerFootRay, self.lifter)

        # Player weapon setup
        self.gunAttach = self.player.exposeJoint(None, "modelRoot", "WeaponSlot_R")
        self.color = LPoint3f(1, 1, 1)
        self.gun = Gun(id(self))
        self.gun.reparentTo(self.gunAttach)
        self.gun.hide()
        self.gun.setColor(self.color)

        self.hud = None

        # Player controls setup
        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0}
        # screen sizes
        self.winXhalf = base.win.getXSize() / 2
        self.winYhalf = base.win.getYSize() / 2
        self.mouseSpeedX = 0.1
        self.mouseSpeedY = 0.1
        # AI controllable variables
        self.AIP = 0.0
        self.AIH = 0.0

        self.movespeed = 5.0

        self.userControlled = False

        self.accept("Bulet-hit-playerCollision%d" % id(self), self.hit)
        self.accept("window-event", self.recalcAspectRatio)

    def runBase(self):
        self.player.show()
        self.gun.show()
        taskMgr.add(self.move, "moveTask%d"%id(self), priority=-4)

    def stopBase(self):
        taskMgr.remove("moveTask%d"%id(self))
        self.ignoreAll()
        self.gun.remove()
        self.footstep.stop()
        base.audio3d.detachSound(self.footstep)
        self.player.delete()

    def setKey(self, key, value):
        self.keyMap[key] = value

    def setPos(self, pos):
        self.player.setPos(pos)

    def setColor(self, color=LPoint3f(0,0,0)):
        self.color = color
        self.gun.setColor(color)
        c = (color[0], color[1], color[2], 1.0)
        self.lblTeam["text_fg"] = c

    def setTeam(self, team):
        self.playerTeam = team
        self.lblTeam["text"] = team


    def shoot(self, shotVec=None):
        self.gun.shoot(shotVec)
        if self.hud != None:
            self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition)

    def reload(self):
        self.gun.reload()
        if self.hud != None:
            self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition)

    def recalcAspectRatio(self, window):
        self.winXhalf = window.getXSize() / 2
        self.winYhalf = window.getYSize() / 2

    def hit(self, entry, color):
        self.currentHits += 1

        # Create a brush to paint on the texture
        splat = PNMImage("../data/Splat.png")
        splat = splat * LColorf(color[0], color[1], color[2], 1.0)
        self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1)

        self.paintAvatar(entry)

        if self.currentHits >= self.maxHits:
            base.messenger.send("GameOver-player%d" % id(self))
            self.isOut = True

    def __paint(self, s, t):
        """ Paints a point on the avatar at texture coordinates (s, t). """
        x = (s * self.p.getXSize())
        y = ((1.0 - t) * self.p.getYSize())

        # Draw in color directly on the avatar
        p1 = PNMPainter(self.p)
        p1.setPen(self.colorBrush)
        p1.drawPoint(x, y)

        self.tex.load(self.p)
        self.tex.setWrapU(self.tex.WMClamp)
        self.tex.setWrapV(self.tex.WMClamp)

        self.paintDirty = True

    def paintAvatar(self, entry):
        """ Paints onto an avatar.  Returns true on success, false on
        failure (because there are no avatar pixels under the mouse,
        for instance). """

        # First, we have to render the avatar in its false-color
        # image, to determine which part of its texture is under the
        # mouse.
        if not self.avbuf:
            return False

        #mpos = base.mouseWatcherNode.getMouse()
        mpos = entry.getSurfacePoint(self.player)
        ppos = entry.getSurfacePoint(render)

        self.player.showThrough(BitMask32.bit(1))
        self.avbuf.setActive(True)
        base.graphicsEngine.renderFrame()
        self.player.show(BitMask32.bit(1))
        self.avbuf.setActive(False)

        # Now we have the rendered image in self.avbufTex.
        if not self.avbufTex.hasRamImage():
            print "Weird, no image in avbufTex."
            return False
        p = PNMImage()
        self.avbufTex.store(p)
        ix = int((1 + mpos.getX()) * p.getXSize() * 0.5)
        iy = int((1 - mpos.getY()) * p.getYSize() * 0.5)
        x = 1
        if ix >= 0 and ix < p.getXSize() and iy >= 0 and iy < p.getYSize():
            s = p.getBlue(ix, iy)
            t = p.getGreen(ix, iy)
            x = p.getRed(ix, iy)
        if x > 0.5:
            # Off the avatar.
            return False

        # At point (s, t) on the avatar's map.

        self.__paint(s, t)
        return True

    def move(self, task):
        if self is None: return task.done
        if self.userControlled:
            if not base.mouseWatcherNode.hasMouse(): return task.cont
            self.pointer = base.win.getPointer(0)
            mouseX = self.pointer.getX()
            mouseY = self.pointer.getY()

            if base.win.movePointer(0, self.winXhalf, self.winYhalf):
                p = self.TorsorControl.getP() + (mouseY - self.winYhalf) * self.mouseSpeedY
                if p <-80:
                    p = -80
                elif p > 90:
                    p = 90
                self.TorsorControl.setP(p)

                h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX
                if h <-360:
                    h = 360
                elif h > 360:
                    h = -360
                self.player.setH(h)
        else:
            self.TorsorControl.setP(self.AIP)
            self.player.setH(self.AIH)

        forward =  self.keyMap["forward"] != 0
        backward = self.keyMap["backward"] != 0

        if self.keyMap["left"] != 0:
            if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward):
                self.player.loop("Sidestep")
                self.player.setPlayRate(5, "Sidestep")
            self.player.setX(self.player, self.movespeed * globalClock.getDt())
        elif self.keyMap["right"] != 0:
            if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward):
                self.player.loop("Sidestep")
                self.player.setPlayRate(5, "Sidestep")
            self.player.setX(self.player, -self.movespeed * globalClock.getDt())
        else:
            self.player.stop("Sidestep")
        if forward:
            if self.player.getCurrentAnim() != "Run":
                self.player.loop("Run")
                self.player.setPlayRate(5, "Run")
            self.player.setY(self.player, -self.movespeed * globalClock.getDt())
        elif backward:
            if self.player.getCurrentAnim() != "Run":
                self.player.loop("Run")
                self.player.setPlayRate(-5, "Run")
            self.player.setY(self.player, self.movespeed * globalClock.getDt())
        else:
            self.player.stop("Run")

        if not (self.keyMap["left"] or self.keyMap["right"] or
                self.keyMap["forward"] or self.keyMap["backward"] or
                self.player.getCurrentAnim() == "Idle"):
            self.player.loop("Idle")
            self.footstep.stop()
        else:
            self.footstep.play()

        return task.cont
Exemple #50
0
    def build(self, exit_behav):
        self.drv_info = self.props.gameprops.drivers_info
        menu_props = self.menu_props
        widgets = [Text(_('Select the driver'), pos=(0, .8),
                                **menu_props.text_args)]
        t_a = self.menu_props.text_args.copy()
        del t_a['scale']
        self.name = Text(_('Write your name:'), pos=(-.1, .6), scale=.06,
                            align='right', wordwrap=128, **t_a)
        self.drivers = []
        for row, col in product(range(2), range(4)):
            idx = col + row * 4
            drv_btn = ImgBtn(
                scale=(.24, .24), pos=(-.75 + col * .5, .3 - row * .64),
                frame_col=(0, 0, 0, 0),
                img=self.props.gameprops.drivers_img.path % idx,
                cmd=self.on_click, extra_args=[idx],
                **self.menu_props.imgbtn_args)
            name = Text(
                '',
                pos=(-.75 + col * .5, .01 - row * .64),
                scale=.046, **t_a)
            drv_btn._name_txt = name
            widgets += [drv_btn, name]
            self.drivers += [widgets[-2]]
            sign = lambda pos_x: '\1green\1+\2' if pos_x > 0 else ''
            psign = lambda pos_x, sgn=sign: '+' if pos_x == 0 else sgn(pos_x)

            def ppcol(x):
                return '\1green\1%s\2' % x if x > 0 else '\1red\1%s\2' % x
            pcol = lambda x: x if x == 0 else ppcol(x)
            lab_lst = [(_('adherence'), .09), (_('speed'), .21),
                       (_('stability'), .15)]
            widgets += list(map(
                lambda lab_def: self._add_lab(*(lab_def + (row, col))),
                lab_lst))
            txt_lst = [(self.drv_info[idx - 1].adherence, .09),
                       (self.drv_info[idx - 1].speed, .21),
                       (self.drv_info[idx - 1].stability, .15)]
            widgets += list(map(
                lambda txt_def: self._add_txt(
                    *txt_def + (psign, pcol, col, row)),
                txt_lst))
        self.sel_drv_img = Img(
            self.props.gameprops.cars_img % self.mediator.car,
            parent=base.a2dBottomLeft, pos=(.3, .4), scale=.28)
        instr_txt = _(
            'If you use the keyboard, press FIRE to edit the field, then '
            "ENTER when you're done")
        instr = Text(instr_txt, pos=(1.4, .6), scale=.042, wordwrap=16, **t_a)
        widgets += [self.sel_drv_img, self.name, instr]
        self.add_widgets(widgets)
        ffilterpath = self.eng.curr_path + 'yyagl/assets/shaders/filter.vert'
        with open(ffilterpath) as ffilter:
            vert = ffilter.read()
        shader = load_shader(vert, frag)
        if shader:
            self.sel_drv_img.set_shader(shader)
        self.sel_drv_img.set_transparent()
        self.t_s = TextureStage('ts')
        self.t_s.set_mode(TextureStage.MDecal)
        empty_img = PNMImage(1, 1)
        empty_img.add_alpha()
        empty_img.alpha_fill(0)
        tex = Texture()
        tex.load(empty_img)
        self.sel_drv_img.set_texture(self.t_s, tex)
        ThanksPageGui.build(self, exit_behav=exit_behav)
Exemple #51
0
    def build(self):
        self.drv_info = self.props.gameprops.drivers_info
        menu_props = self.menu_props
        widgets = [Text(_('Select the drivers'), pos=(0, .91),
                                **menu_props.text_args)]
        t_a = self.menu_props.text_args.copy()
        del t_a['scale']
        self.name = Text(_('Write your names:'), pos=(-.1, .7), scale=.06,
                            align='right', wordwrap=128, **t_a)
        self.drivers = []
        for row, col in product(range(2), range(4)):
            idx = col + row * 4
            drv_btn = ImgBtn(
                scale=(.24, .24), pos=(-.75 + col * .5, .1 - row * .64),
                frame_col=(0, 0, 0, 0),
                img=self.props.gameprops.drivers_img.path % idx,
                cmd=self.on_click, extra_args=[idx],
                **self.menu_props.imgbtn_args)
            name = Text(
                '',
                pos=(-.75 + col * .5, -.19 - row * .64),
                scale=.046, **t_a)
            drv_btn._name_txt = name
            widgets += [drv_btn, name]
            self.drivers += [widgets[-2]]
            sign = lambda pos_x: '\1green\1+\2' if pos_x > 0 else ''
            psign = lambda pos_x, sgn=sign: '+' if pos_x == 0 else sgn(pos_x)

            def ppcol(x):
                return '\1green\1%s\2' % x if x > 0 else '\1red\1%s\2' % x
            pcol = lambda x: x if x == 0 else ppcol(x)
            lab_lst = [(_('adherence'), -.11), (_('speed'), .01),
                       (_('stability'), -.05)]
            widgets += list(map(
                lambda lab_def: self._add_lab(*(lab_def + (row, col))),
                lab_lst))
            txt_lst = [(self.drv_info[idx - 1].adherence, -.11),
                       (self.drv_info[idx - 1].speed, .01),
                       (self.drv_info[idx - 1].stability, -.05)]
            widgets += list(map(
                lambda txt_def: self._add_txt(
                    *txt_def + (psign, pcol, col, row)),
                txt_lst))
        self.sel_drv_img = []
        self.tss = []
        instr_txt = _(
            'If you use the keyboard, press FIRE to edit the field, then '
            "ENTER when you're done. Other players can't move while someone"
            'is writing (since, with keyboards, some letters may be bound to '
            'movements).')
        instr = Text(instr_txt, pos=(1.28, .8), scale=.042, wordwrap=24, **t_a)
        widgets += [self.name, instr]
        for i, car in enumerate(self.mediator.cars):
            self.sel_drv_img += [Img(
                self.props.gameprops.cars_img % car,
                parent=base.a2dBottomLeft, pos=(.3, 1.74 - i * .46), scale=.22)]
            widgets += [self.sel_drv_img[-1]]
            ffilterpath = self.eng.curr_path + 'yyagl/assets/shaders/filter.vert'
            with open(ffilterpath) as ffilter:
                vert = ffilter.read()
            shader = load_shader(vert, frag)
            if shader:
                self.sel_drv_img[-1].set_shader(shader)
            self.sel_drv_img[-1].set_transparent()
            self.tss += [TextureStage('ts')]
            self.tss[-1].set_mode(TextureStage.MDecal)
            empty_img = PNMImage(1, 1)
            empty_img.add_alpha()
            empty_img.alpha_fill(0)
            tex = Texture()
            tex.load(empty_img)
            self.sel_drv_img[-1].set_texture(self.tss[-1], tex)
        self.ents = [Entry(
            scale=.06, pos=(0, .8 - .12 * i), entry_font=menu_props.font, width=12,
            frame_col=menu_props.btn_col,
            initial_text=self.props.gameprops.player_name or _('your name'),
            text_fg=menu_props.text_active_col) for i in range(len(self.mediator.cars))]
        self.add_widgets(self.ents)
        self.add_widgets(widgets)
        ThanksPageGui.build(self, exit_behav=False)
        self.update_tsk = taskMgr.add(self.update_text, 'update text')
        self.enable_buttons(False)
Exemple #52
0
class HtmlView(DirectObject):
    notify = DirectNotifyGlobal.directNotify.newCategory('HtmlView')
    useHalfTexture = base.config.GetBool('news-half-texture', 0)

    def __init__(self, parent = aspect2d):
        global GlobalWebcore
        self.parent_ = parent
        self.mx = 0
        self.my = 0
        self.htmlFile = 'index.html'
        self.transparency = False
        if GlobalWebcore:
            pass
        else:
            GlobalWebcore = AwWebCore(AwWebCore.LOGVERBOSE, True, AwWebCore.PFBGRA)
            GlobalWebcore.setBaseDirectory('.')
            for errResponse in xrange(400, 600):
                GlobalWebcore.setCustomResponsePage(errResponse, 'error.html')

        self.webView = GlobalWebcore.createWebView(WEB_WIDTH, WEB_HEIGHT, self.transparency, False, 70)
        frameName = ''
        inGameNewsUrl = self.getInGameNewsUrl()
        self.imgBuffer = array.array('B')
        for i in xrange(WEB_WIDTH * WEB_HEIGHT):
            self.imgBuffer.append(0)
            self.imgBuffer.append(0)
            self.imgBuffer.append(0)
            self.imgBuffer.append(255)

        if self.useHalfTexture:
            self.leftBuffer = array.array('B')
            for i in xrange(WEB_HALF_WIDTH * WEB_HEIGHT):
                self.leftBuffer.append(0)
                self.leftBuffer.append(0)
                self.leftBuffer.append(0)
                self.leftBuffer.append(255)

            self.rightBuffer = array.array('B')
            for i in xrange(WEB_HALF_WIDTH * WEB_HEIGHT):
                self.rightBuffer.append(0)
                self.rightBuffer.append(0)
                self.rightBuffer.append(0)
                self.rightBuffer.append(255)

        self.setupTexture()
        if self.useHalfTexture:
            self.setupHalfTextures()
        self.accept('mouse1', self.mouseDown, [AwWebView.LEFTMOUSEBTN])
        self.accept('mouse3', self.mouseDown, [AwWebView.RIGHTMOUSEBTN])
        self.accept('mouse1-up', self.mouseUp, [AwWebView.LEFTMOUSEBTN])
        self.accept('mouse3-up', self.mouseUp, [AwWebView.RIGHTMOUSEBTN])

    def getInGameNewsUrl(self):
        result = base.config.GetString('fallback-news-url', 'http://cdn.toontown.disney.go.com/toontown/en/gamenews/')
        override = base.config.GetString('in-game-news-url', '')
        if override:
            self.notify.info('got an override url,  using %s for in a game news' % override)
            result = override
        else:
            try:
                launcherUrl = base.launcher.getValue('GAME_IN_GAME_NEWS_URL', '')
                if launcherUrl:
                    result = launcherUrl
                    self.notify.info('got GAME_IN_GAME_NEWS_URL from launcher using %s' % result)
                else:
                    self.notify.info('blank GAME_IN_GAME_NEWS_URL from launcher, using %s' % result)
            except:
                self.notify.warning('got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s' % result)

        return result

    def setupTexture(self):
        cm = CardMaker('quadMaker')
        cm.setColor(1.0, 1.0, 1.0, 1.0)
        aspect = base.camLens.getAspectRatio()
        htmlWidth = 2.0 * aspect * WEB_WIDTH_PIXELS / float(WIN_WIDTH)
        htmlHeight = 2.0 * float(WEB_HEIGHT_PIXELS) / float(WIN_HEIGHT)
        cm.setFrame(-htmlWidth / 2.0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0)
        bottomRightX = WEB_WIDTH_PIXELS / float(WEB_WIDTH + 1)
        bottomRightY = WEB_HEIGHT_PIXELS / float(WEB_HEIGHT + 1)
        cm.setUvRange(Point2(0, 1 - bottomRightY), Point2(bottomRightX, 1))
        card = cm.generate()
        self.quad = NodePath(card)
        self.quad.reparentTo(self.parent_)
        self.guiTex = Texture('guiTex')
        self.guiTex.setupTexture(Texture.TT2dTexture, WEB_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba)
        self.guiTex.setMinfilter(Texture.FTLinear)
        self.guiTex.setKeepRamImage(True)
        self.guiTex.makeRamImage()
        self.guiTex.setWrapU(Texture.WMRepeat)
        self.guiTex.setWrapV(Texture.WMRepeat)
        ts = TextureStage('webTS')
        self.quad.setTexture(ts, self.guiTex)
        self.quad.setTexScale(ts, 1.0, -1.0)
        self.quad.setTransparency(0)
        self.quad.setTwoSided(True)
        self.quad.setColor(1.0, 1.0, 1.0, 1.0)
        self.calcMouseLimits()

    def setupHalfTextures(self):
        self.setupLeftTexture()
        self.setupRightTexture()
        self.fullPnmImage = PNMImage(WEB_WIDTH, WEB_HEIGHT, 4)
        self.leftPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4)
        self.rightPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4)

    def setupLeftTexture(self):
        cm = CardMaker('quadMaker')
        cm.setColor(1.0, 1.0, 1.0, 1.0)
        aspect = base.camLens.getAspectRatio()
        htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH)
        htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT)
        cm.setFrame(-htmlWidth / 2.0, 0, -htmlHeight / 2.0, htmlHeight / 2.0)
        card = cm.generate()
        self.leftQuad = NodePath(card)
        self.leftQuad.reparentTo(self.parent_)
        self.leftGuiTex = Texture('guiTex')
        self.leftGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba)
        self.leftGuiTex.setKeepRamImage(True)
        self.leftGuiTex.makeRamImage()
        self.leftGuiTex.setWrapU(Texture.WMClamp)
        self.leftGuiTex.setWrapV(Texture.WMClamp)
        ts = TextureStage('leftWebTS')
        self.leftQuad.setTexture(ts, self.leftGuiTex)
        self.leftQuad.setTexScale(ts, 1.0, -1.0)
        self.leftQuad.setTransparency(0)
        self.leftQuad.setTwoSided(True)
        self.leftQuad.setColor(1.0, 1.0, 1.0, 1.0)

    def setupRightTexture(self):
        cm = CardMaker('quadMaker')
        cm.setColor(1.0, 1.0, 1.0, 1.0)
        aspect = base.camLens.getAspectRatio()
        htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH)
        htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT)
        cm.setFrame(0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0)
        card = cm.generate()
        self.rightQuad = NodePath(card)
        self.rightQuad.reparentTo(self.parent_)
        self.rightGuiTex = Texture('guiTex')
        self.rightGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba)
        self.rightGuiTex.setKeepRamImage(True)
        self.rightGuiTex.makeRamImage()
        self.rightGuiTex.setWrapU(Texture.WMClamp)
        self.rightGuiTex.setWrapV(Texture.WMClamp)
        ts = TextureStage('rightWebTS')
        self.rightQuad.setTexture(ts, self.rightGuiTex)
        self.rightQuad.setTexScale(ts, 1.0, -1.0)
        self.rightQuad.setTransparency(0)
        self.rightQuad.setTwoSided(True)
        self.rightQuad.setColor(1.0, 1.0, 1.0, 1.0)

    def calcMouseLimits(self):
        ll = Point3()
        ur = Point3()
        self.quad.calcTightBounds(ll, ur)
        self.notify.debug('ll=%s ur=%s' % (ll, ur))
        offset = self.quad.getPos(aspect2d)
        self.notify.debug('offset = %s ' % offset)
        ll.setZ(ll.getZ() + offset.getZ())
        ur.setZ(ur.getZ() + offset.getZ())
        self.notify.debug('new LL=%s, UR=%s' % (ll, ur))
        relPointll = self.quad.getRelativePoint(aspect2d, ll)
        self.notify.debug('relPoint = %s' % relPointll)
        self.mouseLL = (aspect2d.getScale()[0] * ll[0], aspect2d.getScale()[2] * ll[2])
        self.mouseUR = (aspect2d.getScale()[0] * ur[0], aspect2d.getScale()[2] * ur[2])
        self.notify.debug('original mouseLL=%s, mouseUR=%s' % (self.mouseLL, self.mouseUR))

    def writeTex(self, filename = 'guiText.png'):
        self.notify.debug('writing texture')
        self.guiTex.generateRamMipmapImages()
        self.guiTex.write(filename)

    def toggleRotation(self):
        if self.interval.isPlaying():
            self.interval.finish()
        else:
            self.interval.loop()

    def mouseDown(self, button):
        messenger.send('wakeup')
        self.webView.injectMouseDown(button)

    def mouseUp(self, button):
        self.webView.injectMouseUp(button)

    def reload(self):
        pass

    def zoomIn(self):
        self.webView.zoomIn()

    def zoomOut(self):
        self.webView.zoomOut()

    def toggleTransparency(self):
        self.transparency = not self.transparency
        self.webView.setTransparent(self.transparency)

    def update(self, task):
        if base.mouseWatcherNode.hasMouse():
            x, y = self._translateRelativeCoordinates(base.mouseWatcherNode.getMouseX(), base.mouseWatcherNode.getMouseY())
            if self.mx - x != 0 or self.my - y != 0:
                self.webView.injectMouseMove(x, y)
                self.mx, self.my = x, y
            if self.webView.isDirty():
                self.webView.render(self.imgBuffer.buffer_info()[0], WEB_WIDTH * 4, 4)
                Texture.setTexturesPower2(2)
                textureBuffer = self.guiTex.modifyRamImage()
                textureBuffer.setData(self.imgBuffer.tostring())
                if self.useHalfTexture:
                    self.guiTex.store(self.fullPnmImage)
                    self.leftPnmImage.copySubImage(self.fullPnmImage, 0, 0, 0, 0, WEB_HALF_WIDTH, WEB_HEIGHT)
                    self.rightPnmImage.copySubImage(self.fullPnmImage, 0, 0, WEB_HALF_WIDTH, 0, WEB_HALF_WIDTH, WEB_HEIGHT)
                    self.leftGuiTex.load(self.leftPnmImage)
                    self.rightGuiTex.load(self.rightPnmImage)
                    self.quad.hide()
                Texture.setTexturesPower2(1)
            GlobalWebcore.update()
        return Task.cont

    def _translateRelativeCoordinates(self, x, y):
        sx = int((x - self.mouseLL[0]) / (self.mouseUR[0] - self.mouseLL[0]) * WEB_WIDTH_PIXELS)
        sy = WEB_HEIGHT_PIXELS - int((y - self.mouseLL[1]) / (self.mouseUR[1] - self.mouseLL[1]) * WEB_HEIGHT_PIXELS)
        return (sx, sy)

    def unload(self):
        self.ignoreAll()
        self.webView.destroy()
        self.webView = None
        return

    def onCallback(self, name, args):
        if name == 'requestFPS':
            pass

    def onBeginNavigation(self, url, frameName):
        pass

    def onBeginLoading(self, url, frameName, statusCode, mimeType):
        pass

    def onFinishLoading(self):
        self.notify.debug('finished loading')

    def onReceiveTitle(self, title, frameName):
        pass

    def onChangeTooltip(self, tooltip):
        pass

    def onChangeCursor(self, cursor):
        pass

    def onChangeKeyboardFocus(self, isFocused):
        pass

    def onChangeTargetURL(self, url):
        pass
class MazeMapGui(DirectFrame):
    notify = directNotify.newCategory('MazeMapGui')

    def __init__(self,
                 mazeCollTable,
                 maskResolution=None,
                 radiusRatio=None,
                 bgColor=(0.8, 0.8, 0.8),
                 fgColor=(0.5, 0.5, 0.5, 1.0)):
        DirectFrame.__init__(self,
                             relief=None,
                             state=DGG.NORMAL,
                             sortOrder=DGG.BACKGROUND_SORT_INDEX)
        self.hide()
        self._bgColor = bgColor
        self._fgColor = fgColor
        self._mazeCollTable = mazeCollTable
        self._mazeWidth = len(self._mazeCollTable[0])
        self._mazeHeight = len(self._mazeCollTable)
        self._maskResolution = maskResolution or DEFAULT_MASK_RESOLUTION
        if radiusRatio is None:
            self._radius = self._maskResolution * DEFAULT_RADIUS_RATIO
        else:
            self._radius = self._maskResolution * radiusRatio
        self._revealedCells = []
        for y in range(self._mazeHeight):
            self._revealedCells.append([])
            for u in range(self._mazeWidth):
                self._revealedCells[y].append(False)

        self._revealFunctions = {
            MazeRevealType.SmoothCircle: self._revealSmoothCircle,
            MazeRevealType.HardCircle: self._revealHardCircle,
            MazeRevealType.Square: self._revealSquare
        }
        self._revealFunction = MAZE_REVEAL_TYPE
        self.map = self._createMapTextureCard()
        self.map.reparentTo(self)
        self.maskedLayer = self.attachNewNode('maskedLayer')
        self.mask = self._createMaskTextureCard()
        self.mask.reparentTo(self)
        self.visibleLayer = self.attachNewNode('visibleLayer')
        self._laffMeterModel = loader.loadModel(
            'phase_3/models/gui/laff_o_meter')
        self._toon2marker = {}
        return

    def _createMapTextureCard(self):
        mapImage = PNMImage(MAP_RESOLUTION, MAP_RESOLUTION)
        mapImage.fill(*self._bgColor)
        fgColor = VBase4D(*self._fgColor)
        for x in range(self._mazeHeight):
            for y in range(self._mazeWidth):
                if self._mazeCollTable[y][x] == 1:
                    ax = float(x) / self._mazeWidth * MAP_RESOLUTION
                    invertedY = self._mazeHeight - 1 - y
                    ay = float(invertedY) / self._mazeHeight * MAP_RESOLUTION
                    self._drawSquare(mapImage, int(ax), int(ay), 10, fgColor)

        mapTexture = Texture('mapTexture')
        mapTexture.setupTexture(Texture.TT2dTexture, self._maskResolution,
                                self._maskResolution, 1, Texture.TUnsignedByte,
                                Texture.FRgba)
        mapTexture.setMinfilter(Texture.FTLinear)
        mapTexture.load(mapImage)
        mapTexture.setWrapU(Texture.WMClamp)
        mapTexture.setWrapV(Texture.WMClamp)
        mapImage.clear()
        del mapImage
        cm = CardMaker('map_cardMaker')
        cm.setFrame(-1.0, 1.0, -1.0, 1.0)
        map = self.attachNewNode(cm.generate())
        map.setTexture(mapTexture, 1)
        return map

    def _createMaskTextureCard(self):
        self._maskImage = PNMImage(self._maskResolution, self._maskResolution,
                                   4)
        for x in range(self._maskResolution):
            for y in range(self._maskResolution):
                self._maskImage.setXelA(x, y, 0, 0, 0, 1)

        self.maskTexture = Texture('maskTexture')
        self.maskTexture.setupTexture(Texture.TT2dTexture,
                                      self._maskResolution,
                                      self._maskResolution, 1,
                                      Texture.TUnsignedByte, Texture.FRgba)
        self.maskTexture.setMinfilter(Texture.FTLinear)
        self.maskTexture.setWrapU(Texture.WMClamp)
        self.maskTexture.setWrapV(Texture.WMClamp)
        self.maskTexture.load(self._maskImage)
        base.graphicsEngine.renderFrame()
        cm = CardMaker('mask_cardMaker')
        cm.setFrame(-1.1, 1.1, -1.1, 1.1)
        mask = self.attachNewNode(cm.generate())
        mask.setTexture(self.maskTexture, 1)
        mask.setTransparency(1)
        return mask

    def _drawSquare(self, image, ulx, uly, size, color):
        x = int(ulx)
        while x <= ulx + size:
            y = int(uly)
            while y <= uly + size:
                if x > 0 and y > 0 and x < image.getXSize(
                ) and y < image.getYSize():
                    image.setXelA(x, y, color)
                y += 1

            x += 1

    def destroy(self):
        del self._mazeCollTable
        del self._maskResolution
        del self._radius
        del self._revealedCells
        del self._revealFunctions
        del self._revealFunction
        self.map.removeNode()
        del self.map
        self.mask.removeNode()
        del self.mask
        self.maskedLayer.removeNode()
        del self.maskedLayer
        self.visibleLayer.removeNode()
        del self.visibleLayer
        self._maskImage.clear()
        del self._maskImage
        self.maskTexture.clear()
        del self.maskTexture
        self._laffMeterModel.removeNode()
        del self._laffMeterModel
        DirectFrame.destroy(self)

    def _revealSmoothCircle(self, x, y, center):
        length = (Vec2(x, y) - center).length()
        goalAlpha = max(0.0, length / float(self._radius) - 0.5)
        self._maskImage.setXelA(
            x, y,
            VBase4D(0.0, 0.0, 0.0,
                    min(self._maskImage.getAlpha(x, y), goalAlpha * 2.0)))

    def _revealHardCircle(self, x, y, center):
        length = (Vec2(x, y) - center).length()
        if length <= self._radius:
            self._maskImage.setXelA(x, y, VBase4D(0, 0, 0, 0))

    def _revealSquare(self, x, y, center):
        self._maskImage.setXelA(x, y, VBase4D(0, 0, 0, 0))

    def _drawHole(self, x, y):
        center = Vec2(x, y)
        ul = center - Vec2(self._radius, self._radius)
        lr = center + Vec2(self._radius, self._radius)
        x = int(ul[0])
        while x <= lr[0]:
            y = int(ul[1])
            while y <= lr[1]:
                if x > 0 and y > 0 and x < self._maskResolution and y < self._maskResolution:
                    self._revealFunctions[self._revealFunction](x, y, center)
                y += 1

            x += 1

        self.maskTexture.load(self._maskImage)
        self.mask.setTexture(self.maskTexture, 1)

    def _createSimpleMarker(self, size, color=(1, 1, 1)):
        halfSize = size * 0.5
        cm = CardMaker('mazemap_simple_marker')
        cm.setFrame(-halfSize, halfSize, -halfSize, halfSize)
        markerNP = self.maskedLayer.attachNewNode(cm.generate())
        markerNP.setColor(*color)
        return markerNP

    def tile2gui(self, x, y):
        y = self._mazeHeight - y
        cellWidth = self._maskResolution / self._mazeWidth
        cellHeight = self._maskResolution / self._mazeHeight
        ax = float(x) / self._mazeWidth * self._maskResolution
        ax += cellWidth
        ay = float(y) / self._mazeHeight * self._maskResolution
        ay += cellHeight
        return (ax, ay)

    def gui2pos(self, x, y):
        return (x / self._maskResolution * 2.0 - 0.97, 0,
                y / self._maskResolution * -2.0 + 1.02)

    def _getToonMarker(self, toon):
        hType = toon.style.getType()
        if hType == 'rabbit':
            hType = 'bunny'
        return self._laffMeterModel.find('**/' + hType + 'head')

    def addToon(self, toon, tX, tY):
        marker = NodePath('toon_marker-%i' % toon.doId)
        marker.reparentTo(self)
        self._getToonMarker(toon).copyTo(marker)
        marker.setColor(toon.style.getHeadColor())
        if toon.isLocal():
            marker.setScale(0.07)
        else:
            marker.setScale(0.05)
        marker.flattenStrong()
        marker.setPos(*self.gui2pos(*self.tile2gui(tX, tY)))
        self._toon2marker[toon] = marker

    def removeToon(self, toon):
        if toon not in self._toon2marker:
            return
        self._toon2marker[toon].removeNode()
        del self._toon2marker[toon]

    def updateToon(self, toon, tX, tY):
        if toon not in self._toon2marker:
            return
        x, y = self.tile2gui(tX, tY)
        self._toon2marker[toon].setPos(*self.gui2pos(x, y))
        if tY < 0 or tY >= len(self._revealedCells):
            self.notify.warning('updateToon earlying out:')
            self.notify.warning('(tX, tY): (%s, %s)' % (tX, tY))
            self.notify.warning('len(_revealedCells): %s' %
                                (len(self._revealedCells), ))
            if len(self._revealedCells) > 0:
                self.notify.warning('len(_revealedCells[0]): %s' %
                                    (len(self._revealedCells[0]), ))
            return
        if tX < 0 or tX >= len(self._revealedCells[tY]):
            self.notify.warning('updateToon earlying out:')
            self.notify.warning('(tX, tY): (%s, %s)' % (tX, tY))
            self.notify.warning('len(_revealedCells): %s' %
                                (len(self._revealedCells), ))
            if tY < len(self._revealedCells):
                self.notify.warning('len(_revealedCells[tY]): %s' %
                                    (len(self._revealedCells[tY]), ))
            elif len(self._revealedCells) > 0:
                self.notify.warning('len(_revealedCells[0]): %s' %
                                    (len(self._revealedCells[0]), ))
            return
        if not self._revealedCells[tY][tX]:
            self._drawHole(x, y)
            self._revealedCells[tY][tX] = True

    def revealCell(self, x, y):
        ax, ay = self.tile2gui(x, y)
        if not self._revealedCells[y][x]:
            self._drawHole(ax, ay)
            self._revealedCells[y][x] = True

    def revealAll(self):
        for x in range(self._maskResolution):
            for y in range(self._maskResolution):
                self._maskImage.setXelA(x, y, 0, 0, 0, 0)

        self.revealCell(0, 0)

    def reset(self):
        for x in range(self._maskResolution):
            for y in range(self._maskResolution):
                self._maskImage.setXelA(x, y, 0, 0, 0, 1)
class WaterManager(DebugObject):

    """ Simple wrapper arround WaterDisplacement which combines 3 displacement
    maps into one, and also generates a normal map """

    def __init__(self):
        DebugObject.__init__(self, "WaterManager")
        self.options = OceanOptions()
        self.options.size = 512
        self.options.windDir.normalize()
        self.options.waveAmplitude *= 1e-7

        self.displacementTex = Texture("Displacement")
        self.displacementTex.setup2dTexture(
            self.options.size, self.options.size,
            Texture.TFloat, Texture.FRgba16)

        self.normalTex = Texture("Normal")
        self.normalTex.setup2dTexture(
            self.options.size, self.options.size,
            Texture.TFloat, Texture.FRgba16)

        self.combineShader = Shader.loadCompute(Shader.SLGLSL,
            "Shader/WaterFFT/Combine.compute")

        self.ptaTime = PTAFloat.emptyArray(1)

        # Create a gaussian random texture, as shaders aren't well suited
        # for that
        setRandomSeed(523)
        self.randomStorage = PNMImage(self.options.size, self.options.size, 4)
        self.randomStorage.setMaxval((2 ** 16) - 1)

        for x in xrange(self.options.size):
            for y in xrange(self.options.size):
                rand1 = self._getGaussianRandom() / 10.0 + 0.5
                rand2 = self._getGaussianRandom() / 10.0 + 0.5
                self.randomStorage.setXel(x, y, float(rand1), float(rand2), 0)
                self.randomStorage.setAlpha(x, y, 1.0)

        self.randomStorageTex = Texture("RandomStorage")
        self.randomStorageTex.load(self.randomStorage)
        self.randomStorageTex.setFormat(Texture.FRgba16)
        self.randomStorageTex.setMinfilter(Texture.FTNearest)
        self.randomStorageTex.setMagfilter(Texture.FTNearest)

        # Create the texture wwhere the intial height (H0 + Omega0) is stored.
        self.texInitialHeight = Texture("InitialHeight")
        self.texInitialHeight.setup2dTexture(
            self.options.size, self.options.size,
            Texture.TFloat, Texture.FRgba16)
        self.texInitialHeight.setMinfilter(Texture.FTNearest)
        self.texInitialHeight.setMagfilter(Texture.FTNearest)

        # Create the shader which populates the initial height texture
        self.shaderInitialHeight = Shader.loadCompute(Shader.SLGLSL,
            "Shader/WaterFFT/InitialHeight.compute")
        self.nodeInitialHeight = NodePath("initialHeight")
        self.nodeInitialHeight.setShader(self.shaderInitialHeight)
        self.nodeInitialHeight.setShaderInput("dest", self.texInitialHeight)
        self.nodeInitialHeight.setShaderInput(
            "N", LVecBase2i(self.options.size))
        self.nodeInitialHeight.setShaderInput(
            "patchLength", self.options.patchLength)
        self.nodeInitialHeight.setShaderInput("windDir", self.options.windDir)
        self.nodeInitialHeight.setShaderInput(
            "windSpeed", self.options.windSpeed)
        self.nodeInitialHeight.setShaderInput(
            "waveAmplitude", self.options.waveAmplitude)
        self.nodeInitialHeight.setShaderInput(
            "windDependency", self.options.windDependency)
        self.nodeInitialHeight.setShaderInput(
            "randomTex", self.randomStorageTex)

        self.attrInitialHeight = self.nodeInitialHeight.getAttrib(ShaderAttrib)

        self.heightTextures = []
        for i in xrange(3):

            tex = Texture("Height")
            tex.setup2dTexture(self.options.size, self.options.size,
                               Texture.TFloat, Texture.FRgba16)
            tex.setMinfilter(Texture.FTNearest)
            tex.setMagfilter(Texture.FTNearest)
            tex.setWrapU(Texture.WMClamp)
            tex.setWrapV(Texture.WMClamp)
            self.heightTextures.append(tex)

        # Also create the shader which updates the spectrum
        self.shaderUpdate = Shader.loadCompute(Shader.SLGLSL,
            "Shader/WaterFFT/Update.compute")
        self.nodeUpdate = NodePath("update")
        self.nodeUpdate.setShader(self.shaderUpdate)
        self.nodeUpdate.setShaderInput("outH0x", self.heightTextures[0])
        self.nodeUpdate.setShaderInput("outH0y", self.heightTextures[1])
        self.nodeUpdate.setShaderInput("outH0z", self.heightTextures[2])
        self.nodeUpdate.setShaderInput("initialHeight", self.texInitialHeight)
        self.nodeUpdate.setShaderInput("N", LVecBase2i(self.options.size))
        self.nodeUpdate.setShaderInput("time", self.ptaTime)
        self.attrUpdate = self.nodeUpdate.getAttrib(ShaderAttrib)

        # Create 3 FFTs
        self.fftX = GPUFFT(self.options.size, self.heightTextures[0],
                           self.options.normalizationFactor)
        self.fftY = GPUFFT(self.options.size, self.heightTextures[1],
                           self.options.normalizationFactor)
        self.fftZ = GPUFFT(self.options.size, self.heightTextures[2],
                           self.options.normalizationFactor)

        self.combineNode = NodePath("Combine")
        self.combineNode.setShader(self.combineShader)
        self.combineNode.setShaderInput(
            "displacementX", self.fftX.getResultTexture())
        self.combineNode.setShaderInput(
            "displacementY", self.fftY.getResultTexture())
        self.combineNode.setShaderInput(
            "displacementZ", self.fftZ.getResultTexture())
        self.combineNode.setShaderInput("normalDest", self.normalTex)
        self.combineNode.setShaderInput(
            "displacementDest", self.displacementTex)
        self.combineNode.setShaderInput(
            "N", LVecBase2i(self.options.size))
        self.combineNode.setShaderInput(
            "choppyScale", self.options.choppyScale)
        self.combineNode.setShaderInput(
            "gridLength", self.options.patchLength)
        # Store only the shader attrib as this is way faster
        self.attrCombine = self.combineNode.getAttrib(ShaderAttrib)

    def _getGaussianRandom(self):
        """ Returns a gaussian random number """
        u1 = generateRandom()
        u2 = generateRandom()
        if u1 < 1e-6:
            u1 = 1e-6
        return sqrt(-2 * log(u1)) * cos(2 * pi * u2)

    def setup(self):
        """ Setups the manager """

        Globals.base.graphicsEngine.dispatch_compute(
            (self.options.size / 16,
             self.options.size / 16, 1), self.attrInitialHeight,
            Globals.base.win.get_gsg())

    def getDisplacementTexture(self):
        """ Returns the displacement texture, storing the 3D Displacement in
        the RGB channels """
        return self.displacementTex

    def getNormalTexture(self):
        """ Returns the normal texture, storing the normal in world space in
        the RGB channels """
        return self.normalTex

    def update(self):
        """ Updates the displacement / normal map """

        self.ptaTime[0] = 1 + \
            Globals.clock.getFrameTime() * self.options.timeScale

        Globals.base.graphicsEngine.dispatch_compute(
            (self.options.size / 16,
             self.options.size / 16, 1), self.attrUpdate,
            Globals.base.win.get_gsg())

        self.fftX.execute()
        self.fftY.execute()
        self.fftZ.execute()

        # Execute the shader which combines the 3 displacement maps into
        # 1 displacement texture and 1 normal texture. We could use dFdx in
        # the fragment shader, however that gives no accurate results as
        # dFdx returns the same value for a 2x2 pixel block
        Globals.base.graphicsEngine.dispatch_compute(
            (self.options.size / 16,
             self.options.size / 16, 1), self.attrCombine,
            Globals.base.win.get_gsg())
Exemple #55
0
class Typist(object):

    TARGETS = {
        'paper': {
            'model': 'paper',
            'textureRoot': 'Front',
            'scale': Point3(0.85, 0.85, 1),
            'hpr': Point3(0, 0, 0),
        }
    }

    def __init__(self, base, typewriterNP, underDeskClip, sounds):
        self.base = base
        self.sounds = sounds
        self.underDeskClip = underDeskClip
        self.typeIndex = 0

        self.typewriterNP = typewriterNP
        self.rollerAssemblyNP = typewriterNP.find("**/roller assembly")
        assert self.rollerAssemblyNP
        self.rollerNP = typewriterNP.find("**/roller")
        assert self.rollerNP
        self.carriageNP = typewriterNP.find("**/carriage")
        assert self.carriageNP
        self.baseCarriagePos = self.carriageNP.getPos()
        self.carriageBounds = self.carriageNP.getTightBounds()

        self.font = base.loader.loadFont('Harting.ttf', pointSize=32)
        self.pnmFont = PNMTextMaker(self.font)
        self.fontCharSize, _, _ = fonts.measureFont(self.pnmFont, 32)
        print "font char size: ", self.fontCharSize

        self.pixelsPerLine = int(round(self.pnmFont.getLineHeight()))

        self.target = None
        """ panda3d.core.NodePath """
        self.targetRoot = None
        """ panda3d.core.NodePath """
        self.paperY = 0.0
        """ range from 0 to 1 """
        self.paperX = 0.0
        """ range from 0 to 1 """

        self.createRollerBase()

        self.tex = None
        self.texImage = None
        self.setupTexture()

        self.scheduler = Scheduler()
        task = self.base.taskMgr.add(self.tick, 'timerTask')
        task.setDelay(0.01)

    def tick(self, task):
        self.scheduler.tick(globalClock.getRealTime())
        return task.cont

    def setupTexture(self):
        """
        This is the overlay/decal/etc. which contains the typed characters.

        The texture size and the font size are currently tied together.
        :return:
        """
        self.texImage = PNMImage(1024, 1024)
        self.texImage.addAlpha()
        self.texImage.fill(1.0)
        self.texImage.alphaFill(1.0)

        self.tex = Texture('typing')
        self.tex.setMagfilter(Texture.FTLinear)
        self.tex.setMinfilter(Texture.FTLinear)

        self.typingStage = TextureStage('typing')
        self.typingStage.setMode(TextureStage.MModulate)

        self.tex.load(self.texImage)

        # ensure we can quickly update subimages
        self.tex.setKeepRamImage(True)

        # temp for drawing chars
        self.chImage = PNMImage(*self.fontCharSize)

    def drawCharacter(self, ch, px, py):
        """
        Draw a character onto the texture
        :param ch:
        :param px: paperX
        :param py: paperY
        :return: the paper-relative size of the character
        """

        h = self.fontCharSize[1]

        if ch != ' ':

            # position -> pixel, applying margins
            x = int(self.tex.getXSize() * (px * 0.8 + 0.1))
            y = int(self.tex.getYSize() * (py * 0.8 + 0.1))

            # always draw onto the paper, to capture
            # incremental character overstrikes
            self.pnmFont.generateInto(ch, self.texImage, x, y)

            if False:
                #print ch,"to",x,y,"w=",g.getWidth()
                self.tex.load(self.texImage)

            else:
                # copy an area (presumably) encompassing the character
                g = self.pnmFont.getGlyph(ord(ch))
                cx, cy = self.fontCharSize

                # a glyph is minimally sized and "moves around" in its text box
                # (think ' vs. ,), so it has been drawn somewhere relative to
                # the 'x' and 'y' we wanted.
                x += g.getLeft()
                y -= g.getTop()

                self.chImage.copySubImage(
                    self.texImage,
                    0,
                    0,  # from
                    x,
                    y,  # to
                    cx,
                    cy  # size
                )

                self.tex.loadSubImage(self.chImage, x, y)

            # toggle for a typewriter that uses non-proportional spacing
            #w = self.paperCharWidth(g.getWidth())
            w = self.paperCharWidth()

        else:

            w = self.paperCharWidth()

        return w, h

    def start(self):
        self.target = None
        self.setTarget('paper')

        self.hookKeyboard()

    def createRollerBase(self):
        """ The paper moves such that it is tangent to the roller.

        This nodepath keeps a coordinate space relative to that, so that
        the paper can be positioned from (0,0,0) to (0,0,1) to "roll" it
        along the roller.
        """
        bb = self.rollerNP.getTightBounds()

        #self.rollerNP.showTightBounds()
        self.paperRollerBase = self.rollerAssemblyNP.attachNewNode(
            'rollerBase')
        self.paperRollerBase.setHpr(0, -20, 0)

        print "roller:", bb
        rad = abs(bb[0].y - bb[1].y) / 2
        center = Vec3(-(bb[0].x + bb[1].x) / 2 - 0.03, (bb[0].y - bb[1].y) / 2,
                      (bb[0].z + bb[1].z) / 2)
        self.paperRollerBase.setPos(center)

    def setTarget(self, name):
        if self.target:
            self.target.removeNode()

        # load and transform the model
        target = self.TARGETS[name]
        self.target = self.base.loader.loadModel(target['model'])
        #self.target.setScale(target['scale'])
        self.target.setHpr(target['hpr'])

        # put it in the world
        self.target.reparentTo(self.paperRollerBase)

        rbb = self.rollerNP.getTightBounds()
        tbb = self.target.getTightBounds()

        rs = (rbb[1] - rbb[0])
        ts = (tbb[1] - tbb[0])

        self.target.setScale(rs.x / ts.x, 1, 1)

        # apply the texture
        self.targetRoot = self.target
        if 'textureRoot' in target:
            self.targetRoot = self.target.find("**/" + target['textureRoot'])
            assert self.targetRoot

        self.targetRoot.setTexture(self.typingStage, self.tex)

        #self.setupTargetClip()

        # reset
        self.paperX = self.paperY = 0.
        newPos = self.calcPaperPos(self.paperY)
        self.target.setPos(newPos)

        self.moveCarriage()

    def setupTargetClip(self):
        """
        The target is fed in to the typewriter but until we invent "geom curling",
        it shouldn't be visible under the typewriter under the desk.

        The @underDeskClip node has a world-relative bounding box, which
        we can convert to the target-relative bounding box, and pass to a
        shader that can clip the nodes.

        """
        shader = Shader.make(
            Shader.SLGLSL, """
#version 120

attribute vec4 p3d_MultiTexCoord0;
attribute vec4 p3d_MultiTexCoord1;

void main() {
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_TexCoord[0] = p3d_MultiTexCoord0;
    gl_TexCoord[1] = p3d_MultiTexCoord1;
}

            """, """
#version 120

uniform sampler2D baseTex;
uniform sampler2D charTex;
const vec4 zero = vec4(0, 0, 0, 0);
const vec4 one = vec4(1, 1, 1, 1);
const vec4 half = vec4(0.5, 0.5, 0.5, 0);

void main() {
    vec4 baseColor = texture2D(baseTex, gl_TexCoord[0].st);
    vec4 typeColor = texture2D(charTex, gl_TexCoord[1].st);
    gl_FragColor = baseColor * typeColor;

}""")

        self.target.setShader(shader)

        baseTex = self.targetRoot.getTexture()
        print "Base Texture:", baseTex
        self.target.setShaderInput("baseTex", baseTex)

        self.target.setShaderInput("charTex", self.tex)

    def hookKeyboard(self):
        """
        Hook events so we can respond to keypresses.
        """
        self.base.buttonThrowers[0].node().setKeystrokeEvent('keystroke')
        self.base.accept('keystroke', self.schedTypeCharacter)
        self.base.accept('backspace', self.schedBackspace)

        self.base.accept('arrow_up', lambda: self.schedAdjustPaper(-5))
        self.base.accept('arrow_up-repeat', lambda: self.schedAdjustPaper(-1))
        self.base.accept('arrow_down', lambda: self.schedAdjustPaper(5))
        self.base.accept('arrow_down-repeat', lambda: self.schedAdjustPaper(1))

        self.base.accept('arrow_left', lambda: self.schedAdjustCarriage(-1))
        self.base.accept('arrow_left-repeat',
                         lambda: self.schedAdjustCarriage(-1))
        self.base.accept('arrow_right', lambda: self.schedAdjustCarriage(1))
        self.base.accept('arrow_right-repeat',
                         lambda: self.schedAdjustCarriage(1))

    def paperCharWidth(self, pixels=None):
        if not pixels:
            pixels = self.fontCharSize[0]
        return float(pixels) / self.tex.getXSize()

    def paperLineHeight(self):
        return float(self.fontCharSize[1] * 1.2) / self.tex.getYSize()

    def schedScroll(self):
        if self.scheduler.isQueueEmpty():
            self.schedRollPaper(1)
            self.schedResetCarriage()

    def schedBackspace(self):
        if self.scheduler.isQueueEmpty():

            def doit():
                if self.paperX > 0:
                    self.schedAdjustCarriage(-1)

            self.scheduler.schedule(0.01, doit)

    def createMoveCarriageInterval(self, newX, curX=None):
        if curX is None:
            curX = self.paperX
        here = self.calcCarriage(curX)
        there = self.calcCarriage(newX)

        posInterval = LerpPosInterval(self.carriageNP,
                                      abs(newX - curX),
                                      there,
                                      startPos=here,
                                      blendType='easeIn')

        posInterval.setDoneEvent('carriageReset')

        def isReset():
            self.paperX = newX

        self.base.acceptOnce('carriageReset', isReset)
        return posInterval

    def schedResetCarriage(self):
        if self.paperX > 0.1:
            self.sounds['pullback'].play()

        invl = self.createMoveCarriageInterval(0)

        self.scheduler.scheduleInterval(0, invl)

    def calcCarriage(self, paperX):
        """
        Calculate where the carriage should be offset based
        on the position on the paper
        :param paperX: 0...1
        :return: pos for self.carriageNP
        """
        x = (0.5 - paperX) * 0.69 * 0.8 + 0.01

        bb = self.carriageBounds
        return self.baseCarriagePos + Point3(x * (bb[1].x - bb[0].x), 0, 0)

    def moveCarriage(self):
        pos = self.calcCarriage(self.paperX)
        self.carriageNP.setPos(pos)

    def schedMoveCarriage(self, curX, newX):
        if self.scheduler.isQueueEmpty():
            #self.scheduler.schedule(0.1, self.moveCarriage)
            invl = self.createMoveCarriageInterval(newX, curX=curX)
            invl.start()

    def schedAdjustCarriage(self, bx):
        if self.scheduler.isQueueEmpty():

            def doit():
                self.paperX = max(
                    0.0, min(1.0, self.paperX + bx * self.paperCharWidth()))
                self.moveCarriage()

            self.scheduler.schedule(0.1, doit)

    def calcPaperPos(self, paperY):
        # center over roller, peek out a little
        z = paperY * 0.8 - 0.5 + 0.175

        bb = self.target.getTightBounds()

        return Point3(-0.5, 0, z * (bb[1].z - bb[0].z))

    def createMovePaperInterval(self, newY):
        here = self.calcPaperPos(self.paperY)
        there = self.calcPaperPos(newY)

        posInterval = LerpPosInterval(self.target,
                                      abs(newY - self.paperY),
                                      there,
                                      startPos=here,
                                      blendType='easeInOut')

        posInterval.setDoneEvent('scrollDone')

        def isDone():
            self.paperY = newY

        self.base.acceptOnce('scrollDone', isDone)
        return posInterval

    def schedAdjustPaper(self, by):
        if self.scheduler.isQueueEmpty():

            def doit():
                self.schedRollPaper(by)

            self.scheduler.schedule(0.1, doit)

    def schedRollPaper(self, by):
        """
        Position the paper such that @percent of it is rolled over roller
        :param percent:
        :return:
        """
        def doit():
            self.sounds['scroll'].play()

            newY = min(1.0, max(0.0,
                                self.paperY + self.paperLineHeight() * by))

            invl = self.createMovePaperInterval(newY)
            invl.start()

        self.scheduler.schedule(0.1, doit)

    def schedTypeCharacter(self, keyname):
        # filter for visibility
        if ord(keyname) == 13:
            self.schedScroll()

        elif ord(keyname) >= 32 and ord(keyname) != 127:
            if self.scheduler.isQueueEmpty():
                curX, curY = self.paperX, self.paperY
                self.typeCharacter(keyname, curX, curY)

    def typeCharacter(self, ch, curX, curY):

        newX = curX

        w, h = self.drawCharacter(ch, curX, curY)

        newX += w

        if ch != ' ':
            # alternate typing sound
            #self.typeIndex = (self.typeIndex+1) % 3
            self.typeIndex = random.randint(0, 2)
            self.sounds['type' + str(self.typeIndex + 1)].play()

        else:
            self.sounds['advance'].play()

        if newX >= 1:
            self.sounds['bell'].play()
            newX = 1

        self.schedMoveCarriage(self.paperX, newX)

        # move first, to avoid overtype
        self.paperX = newX
def checkForLoad(task):
    
    #print globalClock.getAverageFrameRate()
    global model_queue
    
    checkQueue()
    
    try:
        action = load_queue.get_nowait()
    except Queue.Empty:
        action = None
    
    if EXIT_AFTER and action is None and base.num_models_loaded >= NUM_MODELS and base.quit and base.screenshot_frame > base.quit_frame:
        sys.exit(0)
    elif action is None and base.num_models_loaded >= NUM_MODELS and base.quit and base.screenshot_frame > base.quit_frame:
        base.render.analyze()
        base.quit = False
    
    if action is None:
        return task.cont

    action_type = action[0]
    
    if action_type == ActionType.LOAD_MODEL:
        model = action[1]
        print 'Queueing model for load:', model.model_json['full_path'], 'queue size', len(model_queue)
        model_queue.append(model)
        checkQueue()
    
    elif action_type == ActionType.UPDATE_TEXTURE:
        model = action[1]
        offset = action[2]
        data = action[3]
        print model.model_json['base_path'], 'needs texture updating offset', offset
        texpnm = PNMImage()
        texpnm.read(StringStream(data), 'something.jpg')
        newtex = Texture()
        newtex.load(texpnm)
        
        path_search = '**/*' + model.model_json['full_path'].replace('/', '_') + '*'
        np = render.find(path_search)
        
        np.setTextureOff(1)
        np.setTexture(newtex, 1)
    
    elif action_type == ActionType.PROGRESSIVE_ADDITION:
        model = action[1]
        refinements = action[2]
        
        path_search = '**/*' + model.model_json['full_path'].replace('/', '_') + '*'
        np = render.find(path_search)
        np = np.find("**/primitive")
        pnode = np.node()
        
        
        start = time.time()
        update_nodepath(pnode, refinements)
        end = time.time()
    
        print '---JUST UPDATED ' + model.model_json['full_path'] + ' ----'
        
    elif action_type == ActionType.QUIT:
        print 'Got a quit message, triggering quit flag'
        base.quit = True
    
    return task.cont