Initial commit
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
'''
|
||||
Copyright (C) 2020 Akaneyu
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
import sys
|
||||
import math
|
||||
import time
|
||||
import bpy
|
||||
import bgl
|
||||
import blf
|
||||
import gpu
|
||||
from gpu_extras.batch import batch_for_shader
|
||||
from mathutils import Matrix, Vector
|
||||
import numpy as np
|
||||
|
||||
default_vertex_shader = '''
|
||||
uniform mat4 ModelViewProjectionMatrix;
|
||||
|
||||
in vec2 pos;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0, 1.0);
|
||||
}
|
||||
'''
|
||||
|
||||
default_fragment_shader = '''
|
||||
uniform vec4 color;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = color;
|
||||
}
|
||||
'''
|
||||
|
||||
dotted_line_vertex_shader = '''
|
||||
uniform mat4 ModelViewProjectionMatrix;
|
||||
|
||||
in vec2 pos;
|
||||
in float arcLength;
|
||||
|
||||
out float arcLengthOut;
|
||||
|
||||
void main()
|
||||
{
|
||||
arcLengthOut = arcLength;
|
||||
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0, 1.0);
|
||||
}
|
||||
'''
|
||||
|
||||
dotted_line_fragment_shader = '''
|
||||
uniform float scale;
|
||||
uniform float offset;
|
||||
uniform vec4 color1;
|
||||
uniform vec4 color2;
|
||||
|
||||
in float arcLengthOut;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
if (step(sin((arcLengthOut + offset) * scale), 0.5) == 1) {
|
||||
fragColor = color1;
|
||||
} else {
|
||||
fragColor = color2;
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
image_vertex_shader = '''
|
||||
uniform mat4 ModelViewProjectionMatrix;
|
||||
|
||||
in vec2 pos;
|
||||
in vec2 texCoord;
|
||||
|
||||
out vec2 texCoordOut;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0, 1.0);
|
||||
texCoordOut = texCoord;
|
||||
}
|
||||
'''
|
||||
|
||||
image_fragment_shader = '''
|
||||
uniform sampler2D image;
|
||||
|
||||
in vec2 texCoordOut;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = texture(image, texCoordOut);
|
||||
}
|
||||
'''
|
||||
|
||||
def make_scale_matrix(scale):
|
||||
return Matrix([
|
||||
[scale[0], 0, 0, 0],
|
||||
[0, scale[1], 0, 0],
|
||||
[0, 0, 1.0, 0],
|
||||
[0, 0, 0, 1.0]
|
||||
])
|
||||
|
||||
class UIRenderer:
|
||||
def __init__(self):
|
||||
self.default_shader = gpu.types.GPUShader(default_vertex_shader,
|
||||
default_fragment_shader)
|
||||
self.default_shader_u_color = self.default_shader.uniform_from_name("color")
|
||||
|
||||
self.dotted_line_shader = gpu.types.GPUShader(dotted_line_vertex_shader,
|
||||
dotted_line_fragment_shader)
|
||||
self.dotted_line_shader_u_color1 = self.dotted_line_shader.uniform_from_name("color1")
|
||||
self.dotted_line_shader_u_color2 = self.dotted_line_shader.uniform_from_name("color2")
|
||||
|
||||
#self.image_shader = gpu.shader.from_builtin('2D_IMAGE')
|
||||
self.image_shader = gpu.types.GPUShader(image_vertex_shader,
|
||||
image_fragment_shader)
|
||||
|
||||
def render_selection_frame(self, pos, size, rot=0, scale=(1.0, 1.0)):
|
||||
width, height = size[0], size[1]
|
||||
|
||||
bgl.glEnable(bgl.GL_BLEND)
|
||||
bgl.glLineWidth(2.0)
|
||||
|
||||
with gpu.matrix.push_pop():
|
||||
verts = [[0, 0], [0, height], [width, height], [width, 0], [0, 0]]
|
||||
# T <= R <= S <= centering
|
||||
mat = Matrix.Translation([pos[0] + width / 2.0, pos[1] + height / 2.0, 0]) \
|
||||
@ Matrix.Rotation(rot, 4, 'Z') \
|
||||
@ make_scale_matrix(scale) \
|
||||
@ Matrix.Translation([-width / 2.0, -height / 2.0, 0])
|
||||
|
||||
for i, vert in enumerate(verts):
|
||||
verts[i] = (mat @ Vector(vert + [0, 1]))[:2]
|
||||
|
||||
verts = np.array(verts, 'f')
|
||||
|
||||
arc_lengths = [0]
|
||||
for a, b in zip(verts[:-1], verts[1:]):
|
||||
arc_lengths.append(arc_lengths[-1] + np.linalg.norm(a - b))
|
||||
|
||||
batch = batch_for_shader(self.dotted_line_shader, 'LINE_STRIP',
|
||||
{"pos": verts, "arcLength": arc_lengths})
|
||||
|
||||
self.dotted_line_shader.bind()
|
||||
|
||||
self.dotted_line_shader.uniform_float("scale", 0.6)
|
||||
self.dotted_line_shader.uniform_float("offset", 0)
|
||||
self.dotted_line_shader.uniform_vector_float(self.dotted_line_shader_u_color1,
|
||||
np.array([1.0, 1.0, 1.0, 0.5], 'f'), 4)
|
||||
self.dotted_line_shader.uniform_vector_float(self.dotted_line_shader_u_color2,
|
||||
np.array([0.0, 0.0, 0.0, 0.5], 'f'), 4)
|
||||
|
||||
batch.draw(self.dotted_line_shader)
|
||||
|
||||
err = bgl.glGetError()
|
||||
if err != bgl.GL_NO_ERROR:
|
||||
print('render_selection_frame')
|
||||
print('OpenGL error:', err)
|
||||
|
||||
def render_image_sub(self, img, pos, size, rot, scale):
|
||||
width, height = size[0], size[1]
|
||||
|
||||
img.gl_load()
|
||||
|
||||
bgl.glActiveTexture(bgl.GL_TEXTURE0)
|
||||
bgl.glBindTexture(bgl.GL_TEXTURE_2D, img.bindcode)
|
||||
bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_NEAREST)
|
||||
bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_NEAREST)
|
||||
|
||||
with gpu.matrix.push_pop():
|
||||
gpu.matrix.translate([pos[0] + width / 2.0, pos[1] + height / 2.0])
|
||||
gpu.matrix.multiply_matrix(
|
||||
Matrix.Rotation(rot, 4, 'Z'))
|
||||
gpu.matrix.scale(scale)
|
||||
gpu.matrix.translate([-width / 2.0, -height / 2.0])
|
||||
|
||||
batch = batch_for_shader(self.image_shader, 'TRI_FAN',
|
||||
{
|
||||
"pos": [
|
||||
(0, 0),
|
||||
(width, 0),
|
||||
size,
|
||||
(0, height)
|
||||
],
|
||||
"texCoord": [(0, 0), (1, 0), (1, 1), (0, 1)]
|
||||
})
|
||||
|
||||
self.image_shader.bind()
|
||||
|
||||
self.image_shader.uniform_int('image', 0)
|
||||
|
||||
batch.draw(self.image_shader)
|
||||
|
||||
err = bgl.glGetError()
|
||||
if err != bgl.GL_NO_ERROR:
|
||||
print('render_image')
|
||||
print('OpenGL error:', err)
|
||||
|
||||
def render_image(self, img, pos, size, rot=0, scale=(1.0, 1.0)):
|
||||
bgl.glEnable(bgl.GL_BLEND)
|
||||
# FIXME: glBlendFuncSeparate does not seem to be implemented,
|
||||
# but we believe this blend mode was already applied
|
||||
#bgl.glBlendFuncSeparate(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA,
|
||||
# bgl.GL_ONE, bgl.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
self.render_image_sub(img, pos, size, rot, scale)
|
||||
|
||||
def render_image_offscreen(self, img, rot=0, scale=(1.0, 1.0)):
|
||||
width, height = img.size[0], img.size[1]
|
||||
|
||||
box = [[0, 0], [width, 0], [0, height], [width, height]]
|
||||
mat = Matrix.Rotation(rot, 4, 'Z') \
|
||||
@ make_scale_matrix(scale) \
|
||||
@ Matrix.Translation([-width / 2.0, -height / 2.0, 0])
|
||||
min_x, min_y = sys.float_info.max, sys.float_info.max
|
||||
max_x, max_y = -sys.float_info.max, -sys.float_info.max
|
||||
|
||||
# calculate bounding box
|
||||
for pos in box:
|
||||
pos = mat @ Vector(pos + [0, 1])
|
||||
min_x = min(min_x, pos[0])
|
||||
min_y = min(min_y, pos[1])
|
||||
max_x = max(max_x, pos[0])
|
||||
max_y = max(max_y, pos[1])
|
||||
|
||||
ofs_width = math.ceil(max_x - min_x)
|
||||
ofs_height = math.ceil(max_y - min_y)
|
||||
|
||||
ofs = gpu.types.GPUOffScreen(ofs_width, ofs_height)
|
||||
with ofs.bind():
|
||||
bgl.glDisable(bgl.GL_BLEND)
|
||||
|
||||
bgl.glClearColor(0, 0, 0, 0)
|
||||
bgl.glClear(bgl.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
with gpu.matrix.push_pop():
|
||||
gpu.matrix.load_projection_matrix(Matrix.Identity(4))
|
||||
|
||||
gpu.matrix.load_identity()
|
||||
gpu.matrix.scale([1.0 / (ofs_width / 2.0), 1.0 / (ofs_height / 2.0)])
|
||||
gpu.matrix.translate([-width / 2.0, -height / 2.0])
|
||||
|
||||
self.render_image_sub(img, [0, 0], [width, height], rot, scale)
|
||||
|
||||
buff = bgl.Buffer(bgl.GL_BYTE, ofs_width * ofs_height * 4)
|
||||
bgl.glReadBuffer(bgl.GL_BACK)
|
||||
bgl.glReadPixels(0, 0, ofs_width, ofs_height, bgl.GL_RGBA,
|
||||
bgl.GL_UNSIGNED_BYTE, buff)
|
||||
|
||||
ofs.free()
|
||||
|
||||
err = bgl.glGetError()
|
||||
if err != bgl.GL_NO_ERROR:
|
||||
print('render_image_offscreen')
|
||||
print('OpenGL error:', err)
|
||||
|
||||
return buff, ofs_width, ofs_height
|
||||
Reference in New Issue
Block a user