Exemplo n.º 1
0
    def SendAndRecv(self, sendCmd, sendValue, checkRecvCmd, checkReceiveValue):
        # send message - must be a tuple type
        self.pipe.send((sendCmd, sendValue))

        # wait recv message - must be a tuple type
        recv, value = self.pipe.recv()
        if self.simpleLog:
            logger.log(MINOR_INFO, "Pipe : Send %s and Recv %s in %s" % (
                get_command_name(sendCmd), get_command_name(recv), getTraceCallStack()))
        else:
            logger.log(MINOR_INFO, "Pipe : Send %s, %s and Recv %s, %s in %s" % (
                get_command_name(sendCmd), str(sendValue), get_command_name(recv), str(value), getTraceCallStack()))

        # check receive correct command and value
        if recv != checkRecvCmd or (checkReceiveValue is not None and checkReceiveValue != value):
            if self.simpleLog:
                logger.log(MINOR_INFO, "Pipe : RecvFailed %s and Send %s in %s" % (get_command_name(recv),
                                                                                   COMMAND.FAIL, getTraceCallStack()))
            else:
                logger.log(MINOR_INFO, "Pipe : RecvFailed %s, %s and Send %s, %s in %s" % (
                    get_command_name(recv), str(value), COMMAND.FAIL, "None", getTraceCallStack()))
            logger.error("ERROR : Received %s not %s" % (recv, checkRecvCmd))
            raise BaseException("Pipe receive error.")
        return value
Exemplo n.º 2
0
def get_numpy_dtype(data_type):
    if GL_BYTE == data_type:
        return np.int8
    elif GL_UNSIGNED_BYTE == data_type:
        return np.uint8
    elif GL_UNSIGNED_BYTE == data_type:
        return np.uint8
    elif GL_SHORT == data_type:
        return np.int16
    elif GL_UNSIGNED_SHORT == data_type:
        return np.uint16
    elif GL_INT == data_type:
        return np.int32
    elif GL_UNSIGNED_INT == data_type:
        return np.uint32
    elif GL_UNSIGNED_INT64 == data_type:
        return np.uint64
    elif GL_FLOAT == data_type:
        return np.float32
    elif GL_DOUBLE == data_type:
        return np.float64

    logger.error('Cannot convert to numpy dtype. UNKOWN DATA TYPE(%s)', data_type)
    return np.uint8
Exemplo n.º 3
0
    def IsExtensionSupported(TargetExtension):
        """ Accesses the rendering context to see if it supports an extension.
            Note, that this test only tells you if the OpenGL library supports
            the extension. The PyOpenGL system might not actually support the extension.
        """
        Extensions = glGetString(GL_EXTENSIONS)
        Extensions = Extensions.split()
        bTargetExtension = str.encode(TargetExtension)
        for extension in Extensions:
            if extension == bTargetExtension:
                break
        else:
            # not found surpport
            msg = "OpenGL rendering context does not support '%s'" % TargetExtension
            logger.error(msg)
            raise BaseException(msg)

        # Now determine if Python supports the extension
        # Exentsion names are in the form GL_<group>_<extension_name>
        # e.g.  GL_EXT_fog_coord
        # Python divides extension into modules
        # g_fVBOSupported = IsExtensionSupported ("GL_ARB_vertex_buffer_object")
        # from OpenGL.GL.EXT.fog_coord import *
        m = re.match(reCheckGLExtention, TargetExtension)
        if m:
            group_name = m.groups()[0]
            extension_name = m.groups()[1]
        else:
            msg = "GL unsupport error, %s" % TargetExtension
            logger.error(msg)
            raise BaseException(msg)

        extension_module_name = "OpenGL.GL.%s.%s" % (group_name,
                                                     extension_name)

        try:
            __import__(extension_module_name)
            logger.info("PyOpenGL supports '%s'" % TargetExtension)
        except:
            msg = 'Failed to import', extension_module_name
            logger.error(msg)
            raise BaseException(msg)
        return True
Exemplo n.º 4
0
 def parsing_matrix(self, xml_node):
     xml_matrix = xml_node.find('matrix')
     if xml_matrix is not None:
         # transform matrix
         matrix = get_xml_text(xml_matrix)
         matrix = [eval(x) for x in matrix.split()]
         if len(matrix) == 16:
             self.matrix = np.array(matrix, dtype=np.float32).reshape(4, 4)
     else:
         # location, rotation, scale
         xml_translate = xml_node.find('translate')
         if xml_translate is not None:
             translation = [
                 eval(x) for x in get_xml_text(xml_translate).split()
             ]
             if len(translation) == 3:
                 matrix_translate(self.matrix, *translation)
             else:
                 logger.error('%s node has a invalid translate.' %
                              self.name)
         xml_rotates = xml_node.findall('rotate')
         for xml_rotate in xml_rotates:
             rotation = [eval(x) for x in get_xml_text(xml_rotate).split()]
             if len(rotation) == 4:
                 axis = get_xml_attrib(xml_rotate, 'sid')
                 if axis == 'rotationX':
                     matrix_rotate_x(self.matrix, rotation[3])
                 elif axis == 'rotationY':
                     matrix_rotate_y(self.matrix, rotation[3])
                 elif axis == 'rotationZ':
                     matrix_rotate_z(self.matrix, rotation[3])
                 else:
                     logger.error('%s node has a invalid rotate.' %
                                  self.name)
         xml_scale = xml_node.find('scale')
         if xml_scale is not None:
             scale = [eval(x) for x in get_xml_text(xml_scale).split()]
             if len(scale) == 3:
                 matrix_scale(self.matrix, *scale)
             else:
                 logger.error('%s node has a invalid scale.' % self.name)
