Skip to content
Snippets Groups Projects
measureit_render.py 5.75 KiB
# SPDX-License-Identifier: GPL-2.0-or-later

# ----------------------------------------------------------
# support routines for render measures in final image
# Author: Antonio Vazquez (antonioya)
#
# ----------------------------------------------------------
# noinspection PyUnresolvedReferences
import bpy
import gpu
# noinspection PyUnresolvedReferences
import blf
from os import path, remove
from sys import exc_info
# noinspection PyUnresolvedReferences
import bpy_extras.image_utils as img_utils
# noinspection PyUnresolvedReferences
import bpy_extras.object_utils as object_utils
# noinspection PyUnresolvedReferences
from bpy_extras import view3d_utils
from math import ceil
from .measureit_geometry import *


# -------------------------------------------------------------
# Render image main entry point
#
# -------------------------------------------------------------
def render_main(self, context, animation=False):
    # Save old info
    settings = bpy.context.scene.render.image_settings
    depth = settings.color_depth
    settings.color_depth = '8'

    # Get object list
    scene = context.scene
    objlist = context.scene.objects
    # --------------------
    # Get resolution
    # --------------------
    render_scale = scene.render.resolution_percentage / 100
    width = int(scene.render.resolution_x * render_scale)
    height = int(scene.render.resolution_y * render_scale)

    # --------------------------------------
    # Loop to draw all lines in Offsecreen
    # --------------------------------------
    offscreen = gpu.types.GPUOffScreen(width, height)
    view_matrix = Matrix([
        [2 / width, 0, 0, -1],
        [0, 2 / height, 0, -1],
        [0, 0, 1, 0],
        [0, 0, 0, 1]])

    with offscreen.bind():
        fb = gpu.state.active_framebuffer_get()
        fb.clear(color=(0.0, 0.0, 0.0, 0.0))
        gpu.matrix.reset()
        gpu.matrix.load_matrix(view_matrix)
        gpu.matrix.load_projection_matrix(Matrix.Identity(4))

        # -----------------------------
        # Loop to draw all objects
        # -----------------------------
        for myobj in objlist:
            if myobj.visible_get() is True:
                if 'MeasureGenerator' in myobj:
                    op = myobj.MeasureGenerator[0]
                    draw_segments(context, myobj, op, None, None)
        # -----------------------------
        # Loop to draw all debug
        # -----------------------------
        if scene.measureit_debug is True:
            selobj = bpy.context.selected_objects
            for myobj in selobj:
                if scene.measureit_debug_objects is True:
                    draw_object(context, myobj, None, None)
                elif scene.measureit_debug_object_loc is True:
                    draw_object(context, myobj, None, None)
                if scene.measureit_debug_vertices is True:
                    draw_vertices(context, myobj, None, None)
                elif scene.measureit_debug_vert_loc is True:
                    draw_vertices(context, myobj, None, None)
                if scene.measureit_debug_edges is True:
                    draw_edges(context, myobj, None, None)
                if scene.measureit_debug_faces is True or scene.measureit_debug_normals is True:
                    draw_faces(context, myobj, None, None)
        # -----------------------------
        # Draw a rectangle frame
        # -----------------------------
        if scene.measureit_rf is True:
            rfcolor = scene.measureit_rf_color
            rfborder = scene.measureit_rf_border
            rfline = scene.measureit_rf_line

            imm_set_line_width(rfline)
            x1 = rfborder
            x2 = width - rfborder
            y1 = int(ceil(rfborder / (width / height)))
            y2 = height - y1
            draw_rectangle((x1, y1), (x2, y2), rfcolor)

        buffer = fb.read_color(0, 0, width, height, 4, 0, 'UBYTE')
        buffer.dimensions = width * height * 4

    offscreen.free()

    # -----------------------------
    # Create image
    # -----------------------------
    image_name = "measureit_output"
    if not image_name in bpy.data.images:
        bpy.data.images.new(image_name, width, height)

    image = bpy.data.images[image_name]
    image.scale(width, height)
    image.pixels = [v / 255 for v in buffer]

    # Saves image
    if image is not None and (scene.measureit_render is True or animation is True):
        ren_path = bpy.context.scene.render.filepath
        filename = "mit_frame"
        if len(ren_path) > 0:
            if ren_path.endswith(path.sep):
                initpath = path.realpath(ren_path) + path.sep
            else:
                (initpath, filename) = path.split(ren_path)

        ftxt = "%04d" % scene.frame_current
        outpath = path.realpath(path.join(initpath, filename + ftxt + ".png"))
        save_image(self, outpath, image)

    # restore default value
    settings.color_depth = depth


# -------------------------------------
# Save image to file
# -------------------------------------
def save_image(self, filepath, myimage):
    # noinspection PyBroadException
    try:

        # Save old info
        settings = bpy.context.scene.render.image_settings
        myformat = settings.file_format
        mode = settings.color_mode
        depth = settings.color_depth

        # Apply new info and save
        settings.file_format = 'PNG'
        settings.color_mode = "RGBA"
        settings.color_depth = '8'
        myimage.save_render(filepath)
        print("MeasureIt: Image " + filepath + " saved")

        # Restore old info
        settings.file_format = myformat
        settings.color_mode = mode
        settings.color_depth = depth
    except:
        print("Unexpected error:" + str(exc_info()))
        self.report({'ERROR'}, "MeasureIt: Unable to save render image")
        return