loading extern texture+sound+model PLUS some GUI-Stuff


I guess some of the problems are already addressed and I just missed them but maybe I can help some people with these snippets or maybe someone can show me better solutions:

  1. loading an image which exists already in the memory i.e. as in a Py-Buffer used by boost-python directly into a texture without using a PNMImage (Important: works only for 32bit image using a ARGB/XRGB format. Furthermore the orignal image is defined bottom-up):
def dataToTexture(imgdata, width, height):
    texture = Texture()
    texture.setup2dTexture(width, height, Texture.TUnsignedByte, Texture.FRgba)
    data = PTAUchar()
    texture.setRamImage(CPTAUchar(data), Texture.CMOff)
    return texture

Of course this code is not as mighty as the PNMImage but it redundantize one copyprocess afaik. Furthermore this can be used for a video by simply calling setRamImage by a task for every frame. The change of the texture-data will be automatically propageted to the device and the shown texture changes.

  1. loading a PCM (16 Bit, 2 Channels[1. word left, 2. word right, 3. word left and so on]), sound directly from i.e. a Py-Buffer. If looping is needed a simple task can help. Does not work with FMod because FMod does not support UserDataAudio as a source:
def playSound(sounddata, rate, volume):
    source = UserDataAudio(rate,2)
    sound = audiomgr.getSound(source)
  1. loading a extern model. This is no rocketscience too but maybe a helpful skeleton for someone who is not used to the vertex/index-bufferstuff. At least you have to replace modloader by your own loader:
    if ModelPool.hasModel(name):
        return ModelPool.loadModel(name)
        model = ModelRoot(name)
        geomnode = GeomNode(name)
        modloader = sf_loader.MODLoader() #replace this with your own model-loader
        modloader.load("VFX/MODULE/" + name)

        #a face is something like a limited plane (2D surface in 3D coords)
        for face in modloader.faces:
            triangles = GeomTriangles(Geom.UHStatic)

            #importTexture loads a texture by a name. just replace it with your own texture loader
            texture = importTexture(face.texture)
            geomdata = GeomVertexData("data", GeomVertexFormat.getV3n3t2(), Geom.UHStatic)
            vertexwriter = GeomVertexWriter(geomdata, InternalName.getVertex())
            normalwriter = GeomVertexWriter(geomdata, InternalName.getNormal())
            textcoordwriter = GeomVertexWriter(geomdata, InternalName.getTexcoord())
            for coord in face.texturecoords:
                relx = coord.x / float(texture.getXSize())
                rely = coord.y / float(texture.getYSize())
                textcoordwriter.addData2f(relx, rely)
            vertices = [modloader.points[index.id] for index in face.indices]
            A = Vec3(vertices[0].x, vertices[0].y, vertices[0].z)
            B = Vec3(vertices[1].x, vertices[1].y, vertices[1].z)
            C = Vec3(vertices[2].x, vertices[2].y, vertices[2].z)
            normal = (C - A).cross(B - A)
            for vertex in vertices:
                vertexwriter.addData3f(vertex.x, vertex.y, vertex.z)

            for counter in range(len(vertices) - 1):

            subset = Geom(geomdata)
            state = RenderState.make(TextureAttrib.make(texture))
            geomnode.addGeom(subset, state)
        return model

Now some GUI stuff/workarounds I needed in my project too:

  1. redirect a mouseclick event / message to the parent
def redirect(event,param):
    messenger.send(event, [param])

child.bind(DGG.B1PRESS, redirect, ["press-mouse1-" + parent.guiId])
  1. if one wants to map an image to a button directly and place it “semipixel-precise” (coords are given in pixel, relution sizes etc. are relative so resizing the windows does not mess the gui), one can use the following stuff. Attention: this is addressed to a window of 640x480. If you want to use i.e. 800x600 just replace the 320(=640/2) by 400(=800/2) and the 240(=480/2) by 300(=600/2). Furthermore the most-top-parent must be child of base.aspect2d. X,Y,Width,Height should be in range of 0…640,0…480,0…img.getXSize,0…img.getYSize. Of course the max of X and Y depends on the given windowsize.
def addImageButton(parent,img,x,y,align, com, param=[], pressedimg=None,hoverimg=None,disabledimg=None):
    if not pressedimg: pressedimg = img
    if not disabledimg: disabledimg = img
    if not hoverimg: hoverimg = img
    d = DirectButton(frameSize=PixelToSize(img.getXSize(),img.getYSize()),
                     frameTexture=(img,pressedimg,hoverimg,disabledimg), parent=parent,command=com, extraArgs=param, relief=1,
                     rolloverSound = None,clickSound = None, sortOrder=parent["sortOrder"])
    return d

def PixelToRel(x,y):
    return Vec3((x/320.0)*4/3,0,-y/240.0)

def PixelToPos(x,y,width,height,align):
    if align == "TopLeft":
        return PixelToRel(x,y)
    elif align == "TopRight":
        return PixelToRel(x-width,y)
    elif align == "TopCenter":
        return PixelToRel(x-width/2,y)
    elif align == "MidCenter":
        return PixelToRel(x-width/2,y-height/2)
    elif align == "BottomLeft":
        return PixelToRel(x,y-height)
    elif align == "BottomRight":
        return PixelToRel(x-width,y-height)
    elif align == "BottomCenter":
        return PixelToRel(x-width/2,y-height)
        raise Exception("align not defined: " + align)

def PixelToSize(width,height):