Exemplo n.º 5
0
    def initialize():
        try:
            logger.info("=" * 30)

            infos = [
                GL_VERSION, GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION
            ]
            for info in infos:
                info_string = glGetString(info)
                if type(info_string) == bytes:
                    info_string = info_string.decode("utf-8")
                logger.info("%s : %s" % (info.name, info_string))
                # set value
                setattr(OpenGLContext, info.name, info_string)

            infos = [
                GL_MAX_VERTEX_ATTRIBS, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
                GL_MAX_VERTEX_UNIFORM_COMPONENTS, GL_MAX_VERTEX_UNIFORM_BLOCKS,
                GL_MAX_GEOMETRY_UNIFORM_BLOCKS, GL_MAX_FRAGMENT_UNIFORM_BLOCKS,
                GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, GL_MAX_UNIFORM_BLOCK_SIZE,
                GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
                GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, GL_MAX_DRAW_BUFFERS,
                GL_MAX_TEXTURE_COORDS, GL_MAX_TEXTURE_IMAGE_UNITS,
                GL_MAX_VARYING_FLOATS
            ]
            for info in infos:
                logger.info("%s : %s" % (info.name, glGetIntegerv(info)))
                # set value
                setattr(OpenGLContext, info.name, glGetIntegerv(info))

            # shader storage
            infos = [
                GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
                GL_MAX_SHADER_STORAGE_BLOCK_SIZE,
                GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,
                GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,
                GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
                GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
                GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
                GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS,
                GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS
            ]
            for info in infos:
                logger.info("%s : %s" % (info.name, glGetIntegerv(info)))
                # set value
                setattr(OpenGLContext, info.name, glGetIntegerv(info))

            # compute shader
            OpenGLContext.GL_MAX_COMPUTE_WORK_GROUP_COUNT = [
                glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, i)[0]
                for i in range(3)
            ]
            OpenGLContext.GL_MAX_COMPUTE_WORK_GROUP_SIZE = [
                glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, i)[0]
                for i in range(3)
            ]
            logger.info("%s : %s" %
                        (GL_MAX_COMPUTE_WORK_GROUP_COUNT.name,
                         OpenGLContext.GL_MAX_COMPUTE_WORK_GROUP_COUNT))
            logger.info("%s : %s" %
                        (GL_MAX_COMPUTE_WORK_GROUP_SIZE.name,
                         OpenGLContext.GL_MAX_COMPUTE_WORK_GROUP_SIZE))

            # OpenGLContext.GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS = glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS)
            # logger.info("%s : %s" % (
            #   GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS.name, OpenGLContext.GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS
            # ))

            logger.info("=" * 30)

        except BaseException:
            logger.error(traceback.format_exc())
Exemplo n.º 6
0
def loadDDS(imagepath):
    if not os.path.exists(imagepath):
        logger.error("Cannot open %s file" % imagepath)
        return None

    with open(imagepath, "rb") as fp:
        filecode = struct.unpack("4s", fp.read(4))[0]

        if filecode.decode('ascii') != "DDS ":
            logger.error("%s is not dds file." % imagepath)
            return None

        # read header
        header = struct.unpack("124s", fp.read(124))[0]
        height = struct.unpack("I", header[8:12])[0]
        width = struct.unpack("I", header[12:16])[0]
        linearSize = struct.unpack("I", header[16:20])[0]
        mipMapCount = struct.unpack("I", header[24:28])[0]
        fourCC = struct.unpack("4s", header[80:84])[0]
        fourCC = fourCC.decode('ascii')

        # read buffer
        bufsize = (linearSize * 2) if mipMapCount > 1 else linearSize
        buffer = fp.read(bufsize)
        # buffer = np.asarray(buffer)
        buffer = np.fromstring(buffer, dtype=np.ubyte)

        # texture desc
        components = 4
        blockSize = 16
        format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
        if fourCC == "DXT1":
            format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
            components = 3
            blockSize = 8
        elif fourCC == "DXT3":
            format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
        elif fourCC == "DXT5":
            format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
        else:
            logger.error("not support %s format" % fourCC)
            return None

        # Create one OpenGL texture
        offset = 0
        textureID = glGenTextures(1)
        glBindTexture(GL_TEXTURE_2D, textureID)
        for level in range(mipMapCount):
            if width > 0 and height > 0:
                size = int((width + 3)/4) * int((height + 3)/4) * blockSize

                # TODO : implement glCompressedTexImage2D
                # glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, size, buffer.ctypes.data)
                glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, buffer)
                offset += size
                width /= 2
                height /= 2
            else:
                break
        return textureID
    return None
Exemplo n.º 7
0
def CreateUniformDataFromString(data_type, strValue=None):
    """ return converted data from string or default data """
    if data_type == 'bool':
        return np.bool(strValue) if strValue else np.bool(False)
    elif data_type == 'float':
        # return float(strValue) if strValue else 0.0
        return np.float32(strValue) if strValue else np.float32(0)
    elif data_type == 'int':
        # return int(strValue) if strValue else 0
        return np.int32(strValue) if strValue else np.int32(0)
    elif data_type == 'uint':
        # return int(strValue) if strValue else 0
        return np.uint32(strValue) if strValue else np.uint32(0)
    elif data_type in ('vec2', 'vec3', 'vec4', 'bvec2', 'bvec3', 'bvec4', 'ivec2', 'ivec3', 'ivec4', 'uvec2', 'uvec3', 'uvec4'):
        if data_type in ('bvec2', 'bvec3', 'bvec4', 'ivec2', 'ivec3', 'ivec4'):
            dtype = np.int32
        elif data_type in ('uvec2', 'uvec3', 'uvec4'):
            dtype = np.uint32
        else:
            dtype = np.float32

        componentCount = int(data_type[-1])
        if strValue is not None:
            vecValue = eval(strValue) if type(strValue) is str else strValue
            if len(vecValue) == componentCount:
                return np.array(vecValue, dtype=dtype)
            else:
                logger.error(ValueError("%s need %d float members." % (data_type, componentCount)))
                raise ValueError
        else:
            return np.array([1, ] * componentCount, dtype=dtype)
    elif data_type in ('mat2', 'mat3', 'mat4', 'dmat2', 'dmat3', 'dmat4'):
        if data_type in ('dmat2', 'dmat3', 'dmat4'):
            dtype = np.float32
        else:
            dtype = np.double
        componentCount = int(data_type[-1])
        if strValue is not None:
            vecValue = eval(strValue) if type(strValue) is str else strValue
            if len(vecValue) == componentCount:
                return np.array(vecValue, dtype=dtype)
            else:
                logger.error(ValueError("%s need %d float members." % (data_type, componentCount)))
                raise ValueError
        else:
            return np.eye(componentCount, dtype=dtype)
    elif data_type in ('sampler2D', 'image2D'):
        texture = CoreManager.instance().resource_manager.get_texture(strValue or 'common.flat_gray')
        return texture
    elif data_type == 'sampler2DMS':
        logger.warn('sampler2DMS need multisample texture.')
        return CoreManager.instance().resource_manager.get_texture(strValue or 'common.flat_gray')
    elif data_type == 'sampler2DArray':
        return CoreManager.instance().resource_manager.get_texture(strValue or 'common.default_2d_array')
    elif data_type in ('sampler3D', 'image3D'):
        return CoreManager.instance().resource_manager.get_texture(strValue or 'common.default_3d')
    elif data_type == 'samplerCube':
        texture = CoreManager.instance().resource_manager.get_texture(strValue or 'common.default_cube')
        return texture

    error_message = 'Cannot find uniform data of %s.' % data_type
    logger.error(error_message)
    raise ValueError(error_message)
    return None
