108 lines
3.7 KiB
Python
108 lines
3.7 KiB
Python
|
|
# People's Video Editor: high quality, GPU accelerated mp4 editor
|
||
|
|
# Copyright (C) 2025 Roz K <roz@rozk.net>
|
||
|
|
#
|
||
|
|
# This file is part of People's Video Editor.
|
||
|
|
#
|
||
|
|
# People's Video Editor 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.
|
||
|
|
#
|
||
|
|
# People's Video Editor 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 People's Video Editor.
|
||
|
|
# If not, see <https://www.gnu.org/licenses/>.
|
||
|
|
|
||
|
|
from array import array
|
||
|
|
|
||
|
|
from .node import Node
|
||
|
|
from .vector import Vector2
|
||
|
|
|
||
|
|
class Point:
|
||
|
|
__slots__ = 'position', 'mapping'
|
||
|
|
|
||
|
|
def __init__(self, xy = Vector2(), uv = Vector2()):
|
||
|
|
assert isinstance(xy, Vector2) and isinstance(uv, Vector2)
|
||
|
|
self.position = xy
|
||
|
|
self.mapping = uv
|
||
|
|
|
||
|
|
class Polygon(Node):
|
||
|
|
__slots__ = '_positions', '_mappings', '_len'
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def rectangle(cls, geometry):
|
||
|
|
tl = Vector2(0.0, 0.0)
|
||
|
|
tr = Vector2(geometry._width, 0.0)
|
||
|
|
br = Vector2(geometry._width, geometry._height)
|
||
|
|
bl = Vector2(0.0, geometry._height)
|
||
|
|
return cls(points = (
|
||
|
|
Point(tl, tl),
|
||
|
|
Point(tr, tr),
|
||
|
|
Point(br, br),
|
||
|
|
Point(bl, bl)))
|
||
|
|
|
||
|
|
def __init__(self, parent = None, children = None, size = 0, points = None):
|
||
|
|
Node.__init__(self, parent, children)
|
||
|
|
self.clear_points()
|
||
|
|
self.add_points(size, points)
|
||
|
|
|
||
|
|
def __len__(self):
|
||
|
|
return self._len
|
||
|
|
|
||
|
|
def __getitem__(self, index):
|
||
|
|
begin = index * 2
|
||
|
|
end = begin + 2
|
||
|
|
return Point(
|
||
|
|
Vector2(*self._positions[begin:end]),
|
||
|
|
Vector2(*self._mappings[begin:end]))
|
||
|
|
|
||
|
|
def __setitem__(self, index, point):
|
||
|
|
begin = index * 2
|
||
|
|
end = begin + 2
|
||
|
|
self._positions[begin:end] = array(Vector2.TYPE, point.position)
|
||
|
|
self._mappings[begin:end] = array(Vector2.TYPE, point.mapping)
|
||
|
|
|
||
|
|
def add_child(self, child):
|
||
|
|
assert isinstance(child, Polygon)
|
||
|
|
Node.add_child(self, child)
|
||
|
|
|
||
|
|
def add_points(self, count = 0, points = None):
|
||
|
|
assert (count > 0) ^ len(points)
|
||
|
|
if count:
|
||
|
|
initializer = bytes(count * Vector2.SIZE)
|
||
|
|
self._positions.frombytes(initializer)
|
||
|
|
self._mappings.frombytes(initializer)
|
||
|
|
self._len += count
|
||
|
|
else:
|
||
|
|
for point in points:
|
||
|
|
self._positions.extend(point.position)
|
||
|
|
self._mappings.extend(point.mapping)
|
||
|
|
self._len += len(points)
|
||
|
|
|
||
|
|
def insert_points(self, index, count = 0, points = None):
|
||
|
|
assert (count == 0) ^ (points is None)
|
||
|
|
index *= 2
|
||
|
|
if count:
|
||
|
|
initializer = array(Vector2.TYPE, bytes(count * Vector2.SIZE))
|
||
|
|
self._positions[index:index] = initializer
|
||
|
|
self._mappings[index:index] = initializer
|
||
|
|
self._len += count
|
||
|
|
else:
|
||
|
|
polygon = Polygon(points = points)
|
||
|
|
self._positions[index:index] = polygon._positions
|
||
|
|
self._mappings[index:index] = polygon._mappings
|
||
|
|
self._len += polygon._len
|
||
|
|
|
||
|
|
def remove_points(self, index, count = 1):
|
||
|
|
begin = index * 2
|
||
|
|
end = begin + count * 2
|
||
|
|
del self._positions[begin:end]
|
||
|
|
del self._mappings[begin:end]
|
||
|
|
self._len -= count
|
||
|
|
|
||
|
|
def clear_points(self):
|
||
|
|
self._positions = array(Vector2.TYPE)
|
||
|
|
self._mappings = array(Vector2.TYPE)
|
||
|
|
self._len = 0
|