Giter VIP home page Giter VIP logo

bgui's People

Contributors

arielvb avatar kupoman avatar moguri avatar nickpolet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bgui's Issues

Unabled to load the image ../../themes/default/audio.png (with solution suggested)

Last Blender build (hash f70d966), Linux Mint Olivia

With the simple example the following error is returned:

Unabled to load the image ../../themes/default/audio.png

Caused by an invalid loaded image using ImageFFmpeg. Unfortunately this error is too common with PNG images (and many other alpha channel involved ones).

I suggest you to workaround the problem using the Qt loader to load the image, and then creating a buffer object for BGE. Following my texture.py:

# This module encapsulates texture loading so we are not dependent on bge.texture

HAVE_BGE_TEXTURE = False
HAVE_PYQT_TEXTURE = False

from .gl_utils import *

try:
    from bge import texture
    import aud
    HAVE_BGE_TEXTURE = True
except ImportError:
    print("Warning: bge cannot be imported")

try:
    from PyQt4 import QtOpenGL, QtGui
    HAVE_PYQT_TEXTURE = True
except ImportError:
    print("Warning: PyQt4 cannot be imported")
    try:
        from PySide import QtOpenGL, QtGui
        HAVE_PYQT_TEXTURE = True
    except ImportError:
        print("Warning: PySide cannot be imported either")


# We are using the Python duck typing to generate a phony blender image that
# store the image buffer and size
class ImageFromBuff:
    def __init__(self, buff, width, height):
        """Build the image data
        :param buff: Image data
        :param width: Image width
        :param height: Image height
        """
        self._image = buff
        self._size = [width, height]
        self._valid = True

    @property
    def image(self):
        """image data"""
        return self._image

    @property
    def size(self):
        """image size"""
        return self._size

    @property
    def valid(self):
        """bool to tell if an image is available"""
        return self._valid


class Texture:
    def __init__(self, path, interp_mode):
        self._tex_id = glGenTextures(1)
        self.size = [0, 0]
        self._interp_mode = None
        self.path = None

        # Setup some parameters
        self.bind()
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
        self.interp_mode = interp_mode

        self.reload(path)

    def __del__(self):
        glDeleteTextures([self._tex_id])

    @property
    def interp_mode(self):
        return self._interp_mode

    @interp_mode.setter
    def interp_mode(self, value):
        if value != self._interp_mode:
            self.bind()
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, value)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, value)
            self._interp_mode = value

    def bind(self):
        glBindTexture(GL_TEXTURE_2D, self._tex_id)


class ImageTexture(Texture):

    _cache = {}

    def __init__(self, image, interp_mode, caching):
        self._caching = caching
        super().__init__(image, interp_mode);

    def reload(self, image):
        if image == self.path:
            return

        img = None
        if image in ImageTexture._cache:
            # Image has already been loaded from disk, recall it from the cache
            img = ImageTexture._cache[image]
        else:
            # Load the image data from disk, try to use BGE first
            if HAVE_BGE_TEXTURE:
                img = texture.ImageFFmpeg(image)
                img.scale = False
                if not img.valid or img.image is None:
                    img = None
                elif self._caching:
                    ImageTexture._cache[image] = img
            # Try to use PyQt (or PySide) if BGE has failed
            if img is None and HAVE_PYQT_TEXTURE:
                qt_img = QtGui.QImage(image)
                if qt_img.isNull():
                    img = None
                else:
                    # Qt returns the image with a lot of weird format, so some
                    # operations must be applied before
                    qt_img = qt_img.convertToFormat(QtGui.QImage.Format_ARGB32)
                    qt_img = qt_img.mirrored()
                    qt_img = qt_img.rgbSwapped()
                    # Now we can extract the image data and create a valid
                    # object for BGE
                    data = qt_img.constBits()
                    size = qt_img.size()
                    data.setsize(qt_img.byteCount())
                    data = memoryview(data).tobytes()
                    channels = len(data) / (size.width() * size.height())
                    buff = Buffer(GL_BYTE,
                                  [len(data)],
                                  data)
                    img = ImageFromBuff(buff, size.width(), size.height())
                    if self._caching:
                        ImageTexture._cache[image] = img

        if img is None:
            print("Unable to load the image", image)
            return

        # Show the image with the appropiated backend
        data = img.image
        if not img.valid or data is None:
            print("Unhandled image exception...", image)
            return

        # Upload the texture data
        self.bind()
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.size[0], img.size[1],
                     0, GL_RGBA, GL_UNSIGNED_BYTE, data)

        self.image_size = img.size[:]

        # Save the image name
        self.path = image

        img = None