Exemplo n.º 8
0
 def bind_uniform(self, texture, level=0, access=GL_READ_WRITE):
     if texture is not None:
         texture.bind_image(self.textureIndex, level, access)
     elif self.show_message:
         self.show_message = False
         logger.error("%s %s is None" % (self.name, self.__class__.__name__))
Exemplo n.º 9
0
    def initialize(self, cmdQueue, uiCmdQueue, cmdPipe, project_filename=""):
        # process start
        logger.info('Platform : %s' % platformModule.platform())
        logger.info("Process Start : %s" % GetClassName(self))

        self.cmdQueue = cmdQueue
        self.uiCmdQueue = uiCmdQueue
        self.cmdPipe = cmdPipe

        self.config = Config("config.ini", log_level)

        self.regist_command()

        # ready to launch - send message to ui
        if self.cmdPipe:
            self.cmdPipe.SendAndRecv(COMMAND.UI_RUN, None, COMMAND.UI_RUN_OK,
                                     None)

        from PyEngine3D.UI import ViewportManager
        from PyEngine3D.OpenGLContext import OpenGLContext
        from PyEngine3D.ResourceManager import ResourceManager
        from PyEngine3D.Render import Renderer, RenderTargetManager, FontManager, RenderOptionManager, EffectManager
        from .SceneManager import SceneManager
        from .ProjectManager import ProjectManager

        self.opengl_context = OpenGLContext
        self.viewport_manager = ViewportManager.instance()
        self.render_option_manager = RenderOptionManager.instance()
        self.rendertarget_manager = RenderTargetManager.instance()
        self.resource_manager = ResourceManager.instance()
        self.font_manager = FontManager.instance()
        self.renderer = Renderer.instance()
        self.scene_manager = SceneManager.instance()
        self.effect_manager = EffectManager.instance()
        self.project_manager = ProjectManager.instance()

        # check invalid project
        if not self.project_manager.initialize(self, project_filename):
            self.valid = False
            self.exit()
            return False

        # do First than other manager initalize. Because have to been opengl init from pygame.display.set_mode
        width, height = self.project_manager.config.Screen.size
        full_screen = self.project_manager.config.Screen.full_screen

        if self.config.hasValue('Project', 'game_backend'):
            self.last_game_backend = self.config.getValue(
                'Project', 'game_backend')

        self.last_game_backend = self.last_game_backend.lower()

        def run_pygame():
            from .GameBackend import GameBackend_pygame
            self.game_backend = GameBackend_pygame.PyGame(self)
            self.last_game_backend = GameBackNames.PYGAME

        def run_pyglet():
            from .GameBackend import GameBackend_pyglet
            self.game_backend = GameBackend_pyglet.PyGlet(self)
            self.last_game_backend = GameBackNames.PYGLET

        # try 2 times.
        for i in range(2):
            if self.last_game_backend == GameBackNames.PYGAME:
                try:
                    run_pygame()
                    break
                except:
                    logger.error(
                        "The pygame library does not exist and execution failed. Run again with the pyglet."
                    )
                    self.last_game_backend = GameBackNames.PYGLET
            else:
                try:
                    run_pyglet()
                    break
                except:
                    logger.error(
                        "The pyglet library does not exist and execution failed. Run again with the pygame."
                    )
                    self.last_game_backend = GameBackNames.PYGAME
        else:
            logger.error(
                'PyGame or PyGlet is required. Please run "pip install -r requirements.txt" and try again.'
            )
            # send a message to close ui
            if self.uiCmdQueue:
                self.uiCmdQueue.put(COMMAND.CLOSE_UI)
            return False

        self.game_backend.create_window(width, height, full_screen)
        self.opengl_context.initialize()
        self.send_game_backend_list(self.game_backend_list)
        index = self.game_backend_list.index(
            self.last_game_backend
        ) if self.last_game_backend in self.game_backend_list else 0
        self.send_current_game_backend_index(index)

        if not self.game_backend.valid:
            self.error('game_backend initializing failed')

        # initialize managers
        self.resource_manager.initialize(self,
                                         self.project_manager.project_dir)
        self.viewport_manager.initialize(self)
        self.render_option_manager.initialize(self)
        self.rendertarget_manager.initialize(self)
        self.font_manager.initialize(self)
        self.renderer.initialize(self)
        self.effect_manager.initialize(self)
        self.scene_manager.initialize(self)

        self.viewport_manager.build_ui()

        self.script_manager = None
        # self.load_script_manager(reload=False)

        # new scene
        self.game_backend.reset_screen()
        self.scene_manager.new_scene()

        self.send(COMMAND.SORT_UI_ITEMS)
        return True
