'''This module contains mesh'''
import numpy as np
import vulk.vulkanconstant as vc
import vulk.vulkanobject as vo
[docs]class VertexAttribute():
def __init__(self, location, attribute_format):
'''
*Parameters:*
- `location`: Attribute location in shader
- `attribute_format`: `Format` constant from `vulkanconstant`
'''
dtype, num_components, size = vc.format_info(attribute_format)
self.location = location
self.format = attribute_format
self.dtype = dtype
self.components = num_components
self.size = size
self.offset = 0
[docs]class VertexAttributes():
def __init__(self, attributes):
'''
*Parameters:*
- `attributes`: `list` of `VertexAttribute`
'''
self.attributes = attributes
offset = 0
for attr in attributes:
attr.offset = offset
offset += attr.size
@property
def size(self):
return sum([a.size for a in self.attributes])
def __iter__(self):
return iter(self.attributes)
[docs]class Mesh():
def __init__(self, context, max_vertices, max_indices, attributes):
'''
*Parameters:*
- `context`: `VulkContext`
- `max_vertices`: Maximum number of vertices for this mesh
- `max_indices`: Maximum number of indice for this mesh
- `attributes`: `VertexAttributes`
'''
self.index_type = vc.IndexType.UINT16
if max_vertices > 65535:
self.index_type = vc.IndexType.UINT32
self.attributes = attributes
self.has_indices = max_indices > 0
# Create numpy type based on vertex attributes
numpy_dtype = []
for attr in attributes:
numpy_dtype.append(
('', vc.DataTypeNumpy[attr.dtype], attr.components))
# Create vertices array and buffer
self.vertices_array = np.zeros(max_vertices, dtype=numpy_dtype)
self.vertices_buffer = vo.HighPerformanceBuffer(
context, self.vertices_array.nbytes,
vc.BufferUsage.VERTEX_BUFFER)
# Create indices array and buffer
if self.has_indices:
self.indices_array = np.zeros(max_indices, dtype=np.uint16)
self.indices_buffer = vo.HighPerformanceBuffer(
context, max_indices * vc.index_type_size(self.index_type),
vc.BufferUsage.INDEX_BUFFER)
# Create othens attributes
self.dirty_indices = True
self.dirty_vertices = True
[docs] def set_indices(self, indices, offset=0):
'''Set indices of mesh
*Parameters:*
- `indices`: `list` of `float`
- `offset`: Offset in mesh indices array
**Note: Mesh must be indexed**
'''
if not self.has_indices:
raise Exception('No index in this mesh')
self.indices_array[offset:] = indices
self.dirty_indices = True
[docs] def set_vertex(self, index, vertex):
'''Set one vertex of the mesh at position `index`
*Parameters:*
- `index`: Vertex index
- `vertex`: Vertex data (tuple format)
*Exemple:*
For a mesh with two attributes (2 components and 4 components):
```
vertex = ([x, y], [r, g, b, a])
mesh.set_vertex(idx, vertex)
```
**Note: Vertex data type depends on `VertexAttributes` of the mesh.
It must be a tuple containing an array for each attributes**
**Note: Once mesh vertices are updated, you need to `upload` the mesh
to take into account the changes.**
'''
self.vertices_array[index] = vertex
self.dirty_vertices = True
[docs] def set_vertices(self, vertices, offset=0):
'''Set vertices of the mesh.
Report to `set_vertex`, it works the same but it waits for an array
of vertex.
*Parameters:*
- `vertices`: `list` of Vertex data (see `set_vertex`)
- `offset`: Offset in the mesh vertices array
'''
self.vertices_array[offset:] = vertices
self.dirty_vertices = True
[docs] def upload_indices(self, context):
'''
Upload indices to graphic card
*Parameters:*
- `context`: `VulkContext`
**Note: Mesh must be indexed**
'''
if not self.has_indices:
raise Exception('No index in this mesh')
if not self.dirty_indices:
return
self.dirty_indices = False
with self.indices_buffer.bind(context) as b:
np.copyto(np.array(b, copy=False),
self.indices_array.view(dtype=np.uint8),
casting='no')
[docs] def upload_vertices(self, context):
'''
Upload vertices to graphic card
*Parameters:*
- `context`: `VulkContext`
'''
if not self.dirty_vertices:
return
self.dirty_vertices = False
with self.vertices_buffer.bind(context) as b:
np.copyto(np.array(b, copy=False),
self.vertices_array.view(dtype=np.uint8),
casting='no')
[docs] def upload(self, context):
'''
Upload vertices and indices to graphic card
*Parameters:*
- `context`: `VulkContext`
'''
self.upload_vertices(context)
if self.has_indices:
self.upload_indices(context)
[docs] def bind(self, cmd):
'''Bind the buffers during command buffer registering
*Parameters:*
- `command`: `CommandBufferRegister`
'''
cmd.bind_vertex_buffers(
0, 1, [self.vertices_buffer.final_buffer], [0])
if self.has_indices:
cmd.bind_index_buffer(
self.indices_buffer.final_buffer, 0, self.index_type)
[docs] def draw(self, cmd, offset=0, count=0):
'''Draw the mesh during command buffer registration
*Parameters:*
- `cmd`: `CommandBufferRegister`
- `offset`: Start drawing at `offset` vertices
- `count`: Draw `count` vertices
**Note: `offset` and `count` target indices if mesh is indexed**
'''
if self.has_indices:
if not count:
count = len(self.indices_array) - offset
cmd.draw_indexed(count, offset)
else:
if not count:
count = len(self.vertices_array) - offset
cmd.draw(count, offset)