class VideoTexture(Texture):
    def __init__(self, video, interp_mode, repeat, play_audio):
        self.repeat = repeat
        self.play_audio = play_audio
        self.video = None
        self.audio = None

        super().__init__(video, interp_mode)

    def __del__(self):
        super().__del__()

        if self.audio:
            self.audio.stop()

        self.video = None

    def reload(self, video):
        if video == self.path:
            return

        if USING_BGE_TEXTURE:
            vid = texture.VideoFFmpeg(video)
            vid.repeat = self.repeat
            vid.play()
            self.video = vid
            data = vid.image

            if self.play_audio:
                self.audio = aud.device().play(aud.Factory(video))
        else:
            data = None

        if data == None:
            print("Unable to load the video", video)
            return

        self.bind()
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.size[0], vid.size[1],
                0, GL_RGBA, GL_UNSIGNED_BYTE, data)

        self.image_size = vid.size[:]
        self.path = video

    def update(self):
        if not self.video:
            return

        self.video.refresh()
        data = self.video.image
        if data:
            self.bind()
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.video.size[0], self.video.size[1],
                    0, GL_RGBA, GL_UNSIGNED_BYTE, data)

    def play(self, start, end, use_frames=True, fps=None):
        if not self.video:
            return

        start = float(start)
        end = float(end)

        if use_frames:
            if not fps:
                fps = self.video.framerate
                print("Using fps:", fps)
            start /= fps
            end /= fps

        if start == end:
            end += 0.1
        self.video.stop()
        self.video.range = [start, end]
        self.video.play()

As you can see I first try to load the image with BGE, but if it fails I fallback to the Qt stuff, loading the image (and conveniently formatting it), creating a BGE Buffer and finally storing it in a phony BGE texture.

I hope it helps!
Jose Luis Cercos Pita

Inconsistencies in widget size and position

I'll start with a quick example:

frame = bgui.Frame(self)
frame.size = [0.5, 0.5]  # Normalized values in
print(frame.size)  # Non-normalized values out

The above shows some unexpected behaviour (its also the same for position). If I'm writing my UI code, and I'm working in normalized coordinates I don't ever want to see or have to deal with pixel values. The fix for this should be simple enough, just do a check on access and convert to normalized values if needed. The problem is a lot of the existing code expects to receive a non-normalized value from those properties.

A second inconsistency has to do with _base_size and _base_pos. I may be wrong here, but from what I can see these represent the underlying coordinate system that bgui widgets use internally. However, depending on whether a widget has BGUI_NO_NORMALIZE set or not, the values stored will be either normalized or non-normalized. I feel that this behaviour is confusing.

I propose a change to the underlying size and position code to remove these inconsistencies.

  1. Variables _base_x and _base_y store the absolute pixel values of the bottom-left corner of the widget and variables _base_width and _base_height store the pixel values of the size of the widget
  2. Variables _x and _y store the relative normalized (or non-normalized, depending on options) value of the bottom-left corner of the widget and variables _width and _height store the normalized (or non-normalized) width and height of the widget
  3. Properties x, y and position as well as properties width, height and size for accessing and modifying the data. position returns [x, y], likewise for size