Exemplo n.º 10
0
    def update(self):
        current_time = time.perf_counter()
        delta = current_time - self.current_time

        if self.vsync and delta < self.limit_delta or delta == 0.0:
            return

        self.acc_time += delta
        self.frame_count += 1
        self.curr_min_delta = min(delta, self.curr_min_delta)
        self.curr_max_delta = max(delta, self.curr_max_delta)

        # set timer
        self.current_time = current_time
        self.delta = delta
        self.fps = 1.0 / delta

        self.update_time = delta * 1000.0  # millisecond

        start_time = time.perf_counter()

        if self.video_resized and self.video_resize_time < self.current_time:
            self.video_resized = False
            self.video_resize_time = 0
            self.game_backend.resize_scene_to_window()

        touch_event = self.viewport_manager.update(delta)

        self.update_command()

        self.resource_manager.update()

        if not touch_event and self.viewport_manager.main_viewport.collide(
                *self.get_mouse_pos()):
            if self.is_play_mode:
                if self.script_manager is not None:
                    try:
                        self.script_manager.update(delta)
                    except:
                        logger.error(traceback.format_exc())
            else:
                self.update_camera()

        self.scene_manager.update_scene(delta)

        # Start Render Scene

        end_time = time.perf_counter()
        self.logic_time = (end_time - start_time) * 1000.0  # millisecond
        start_time = end_time

        if not self.video_resized:
            # render_light_probe scene
            self.renderer.render_light_probe(
                self.scene_manager.main_light_probe)

            # render sceme
            self.renderer.render_scene()

            # render viewport
            self.viewport_manager.render()

            end_time = time.perf_counter()
            self.render_time = (end_time - start_time) * 1000.0  # millisecond
            start_time = end_time

            # end of render scene
            self.opengl_context.present()

            # swap buffer
            self.game_backend.flip()

            end_time = time.perf_counter()
            self.present_time = (end_time - start_time) * 1000.0  # millisecond

        self.acc_logic_time += self.logic_time
        self.acc_gpu_time += self.gpu_time
        self.acc_render_time += self.render_time
        self.acc_present_time += self.present_time

        if 1.0 < self.acc_time:
            self.avg_logic_time = self.acc_logic_time / self.frame_count
            self.avg_gpu_time = self.acc_gpu_time / self.frame_count
            self.avg_render_time = self.acc_render_time / self.frame_count
            self.avg_present_time = self.acc_present_time / self.frame_count

            self.acc_logic_time = 0.0
            self.acc_gpu_time = 0.0
            self.acc_render_time = 0.0
            self.acc_present_time = 0.0

            self.min_delta = self.curr_min_delta * 1000.0
            self.max_delta = self.curr_max_delta * 1000.0
            self.curr_min_delta = sys.float_info.max
            self.curr_max_delta = sys.float_info.min
            self.avg_ms = self.acc_time / self.frame_count * 1000.0
            self.avg_fps = 1000.0 / self.avg_ms
            self.frame_count = 0
            self.acc_time = 0.0

        # debug info
        # print(self.fps, self.update_time)
        self.font_manager.log("%.2f fps" % self.avg_fps)
        self.font_manager.log("%.2f ms (%.2f ms ~ %.2f ms)" %
                              (self.avg_ms, self.min_delta, self.max_delta))
        self.font_manager.log("CPU : %.2f ms" % self.avg_logic_time)
        self.font_manager.log("GPU : %.2f ms" % self.avg_gpu_time)
        self.font_manager.log("Render : %.2f ms" % self.avg_render_time)
        self.font_manager.log("Present : %.2f ms" % self.avg_present_time)

        render_count = len(self.scene_manager.skeleton_solid_render_infos)
        render_count += len(
            self.scene_manager.skeleton_translucent_render_infos)
        render_count += len(self.scene_manager.static_solid_render_infos)
        render_count += len(self.scene_manager.static_translucent_render_infos)
        self.font_manager.log("Render Count : %d" % render_count)
        self.font_manager.log("Point Lights : %d" %
                              self.scene_manager.point_light_count)
        self.font_manager.log("Effect Count : %d" %
                              len(self.effect_manager.render_effects))
        self.font_manager.log("Particle Count : %d" %
                              self.effect_manager.alive_particle_count)

        # selected object transform info
        selected_object = self.scene_manager.get_selected_object()
        if selected_object:
            self.font_manager.log("Selected Object : %s" %
                                  selected_object.name)
            if hasattr(selected_object, 'transform'):
                self.font_manager.log(
                    selected_object.transform.get_transform_infos())
        self.gpu_time = (time.perf_counter() - start_time) * 1000.0

        if self.need_to_gc_collect:
            self.need_to_gc_collect = False
            gc.collect()
Exemplo n.º 11
0
 def error(self, msg):
     logger.error(msg)
     self.close()
Exemplo n.º 12
0
def generate_font_data(resource_name,
                       distance_field_font,
                       anti_aliasing,
                       font_size,
                       padding,
                       unicode_block_name,
                       range_min,
                       range_max,
                       source_filepath,
                       preview_path=''):
    logger.info("Convert Font %s %s : %s" %
                (resource_name, unicode_block_name, source_filepath))

    back_ground_color = (0, 0, 0)
    font_color = (255, 255, 255)
    count = abs(range_max - range_min) + 1
    count_of_side = int(math.ceil(math.sqrt(count)))
    # make texture size to power of 2.
    # texture_size = (2 ** math.ceil(math.log2(texture_size))) if 4 < texture_size else 4

    try:
        unicode_font = ImageFont.truetype(source_filepath,
                                          font_size - padding * 2)
    except:
        logger.error(traceback.format_exc())
        return None

    max_font_size = font_size
    for unicode_index in range(range_min, range_max + 1):
        unicode_text = chr(
            unicode_index
        )  # u"\u2605" + u"\u2606" + u"Текст на русском" + u"파이썬"
        width, height = unicode_font.getsize(unicode_text)
        max_font_size = max(max_font_size, max(width, height))

    font_size = max_font_size

    texture_size = font_size * count_of_side

    if texture_size > 8096:
        logger.error("%s texture size is too large. %d" %
                     (unicode_block_name, texture_size))
        return None

    image = Image.new("RGB", (texture_size, texture_size), back_ground_color)
    draw = ImageDraw.Draw(image)

    if anti_aliasing:
        draw.fontmode = "L"
    else:
        draw.fontmode = "1"

    unicode_index = range_min
    for y in range(count_of_side):
        for x in range(count_of_side):
            unicode_text = chr(
                unicode_index
            )  # u"\u2605" + u"\u2606" + u"Текст на русском" + u"파이썬"

            draw.text((x * font_size, y * font_size),
                      unicode_text,
                      font=unicode_font,
                      fill=font_color)
            unicode_index += 1
            if unicode_index >= range_max:
                break
        else:
            continue
        break

    # Flip Vertical
    # image = image.transpose(Image.FLIP_TOP_BOTTOM)

    image_data = image.tobytes("raw", image.mode, 0, -1)

    if distance_field_font:
        image_data = DistanceField(font_size, image.size[0], image.size[1],
                                   image.mode, image_data)

    # save for preview
    if preview_path:
        texture_name = "_".join([resource_name, unicode_block_name])
        image = Image.frombytes(image.mode, image.size, image_data)
        image.save(os.path.join(preview_path, texture_name + ".png"))
        # image.show()

    font_data = dict(unicode_block_name=unicode_block_name,
                     range_min=range_min,
                     range_max=range_max,
                     text_count=count,
                     font_size=font_size,
                     count_of_side=count_of_side,
                     image_mode=image.mode,
                     image_width=image.size[0],
                     image_height=image.size[1],
                     image_data=image_data,
                     texture=None)

    return font_data
