diff --git a/src/objects/mesh.nim b/src/objects/mesh.nim index 1cc3049..bcd3b7f 100644 --- a/src/objects/mesh.nim +++ b/src/objects/mesh.nim @@ -342,16 +342,18 @@ proc clear_vertices*(self: Mesh) = self.data.num_indices[0] = 0 proc remove_vertex*(self: Mesh, index: int) = + # TODO: This is only valid for points mode if not (index >= 0): - return - # -1 or undefined - let num_indices = self.data.num_indices + return # ignore -1 + assert self.data.num_indices[0] > index, "Invalid index" let stride = self.data.stride # move the last vertex to the one in index - let pos0 = num_indices[0] * stride + let pos0 = self.data.num_indices[0] * stride let pos1 = index * stride var bytes = self.data.varrays[0].to(int8) - bytes.copyWithin(pos1, pos0, pos0 + stride) + for i in 0 ..< stride: + bytes[pos1+i] = bytes[pos0+i] + self.data.num_indices[0] -= 1 proc ensure_capacity*(self: Mesh, extra_elements: int) = if self.data == nil: @@ -371,7 +373,7 @@ proc ensure_capacity*(self: Mesh, extra_elements: int) = while fpos >= cap: cap *= 2 var va = newArrRef[float32](cap) - varray.copy_bytes_to va + copyMem(va.toPointer, varray.toPointer, bytelen) self.load_from_va_ia @[va] self.data.num_indices[0] = current_index @@ -381,8 +383,8 @@ proc ensure_capacity*(self: Mesh, extra_elements: int) = # let ilen = self.offsets[self.offsets.len - 1] # let offset = (self.pack_offset or 0) + buffer_offset # try: -# let va = makeSeq[float32](data, offset, vlen) -# let ia = makeSeq[uint16](data, offset + vlen * 4, ilen) +# let va = newSeq[float32](data, offset, vlen) +# let ia = newSeq[uint16](data, offset + vlen * 4, ilen) # except Exception as e: # let e = Error(&"Mesh {self.name} is corrupt") # raise e @@ -518,7 +520,7 @@ proc generate_tangents*(self: MeshData, uv_layer_name, tangent_layer_name: strin for idx in ia.to int32: maxi = max(maxi, idx) # dump (max_len, maxi) - var tangents = makeSeq[Vec3](max_len div stride_f.int) + var tangents = newSeq[Vec3](max_len div stride_f.int) # for va, ia in zip(self.varrays, self.iarrays): for i in 0 ..< self.varrays.len: let va = self.varrays[i] @@ -627,7 +629,7 @@ proc debug_print_vertices*(self: Mesh, starts: int = 0, ends: int = 10) = of Short: ($cast[ptr array[16, uint16]](varray[offset].addr)[]).split(',')[0 ..< attr.count].join(",") & "]" # of HalfFloat: - # let a = makeSeq[uint16](varray.buffer, offset, attr.count) + # let a = newSeq[uint16](varray.buffer, offset, attr.count) # @[read_f16(a[0]), read_f16(a[1]), read_f16(a[2])] else: "" echo &"{attr.name} {data}" diff --git a/src/util.nim b/src/util.nim index d15fe59..615d54f 100644 --- a/src/util.nim +++ b/src/util.nim @@ -75,96 +75,55 @@ func remove_scale_skew*[T](m: GMat4[T]): GMat4[T] = result[3,1] = m[3,1] result[3,2] = m[3,2] -proc remove*[T](s: var seq[T], element: T) = +proc remove*[T](s: var seq[T], element: T): bool {.raises:[],discardable.} = + ## Removes a value from a seq if it exists. Returns whether an item was + ## removed. Preserves the order of the other elements. If the element is + ## repeated, only one instance is removed. let index = s.find element if index != -1: - s.delete index - # TODO: option to warn or break when not present - # and a version or an argument to not warn + # Since we only remove an existing element, it should never raise, + # but we have to use try/except to satisfy raises:[] + try: s.delete index + except: discard + return true -proc remove_unordered*[T](s: seq[T], element: T) = +proc remove_unordered*[T](s: seq[T], element: T): bool {.raises:[],discardable.} = + ## Removes a value from a seq if it exists. Returns whether an item was + ## removed. It's quicker than `remove` by moving the last element to the slot + ## of the removed one. If the element is repeated, only one instance is + ## removed. let index = s.find element if index != -1: - s.del index + # Since we only remove an existing element, it should never raise, + # but we have to use try/except to satisfy raises:[] + try: s.del index + except: discard + return true -func align4*[T: SomeInteger](n: T): T = n + ((4-(n and 3)) and 3) +func align4*[T: SomeInteger](n: T): T = + # Increments the number to the nearest multiplier of 4 if it's not already + # aligned. + n + ((4-(n and 3)) and 3) func align*[T: SomeInteger](n, align: T): T = + ## Increments the number to the nearest multiplier of the `align` parameter, + ## if it's not already aligned. `align` must be a power of two. let mask = align - 1 assert((align and mask) == 0, "align must be a power of two") return n + ((align-(n and mask)) and mask) -func bytelen*[T](s: seq[T]): int = s.len * sizeof(T) +func bytelen*[T](s: seq[T]): int = + ## Provides the size of the seq in bytes. + s.len * sizeof(T) -func get_or_default*[T](s: seq[T], i: int, default: T = T.default): T = +func getOrDefault*[T](s: seq[T], i: int, default: T = T.default): T = + ## Returns an element of the seq if the index is within bounds, otherwise it + ## returns a default value, optionally given as argument. if i >= s.low and i <= s.high: return s[i] return default -when defined(js): - import jsffi - proc newArrayBufferView(size: uint8): seq[uint8] {.importjs: "(new Uint8Array(#))".} - proc newArrayBufferView(size: uint16): seq[uint16] {.importjs: "(new Uint16Array(#))".} - proc newArrayBufferView(size: uint32): seq[uint32] {.importjs: "(new Uint32Array(#))".} - proc newArrayBufferView(size: int8): seq[int8] {.importjs: "(new Int8Array(#))".} - proc newArrayBufferView(size: int16): seq[int16] {.importjs: "(new Int16Array(#))".} - proc newArrayBufferView(size: int32): seq[int32] {.importjs: "(new Int32Array(#))".} - proc newArrayBufferView(size: float32): seq[float32] {.importjs: "(new Float32Array(#))".} - proc newArrayBufferView(size: float64): seq[float64] {.importjs: "(new Float64Array(#))".} - template makeSeq*[T](size: int): seq[T] = - # incredibly cursed hack, but it works - newArrayBufferView(size.tojs.to(typeof T)) - - proc as_byte_array*[T](arr: seq[T]): seq[int8] {.importjs: "(new Int8Array((#).buffer))".} - proc as_ubyte_array*[T](arr: seq[T]): seq[uint8] {.importjs: "(new Uint8Array((#).buffer))".} - proc set*[T](arr, arr2: seq[T]) {.importjs: "((#).set(#))"} - template copy_bytes_to*[T](arr, arr2: seq[T]) = - arr2.as_byte_array.set arr.as_byte_array - proc copyWithin*[T](arr: seq[T], target, start, ends: int) {.importjs: "#.copyWithin(#,#,#)".} - -else: - template makeSeq*[T](size: int): seq[T] = newSeq[T](size) - template as_byte_array*[T](arr: openArray[T]): ptr UncheckedArray[int8] = - cast[ptr UncheckedArray[int8]](addr arr[0]) - template as_ubyte_array*[T](arr: openArray[T]): ptr UncheckedArray[uint8] = - cast[ptr UncheckedArray[uint8]](addr arr[0]) - template as_byte_array*[T](arr: ArrRef[T]): ArrRef[int8] = - arr.to(int8) - template as_ubyte_array*[T](arr: ArrRef[T]): ArrRef[uint8] = - arr.to(uint8) - - template set*[T](arr, arr2: seq[T]) = - for i,v in arr2: - arr[i] = v - - template copy_bytes_to*[T](arr, arr2: seq[T]|ArrRef[T]) = - let src = arr.as_byte_array - let dst = arr2.as_byte_array - for i in 0 .. min(arr.byte_len, arr2.byte_len): - dst[i] = src[i] - - # TODO: version of arrays with len, that clamps bounds and can use negative indices - proc copyWithin*[T](arr: ptr UncheckedArray[T], target, start, ends: int) = - let len = ends-start - let target_end = target + len - if start < target and target < ends: - # reverse (#TODO: only the overlapping section?) - var i = ends - 1 - var o = target_end - 1 - while i != start: - arr[o] = arr[i] - i -= 1; o -= 1 - else: - var i = start - var o = target - while i != ends: - arr[o] = arr[i] - i += 1; o += 1 - - template copyWithin*[T](arr: ArrRef[T], target, start, ends: int) = - copyWithin(cast[ptr UncheckedArray[T]](arr[0].addr), target, start, ends) - template rotate_cw*[T](v: GVec3[T]): GVec3[T] = gvec3[T](v.y, -v.x, v.z) template rotate_ccw*[T](v: GVec3[T]): GVec3[T] = gvec3[T](-v.y, v.x, v.z) @@ -243,6 +202,13 @@ template high*[T](x: typedesc[GVec2[T]]): GVec2[T] = gvec2[T](T.high,T.high) template high*[T](x: typedesc[GVec3[T]]): GVec3[T] = gvec3[T](T.high,T.high,T.high) template high*[T](x: typedesc[GVec4[T]]): GVec4[T] = gvec4[T](T.high,T.high,T.high,T.high) +proc min*[T](v: GVec2[T]): T {.inline.} = min(v.x, v.y) +proc min*[T](v: GVec3[T]): T {.inline.} = min(min(v.x, v.y), v.z) +proc min*[T](v: GVec4[T]): T {.inline.} = min(min(min(v.x, v.y), v.z), v.w) +proc max*[T](v: GVec2[T]): T {.inline.} = max(v.x, v.y) +proc max*[T](v: GVec3[T]): T {.inline.} = max(max(v.x, v.y), v.z) +proc max*[T](v: GVec4[T]): T {.inline.} = max(max(max(v.x, v.y), v.z), v.w) + # bounding box operations template `&`*[T](a, b: (GVec3[T], GVec3[T])): (GVec3[T], GVec3[T]) =