I found myself quite frequently only modifying the x position of a widget, or only changing the width of a widget, so having x and y properties will definitely be helpful. However I'm not sure on the usefulness of splitting them up into _base_x and _base_y and whether or not its just better to use _base_position.

As it stands the position and size side of things can be a little hard to predict and I think its important to simplify things. Let me know your thoughts, I'll be happy to lend a hand with code over the next few weeks.

Help wanted: port bgui to UPBGE 0.3

Hi, y'all!

I'm interested to port this to UPBGE 0.3 or pay someone talented enough for doing it. It does not work because it uses legacy opengl and the latest version of blender/upbge only allows modern OGL. Any bright soul willing to help? ๐Ÿ˜„

Thank you!

Caching disabled by default for images

ImageTexture arguments are "options & bgui.BGUI_CACHE", which I suspect is intended to be options | bgui.BGUI_CACHE

In addition to this, you cannot load an image at a later time for an Image if it is not initially given one.

Unable to create a themed frame without border (border==0)

If you want to override the border of a themed frame to size 0 when creating a new frame bgui.Frame(...,border=0) the frame will use the border theme value.

You can reproduce this following the next steps:

Advanced widgets

Shouldn't more advanced widgets like scrollable frames be made using simpler widget building blocks like frames, labels etc?

I ask cause I see a few people building them from scratch as opposed to using multiple simple widgets to form more complex ones.

Scrollbar?

Why in the 0.09 version there isn't a scrollbar widget?

Normalise Text/aspect ratio problem

Hi,

I cannot seem to get a correct aspect ratio/normalise text concerning my buttons (or anything) and inside the buttons. Two pictures below to show what I mean. In Windowed mode it looks good, but in Fullscreen it looks bad. I have tried putting Normalise_text = True and changing the aspect ratio but it does not seem to work...

Here is a simplified code of my application :

import bgui
import bgui.bge_utils
import bge

#This is the Main Layout. This never dissapears
class MainLayout(bgui.bge_utils.Layout):
"""A layout showcasing various Bgui features"""

def __init__(self, sys, data):
    super().__init__(sys, data)

    # Add widgets here

    # Use a frame to store all of our widgets
    self.frame = bgui.Frame(self, border=0)
    self.frame.colors = [(0, 0, 0, 0) for i in range(4)]

    # A FrameButton widget
    self.btn = bgui.FrameButton(self.frame, text='Import', size=[0.1, 0.05], pos=[0, 0.95], 
    base_color =(0,255,255,1), options=bgui.BGUI_DEFAULT)

    self.btn.on_click = self.button_click

    self.btn2 = bgui.FrameButton(self.frame, text='Start Simulation', size=[0.2, 0.05], pos=[0.1, 0.95],
          options=bgui.BGUI_DEFAULT)

    self.btn2.on_click = self.button_click2

    self.btn3 = bgui.FrameButton(self.frame, text='Stop Simulation', size=[0.2, 0.05], pos=[0.3, 0.95],
          options=bgui.BGUI_DEFAULT)

    self.btn3.on_click = self.button_click3


    #Simple TextBlock Widget
    self.txt = bgui.TextBlock(self.frame, color =(0,255,255,1), text ='Hello I am testing this',pt_size = 30,pos=[0,-0.95])

#These are the definitions
def button_click(self, widget):
self.lbl.text = 'This is the Import Button'
widget.system.toggle_overlay(testoverlay)

def button_click2(self, widget):
    self.lbl.text = "This starts the Simulation"

def button_click3(self, widget):
    self.lbl.text = "This Stops the Simulation"

def main(cont):
own = cont.owner
mouse = bge.logic.mouse

if 'sys' not in own:
    # Create our system and show the mouse
    own['sys'] = bgui.bge_utils.System('../../themes/default')
    own['sys'].load_layout(MainLayout, None)


    mouse.visible = True
    normalise_text=True
else:
    own['sys'].run()
    normalise_text=True

picture1
picture2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.