Exemplo n.º 13
0
def CreateVertexArrayBuffer(geometry_data):
    geometry_name = geometry_data.get('name', 'VertexArrayBuffer')
    # logger.info("Load %s geometry." % geometry_name)

    mode = geometry_data.get('mode', GL_TRIANGLES)
    positions = geometry_data.get('positions', [])
    indices = geometry_data.get('indices', [])
    bone_indicies = geometry_data.get('bone_indicies', [])
    bone_weights = geometry_data.get('bone_weights', [])

    vertex_count = len(positions)
    if 0 == vertex_count:
        logger.error("%s geometry has no position data." % geometry_name)
        return None

    if 0 == len(indices):
        logger.error("%s geometry has no index data." % geometry_name)
        return None

    if not isinstance(positions, np.ndarray):
        positions = np.array(positions, dtype=np.float32)

    if not isinstance(indices, np.ndarray):
        indices = np.array(indices, dtype=np.uint32)

    if not isinstance(bone_indicies, np.ndarray):
        bone_indicies = np.array(bone_indicies, dtype=np.float32)

    if not isinstance(bone_weights, np.ndarray):
        bone_weights = np.array(bone_weights, dtype=np.float32)

    colors = geometry_data.get('colors', [
        [1.0, 1.0, 1.0, 1.0],
    ] * vertex_count)
    texcoords = geometry_data.get('texcoords', [
        [0.0, 0.0],
    ] * vertex_count)
    normals = geometry_data.get('normals', [
        [1.0, 1.0, 1.0],
    ] * vertex_count)
    tangents = geometry_data.get('tangents', [])

    if not isinstance(colors, np.ndarray):
        colors = np.array(colors, dtype=np.float32)

    if not isinstance(texcoords, np.ndarray):
        texcoords = np.array(texcoords, dtype=np.float32)

    if not isinstance(normals, np.ndarray):
        normals = np.array(normals, dtype=np.float32)

    if not isinstance(tangents, np.ndarray):
        tangents = np.array(tangents, dtype=np.float32)

    if len(tangents) == 0:
        is_triangle_mode = (GL_TRIANGLES == mode)
        tangents = compute_tangent(is_triangle_mode, positions, texcoords,
                                   normals, indices)

    if 0 < len(bone_indicies) and 0 < len(bone_weights):
        vertex_array_buffer = VertexArrayBuffer(geometry_name, mode, [
            positions, colors, normals, tangents, texcoords, bone_indicies,
            bone_weights
        ], indices)
    else:
        vertex_array_buffer = VertexArrayBuffer(
            geometry_name, mode,
            [positions, colors, normals, tangents, texcoords], indices)
    return vertex_array_buffer
Exemplo n.º 14
0
 def bind_texture(self, wrap=None):
     logger.error('%s RenderBuffer cannot use bind_texture method.' %
                  self.name)
Exemplo n.º 15
0
    def __parsing_final_code__(self,
                               is_engine_resource,
                               engine_shader_directory,
                               project_shader_directory,
                               shader_type_name,
                               shader_version,
                               compile_option,
                               external_macros={}):
        if self.shader_code == "" or self.shader_code is None:
            return ""

        # remove comment block
        shader_code = re.sub(reComment, "", self.shader_code)
        code_lines = shader_code.splitlines()

        # combine macro
        combined_macros = OrderedDict()
        # default macro
        for macro in self.default_macros:
            combined_macros[macro] = self.default_macros[macro]
        # shader type macro
        combined_macros[shader_type_name] = "1"

        # external macro
        if external_macros is None:
            external_macros = {}

        for macro in external_macros:
            if external_macros[macro] is None or external_macros[macro] is '':
                combined_macros[macro] = 0
            else:
                combined_macros[macro] = external_macros[macro]

        # insert shader version - ex) #version 430 core
        final_code_lines = [
            shader_version, "# extension GL_EXT_texture_array : enable"
        ]

        # insert defines to final code
        for macro in combined_macros:
            final_code_lines.append("#define %s %s" %
                                    (macro, str(combined_macros[macro])))

        # global texture function
        if ShaderCompileOption.USE_GLOBAL_TEXTURE_FUNCTION in compile_option:
            final_code_lines.append("#if __VERSION__ >= 130")
            # ex) replace texture2D -> texutre, textureCubeLod -> textureLod
            for texture_target in texture_targets:
                if "Lod" in texture_target:
                    final_code_lines.append("#define %s textureLod" %
                                            texture_target)
                elif "Grad" in texture_target:
                    final_code_lines.append("#define %s textureGrad" %
                                            texture_target)
                else:
                    final_code_lines.append("#define %s texture" %
                                            texture_target)
            final_code_lines.append("#endif")

        # insert version as comment
        include_files = dict()  # { 'filename': uuid }

        # do parsing
        line_num = 0
        macro_depth = 0
        macro_result = [
            True,
        ]
        macro_code_remove = True
        while line_num < len(code_lines):
            code = code_lines[line_num]
            line_num += 1

            # remove comment
            if "//" in code:
                code = code.split("//")[0]

            # macro parsing
            m = re.search(reMacroStart, code)
            if m is not None:
                macro, expression = m.groups()
                expression = expression.strip()
                if macro == 'define' or macro == 'undef':
                    define_expression = expression.split('(')[0].strip()
                    if ' ' in define_expression:
                        define_name, define_value = define_expression.split(
                            ' ', 1)
                    else:
                        define_name, define_value = define_expression, None

                    # check external macro
                    if macro == 'define' and define_name in external_macros:
                        continue  # ignore legacy macro

                    if macro == 'define' and define_name not in combined_macros:
                        combined_macros[define_name] = define_value
                    elif macro == 'undef' and define_name in combined_macros:
                        combined_macros.pop(define_name)
                elif macro == 'ifdef':
                    macro_depth += 1
                    if expression in combined_macros:
                        macro_result.append(True)
                    else:
                        macro_result.append(False)
                elif macro == 'ifndef':
                    macro_depth += 1
                    if expression not in combined_macros:
                        macro_result.append(True)
                    else:
                        macro_result.append(False)
                elif macro == 'if' or macro == 'elif' and not macro_result[
                        macro_depth]:
                    variables = re.findall(reVariable, expression)
                    variables.sort(key=lambda x: len(x), reverse=True)
                    for variable in variables:
                        if variable in combined_macros:
                            while True:
                                final_value = combined_macros[variable]
                                if final_value not in combined_macros:
                                    break
                                variable = final_value
                            expression = re.sub(reVariable, str(final_value),
                                                expression, 1)
                    expression = expression.replace('&&', ' and ')
                    expression = expression.replace('||', ' or ')
                    # expression = re.sub('\!?!\=', 'not ', expression)
                    # Important : To avoid errors, convert the undecalred variables to zero.
                    expression = re.sub(reVariable, '0', expression)
                    result = True if eval(expression) else False
                    if macro == 'if':
                        macro_depth += 1
                        macro_result.append(result)
                    elif macro == 'elif':
                        macro_result[macro_depth] = result
                elif macro == 'else':
                    macro_result[macro_depth] = not macro_result[macro_depth]
                elif macro == 'endif':
                    macro_depth -= 1
                    macro_result.pop()
            # be in failed macro block. continue
            elif not macro_result[macro_depth]:
                if not macro_code_remove:
                    # make comment
                    final_code_lines.append("// " + code)
                continue

            # is version code?
            m = re.search(reVersion, code)
            if m is not None:
                version_code = m.groups()[0].strip()
                if final_code_lines[
                        0] == "" or version_code > final_code_lines[0]:
                    final_code_lines[0] = version_code
                continue

            # find include block
            m = re.search(reInclude, code)
            if m is not None:
                is_include_file_exists = False
                include_file_in_engine = os.path.join(engine_shader_directory,
                                                      m.groups()[0])
                include_file_in_project = os.path.join(
                    project_shader_directory,
                    m.groups()[0])
                if is_engine_resource:
                    if os.path.exists(include_file_in_engine):
                        include_file = include_file_in_engine
                        is_include_file_exists = True
                    else:
                        include_file = include_file_in_project
                else:
                    if os.path.exists(include_file_in_project):
                        include_file = include_file_in_project
                        is_include_file_exists = True
                    else:
                        include_file = include_file_in_engine

                # insert include code
                valid = False
                if is_include_file_exists or os.path.exists(include_file):
                    try:
                        f = codecs.open(include_file,
                                        mode='r',
                                        encoding='utf-8')
                        include_source = f.read()
                        # remove comment block
                        include_source = re.sub(reComment, "", include_source)
                        include_code_lines = include_source.splitlines()
                        f.close()
                        valid = True
                    except BaseException:
                        logger.error(traceback.format_exc())

                    if valid:
                        if include_file in include_files:
                            unique_id = include_files[include_file]
                        else:
                            unique_id = "UUID_" + str(
                                uuid.uuid3(uuid.NAMESPACE_DNS,
                                           include_file)).replace("-", "_")
                            include_files[include_file] = unique_id

                            if include_file not in self.include_files:
                                self.include_files.append(include_file)
                        # insert included code
                        final_code_lines.append(
                            "//------------ INCLUDE -------------//")
                        final_code_lines.append("// " +
                                                code)  # include comment
                        include_code_lines.insert(0, "#ifndef %s" % unique_id)
                        include_code_lines.insert(1, "#define %s" % unique_id)
                        include_code_lines.append("#endif /* %s */" %
                                                  unique_id)
                        code_lines = include_code_lines + code_lines[line_num:]
                        line_num = 0

                if not valid:
                    logger.error(
                        "Shader parsing error.\n\t--> Cannot open %s file." %
                        include_file)
                continue
            # append code block
            final_code_lines.append(code)
        return '\n'.join(final_code_lines)
