hellen-one/bin/render_vrml/moderngl_mesh.py

94 lines
2.9 KiB
Python

'''
ModernGL extension for storing mesh data
[andreika]: Modified to support vertex colors instead of texture coords
'''
import logging
import re
import struct
from pyrr import aabb
log = logging.getLogger('ModernGL.ext.obj')
RE_COMMENT = re.compile(r'#[^\n]*\n', flags=re.M)
RE_VERT = re.compile(r'^v\s+(-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?)\s+(-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?)\s+(-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?)$')
RE_COLOR = re.compile(r'^vc\s+(-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?)\s+(-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?)(?:\s+(-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?))?$')
RE_NORM = re.compile(r'^vn\s+(-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?)\s+(-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?)\s+(-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?)$')
RE_FACE = re.compile(r'^f\s+(\d+)(/(\d+)?(/(\d+))?)?\s+(\d+)(/(\d+)?(/(\d+))?)?\s+(\d+)(/(\d+)?(/(\d+))?)?$')
PACKER = 'lambda vx, vy, vz, cx, cy, cz, nx, ny, nz: struct.pack("%df", %s)'
def default_packer(vx, vy, vz, cx, cy, cz, nx, ny, nz):
return struct.pack('9f', vx, vy, vz, cx, cy, cz, nx, ny, nz)
def int_or_none(x):
return None if x is None else int(x)
def safe_float(x):
return 0.0 if x is None else float(x)
class Mesh:
def __init__(self, vert, color, norm, face):
self.vert = vert
self.color = color
self.norm = norm
self.face = face
# we need AABB to zoom in the model
self.aabb = aabb.create_zeros()
def pack(self, packer=default_packer) -> bytes:
'''
Args:
packer (str or lambda): The vertex attributes to pack.
Returns:
bytes: The packed vertex data.
Examples:
.. code-block:: python
import ModernGL
from ModernGL.ext import obj
model = obj.Obj.open('box.obj')
# default packer
data = model.pack()
# same as the default packer
data = model.pack('vx vy vz tx ty tz nx ny nz')
# pack vertices
data = model.pack('vx vy vz')
# pack vertices and texture coordinates (xy)
data = model.pack('vx vy vz tx ty')
# pack vertices and normals
data = model.pack('vx vy vz nx ny nz')
# pack vertices with padding
data = model.pack('vx vy vz 0.0')
'''
if isinstance(packer, str):
nodes = packer.split()
packer = eval(PACKER % (len(nodes), ', '.join(nodes)))
result = bytearray()
for v, t, n in self.face:
vx, vy, vz = self.vert[v - 1]
cx, cy, cz = self.color[t - 1] if t is not None else (0.0, 0.0, 0.0)
nx, ny, nz = self.norm[n - 1] if n is not None else (0.0, 0.0, 0.0)
result += packer(vx, vy, vz, cx, cy, cz, nx, ny, nz)
return bytes(result)