Exemplo n.º 16
0
    def __init__(self, core_manager):
        GameBackend.__init__(self, core_manager)

        logger.info('GameBackend : pygame %s' % pygame.__version__)

        # centered window
        os.environ['SDL_VIDEO_CENTERED'] = '1'
        pygame.mixer.pre_init(44100, -16, 2, 4096)
        pygame.mixer.init()
        pygame.init()

        self.screen_width = pygame.display.Info().current_w
        self.screen_height = pygame.display.Info().current_h

        self.set_mouse_grab(self.get_mouse_grab())

        pygame.font.init()
        if not pygame.font.get_init():
            logger.error('Could not render font.')
            return

        # ASCII commands
        Keyboard.BACKSPACE = K_BACKSPACE
        Keyboard.TAB = K_TAB
        # Keyboard.LINEFEED = K_LINEFEED
        Keyboard.CLEAR = K_CLEAR
        Keyboard.RETURN = K_RETURN
        Keyboard.ENTER = K_KP_ENTER
        Keyboard.PAUSE = K_PAUSE
        Keyboard.SCROLLLOCK = K_SCROLLOCK
        Keyboard.SYSREQ = K_SYSREQ
        Keyboard.ESCAPE = K_ESCAPE
        Keyboard.SPACE = K_SPACE

        # Cursor control and motion
        Keyboard.HOME = K_HOME
        Keyboard.LEFT = K_LEFT
        Keyboard.UP = K_UP
        Keyboard.RIGHT = K_RIGHT
        Keyboard.DOWN = K_DOWN
        Keyboard.PAGEUP = K_PAGEUP
        Keyboard.PAGEDOWN = K_PAGEDOWN
        Keyboard.END = K_END
        # Keyboard.BEGIN = K_BEGIN

        # Misc functions
        Keyboard.DELETE = K_DELETE
        # Keyboard.SELECT = K_SELECT
        Keyboard.PRINT = K_PRINT
        # Keyboard.EXECUTE = K_EXECUTE
        Keyboard.INSERT = K_INSERT
        # Keyboard.UNDO = K_UNDO
        # Keyboard.REDO = K_REDO
        Keyboard.MENU = K_MENU
        # Keyboard.FIND = K_FIND
        # Keyboard.CANCEL = K_CANCEL
        Keyboard.HELP = K_HELP
        Keyboard.BREAK = K_BREAK
        # Keyboard.MODESWITCH = K_MODESWITCH
        # Keyboard.SCRIPTSWITCH = K_SCRIPTSWITCH
        # Keyboard.FUNCTION = K_FUNCTION

        # Number pad
        Keyboard.NUMLOCK = K_NUMLOCK
        # Keyboard.NUM_SPACE = K_NUM_SPACE
        # Keyboard.NUM_TAB = K_NUM_TAB
        # Keyboard.NUM_ENTER = K_NUM_ENTER
        # Keyboard.NUM_F1 = K_NUM_F1
        # Keyboard.NUM_F2 = K_NUM_F2
        # Keyboard.NUM_F3 = K_NUM_F3
        # Keyboard.NUM_F4 = K_NUM_F4
        # Keyboard.NUM_HOME = K_NUM_HOME
        # Keyboard.NUM_LEFT = K_NUM_LEFT
        # Keyboard.NUM_UP = K_NUM_UP
        # Keyboard.NUM_RIGHT = K_NUM_RIGHT
        # Keyboard.NUM_DOWN = K_NUM_DOWN
        # Keyboard.NUM_PRIOR = K_NUM_PRIOR
        # Keyboard.NUM_PAGE_UP = K_NUM_PAGE_UP
        # Keyboard.NUM_NEXT = K_NUM_NEXT
        # Keyboard.NUM_PAGE_DOWN = K_NUM_PAGE_DOWN
        # Keyboard.NUM_END = K_NUM_END
        # Keyboard.NUM_BEGIN = K_NUM_BEGIN
        # Keyboard.NUM_INSERT = K_NUM_INSERT
        # Keyboard.NUM_DELETE = K_NUM_DELETE
        # Keyboard.NUM_EQUAL = K_NUM_EQUAL
        # Keyboard.NUM_MULTIPLY = K_NUM_MULTIPLY
        # Keyboard.NUM_ADD = K_NUM_ADD
        # Keyboard.NUM_SEPARATOR = K_NUM_SEPARATOR
        # Keyboard.NUM_SUBTRACT = K_NUM_SUBTRACT
        # Keyboard.NUM_DECIMAL = K_NUM_DECIMAL
        # Keyboard.NUM_DIVIDE = K_NUM_DIVIDE

        # Keyboard.NUM_0 = K_NUM_0
        # Keyboard.NUM_1 = K_NUM_1
        # Keyboard.NUM_2 = K_NUM_2
        # Keyboard.NUM_3 = K_NUM_3
        # Keyboard.NUM_4 = K_NUM_4
        # Keyboard.NUM_5 = K_NUM_5
        # Keyboard.NUM_6 = K_NUM_6
        # Keyboard.NUM_7 = K_NUM_7
        # Keyboard.NUM_8 = K_NUM_8
        # Keyboard.NUM_9 = K_NUM_9

        # Function keys
        Keyboard.F1 = K_F1
        Keyboard.F2 = K_F2
        Keyboard.F3 = K_F3
        Keyboard.F4 = K_F4
        Keyboard.F5 = K_F5
        Keyboard.F6 = K_F6
        Keyboard.F7 = K_F7
        Keyboard.F8 = K_F8
        Keyboard.F9 = K_F9
        Keyboard.F10 = K_F10
        Keyboard.F11 = K_F11
        Keyboard.F12 = K_F12
        Keyboard.F13 = K_F13
        Keyboard.F14 = K_F14
        Keyboard.F15 = K_F15
        # Keyboard.F16 = K_F16
        # Keyboard.F17 = K_F17
        # Keyboard.F18 = K_F18
        # Keyboard.F19 = K_F19
        # Keyboard.F20 = K_F20

        # Modifiers
        Keyboard.LSHIFT = K_LSHIFT
        Keyboard.RSHIFT = K_RSHIFT
        Keyboard.LCTRL = K_LCTRL
        Keyboard.RCTRL = K_RCTRL
        Keyboard.CAPSLOCK = K_CAPSLOCK
        Keyboard.LMETA = K_LMETA
        Keyboard.RMETA = K_RMETA
        Keyboard.LALT = K_LALT
        Keyboard.RALT = K_RALT
        # Keyboard.LWINDOWS = K_LWINDOWS
        # Keyboard.RWINDOWS = K_RWINDOWS
        # Keyboard.LCOMMAND = K_LCOMMAND
        # Keyboard.RCOMMAND = K_RCOMMAND
        # Keyboard.LOPTION = K_LOPTION
        # Keyboard.ROPTION = K_ROPTION

        # Latin-1
        Keyboard.SPACE = K_SPACE
        # Keyboard.EXCLAMATION = K_EXCLAMATION
        # Keyboard.DOUBLEQUOTE = K_DOUBLEQUOTE
        Keyboard.HASH = K_HASH
        # Keyboard.POUND = K_POUND
        Keyboard.DOLLAR = K_DOLLAR
        # Keyboard.PERCENT = K_PERCENT
        Keyboard.AMPERSAND = K_AMPERSAND
        # Keyboard.APOSTROPHE = K_APOSTROPHE
        Keyboard.PARENLEFT = K_LEFTPAREN
        Keyboard.PARENRIGHT = K_RIGHTPAREN
        Keyboard.ASTERISK = K_ASTERISK
        Keyboard.PLUS = K_PLUS
        Keyboard.COMMA = K_COMMA
        Keyboard.MINUS = K_MINUS
        Keyboard.PERIOD = K_PERIOD
        Keyboard.SLASH = K_SLASH
        Keyboard.BACKQUOTE = K_BACKQUOTE
        Keyboard._0 = K_0
        Keyboard._1 = K_1
        Keyboard._2 = K_2
        Keyboard._3 = K_3
        Keyboard._4 = K_4
        Keyboard._5 = K_5
        Keyboard._6 = K_6
        Keyboard._7 = K_7
        Keyboard._8 = K_8
        Keyboard._9 = K_9
        Keyboard.COLON = K_COLON
        Keyboard.SEMICOLON = K_SEMICOLON
        Keyboard.LESS = K_LESS
        Keyboard.EQUAL = K_EQUALS
        Keyboard.GREATER = K_GREATER
        Keyboard.QUESTION = K_QUESTION
        Keyboard.AT = K_AT
        Keyboard.BRACKETLEFT = K_LEFTBRACKET
        Keyboard.BACKSLASH = K_BACKSLASH
        Keyboard.BRACKETRIGHT = K_RIGHTBRACKET
        # Keyboard.ASCIICIRCUM = K_ASCIICIRCUM
        Keyboard.UNDERSCORE = K_UNDERSCORE
        # Keyboard.GRAVE = K_GRAVE
        Keyboard.QUOTELEFT = K_QUOTE
        Keyboard.A = K_a
        Keyboard.B = K_b
        Keyboard.C = K_c
        Keyboard.D = K_d
        Keyboard.E = K_e
        Keyboard.F = K_f
        Keyboard.G = K_g
        Keyboard.H = K_h
        Keyboard.I = K_i
        Keyboard.J = K_j
        Keyboard.K = K_k
        Keyboard.L = K_l
        Keyboard.M = K_m
        Keyboard.N = K_n
        Keyboard.O = K_o
        Keyboard.P = K_p
        Keyboard.Q = K_q
        Keyboard.R = K_r
        Keyboard.S = K_s
        Keyboard.T = K_t
        Keyboard.U = K_u
        Keyboard.V = K_v
        Keyboard.W = K_w
        Keyboard.X = K_x
        Keyboard.Y = K_y
        Keyboard.Z = K_z
        # Keyboard.BRACELEFT = K_LEFTBRACE
        # Keyboard.BAR = K_BAR
        # Keyboard.BRACERIGHT = K_BRACERIGHT
        # Keyboard.ASCIITILDE = K_ASCIITILDEC

        for symbol in Keyboard.__dict__:
            self.key_pressed[Keyboard.__dict__[symbol]] = False

        self.valid = True
Exemplo n.º 17
0
def DistanceField(font_size, image_width, image_height, image_mode,
                  image_data):
    # GL setting
    glFrontFace(GL_CCW)
    glEnable(GL_TEXTURE_2D)
    glDisable(GL_DEPTH_TEST)
    glDisable(GL_CULL_FACE)
    glDisable(GL_LIGHTING)
    glDisable(GL_BLEND)
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)

    # Create Shader
    vertex_shader = glCreateShader(GL_VERTEX_SHADER)
    glShaderSource(vertex_shader, SIMPLE_VERTEX_SHADER)
    glCompileShader(vertex_shader)

    if glGetShaderiv(vertex_shader, GL_COMPILE_STATUS) != 1 or True:
        infoLogs = glGetShaderInfoLog(vertex_shader)
        if infoLogs:
            if type(infoLogs) == bytes:
                infoLogs = infoLogs.decode("utf-8")
            print(infoLogs)

    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER)
    glShaderSource(fragment_shader, SIMPLE_PIXEL_SHADER)
    glCompileShader(fragment_shader)

    if glGetShaderiv(fragment_shader, GL_COMPILE_STATUS) != 1 or True:
        infoLogs = glGetShaderInfoLog(fragment_shader)
        if infoLogs:
            if type(infoLogs) == bytes:
                infoLogs = infoLogs.decode("utf-8")
            print(infoLogs)

    # Create Program
    program = glCreateProgram()

    # Link Shaders
    glAttachShader(program, vertex_shader)
    glAttachShader(program, fragment_shader)
    glLinkProgram(program)

    # delete shader
    glDetachShader(program, vertex_shader)
    glDetachShader(program, fragment_shader)
    glDeleteShader(vertex_shader)
    glDeleteShader(fragment_shader)

    # Vertex Array Data
    dtype = np.float32
    positions = np.array([(-1, 1, 0), (-1, -1, 0), (1, -1, 0), (1, 1, 0)],
                         dtype=np.float32)
    texcoords = np.array([(0, 1), (0, 0), (1, 0), (1, 1)], dtype=np.float32)
    indices = np.array([0, 1, 2, 0, 2, 3], dtype=np.uint32)

    # data serialize
    vertex_datas = np.hstack([positions, texcoords]).astype(dtype)

    # crate vertex array
    vertex_array = glGenVertexArrays(1)
    glBindVertexArray(vertex_array)

    vertex_buffer = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer)
    glBufferData(GL_ARRAY_BUFFER, vertex_datas, GL_STATIC_DRAW)

    index_buffer_size = indices.nbytes
    index_buffer = glGenBuffers(1)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer)
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_buffer_size, indices,
                 GL_STATIC_DRAW)

    # Create Texture
    texture_format = GL_RGBA
    if image_mode == 'RGB':
        texture_format = GL_RGB
    texture_buffer = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D, texture_buffer)
    glTexImage2D(GL_TEXTURE_2D, 0, texture_format, image_width, image_height,
                 0, texture_format, GL_UNSIGNED_BYTE, image_data)
    glGenerateMipmap(GL_TEXTURE_2D)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                    GL_LINEAR_MIPMAP_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glBindTexture(GL_TEXTURE_2D, 0)

    # Create RenderTarget
    render_target_buffer = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D, render_target_buffer)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, NULL_POINTER)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    glBindTexture(GL_TEXTURE_2D, 0)

    # Create FrameBuffer
    frame_buffer = glGenFramebuffers(1)

    gl_error = glCheckFramebufferStatus(GL_FRAMEBUFFER)
    if gl_error != GL_FRAMEBUFFER_COMPLETE:
        logger.error("glCheckFramebufferStatus error %d." % gl_error)

    # Bind Frame Buffer
    glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer)
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                           render_target_buffer, 0)
    glReadBuffer(GL_COLOR_ATTACHMENT0)
    glDrawBuffers(1, [
        GL_COLOR_ATTACHMENT0,
    ])
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
                           GL_TEXTURE_2D, 0, 0)

    glViewport(0, 0, image_width, image_height)
    glClearColor(1.0, 1.0, 0.0, 1.0)
    glClear(GL_COLOR_BUFFER_BIT)

    # bind program
    glUseProgram(program)

    font_size_location = glGetUniformLocation(program, "font_size")
    glUniform1f(font_size_location, font_size)

    # bind texture
    texture_location = glGetUniformLocation(program, "texture_font")
    glActiveTexture(GL_TEXTURE0)
    glBindTexture(GL_TEXTURE_2D, texture_buffer)
    glUniform1i(texture_location, 0)

    # Bind Vertex Array
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer)

    vertex_position_size = positions[0].nbytes
    vertex_texcoord_size = texcoords[0].nbytes
    vertex_buffer_size = vertex_position_size + vertex_texcoord_size

    location = 0
    offset = 0
    stride = len(positions[0])
    glEnableVertexAttribArray(location)
    glVertexAttribPointer(location, stride, GL_FLOAT, GL_FALSE,
                          vertex_buffer_size, c_void_p(offset))

    location = 1
    offset += vertex_position_size
    stride = len(texcoords[0])
    glEnableVertexAttribArray(1)
    glVertexAttribPointer(location, stride, GL_FLOAT, GL_FALSE,
                          vertex_buffer_size, c_void_p(offset))

    # bind index buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer)

    # Draw Quad
    glDrawElements(GL_TRIANGLES, index_buffer_size, GL_UNSIGNED_INT,
                   NULL_POINTER)

    # Save
    glBindTexture(GL_TEXTURE_2D, render_target_buffer)
    save_image_data = glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE)
    glBindTexture(GL_TEXTURE_2D, 0)

    return save_image_data