diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 4091d36..5feee6f 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -7,11 +7,20 @@ jobs: name: Build wheel on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-13] + os: [ubuntu-latest, ubuntu-24.04-arm, macos-15, macos-13, windows-latest] # Use specific versions for clarity + arch: [x86_64, arm64] + exclude: + - os: ubuntu-24.04-arm # No need to specify arch, it's already implicit + arch: x86_64 # Exclude x86_64 on ARM + - os: macos-15 # Exclude macOS 14 (Sonoma) + arch: x86_64 # Exclude x86_64 explicitly + - os: macos-13 # Exclude macOS 13 (Ventura) - arm64 + arch: arm64 # Exclude arm64 on macOS 13 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 name: Install Python with: python-version: '3.11' @@ -19,11 +28,13 @@ jobs: run: | python -m pip install cibuildwheel==2.22.0 - name: Build wheel - run: | - python -m cibuildwheel --output-dir dist - - uses: actions/upload-artifact@v3 + run: python -m cibuildwheel --output-dir wheelhouse + env: + CIBW_ARCHS_MACOS: ${{ matrix.arch }} + CIBW_SKIP: "cp*-manylinux_i686 cp*-musllinux* cp*-win32" + - uses: actions/upload-artifact@v4 with: - name: wheels + name: wheels-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.pybuilds }} path: dist/ release: @@ -35,13 +46,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Tag Version id: set_tag run: | export V=$(python -c "print(next(iter(eval(L.split('=')[-1]) for L in open('pyproject.toml') if 'version =' in L)))") echo "tag=${V}" >> "$GITHUB_ENV" - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 - name: Create Release uses: ncipollo/release-action@v1 with: @@ -57,10 +68,10 @@ jobs: id-token: write steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download Wheels - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: - packages-dir: wheels \ No newline at end of file + packages-dir: wheels diff --git a/ci/embree.json b/ci/embree.json index 53d9654..5634d67 100644 --- a/ci/embree.json +++ b/ci/embree.json @@ -1,37 +1,51 @@ [ { "extract_skip": ["bin/*", "doc/*"], - "name": "embree2", + "name": "embree4", "platform": "linux", - "sha256": "2c4bdacd8f3c3480991b99e85b8f584975ac181373a75f3e9675bf7efae501fe", + "arch": "x86_64", + "sha256": "757e6e8b987d13ac34aa7c4c3657120fd54a78c2a1034e30dda5cd5df06f3cdd", "strip_components": 1, - "target": "../embree2", - "url": "https://github.com/embree/embree/releases/download/v2.17.7/embree-2.17.7.x86_64.linux.tar.gz" + "target": "../embree4", + "url": "https://github.com/RenderKit/embree/releases/download/v4.3.3/embree-4.3.3.x86_64.linux.tar.gz" }, { "extract_skip": ["bin/*", "doc/*"], - "name": "embree2", - "platform": "mac", - "sha256": "48a2e81d6ccc8782c37f811afe2290969b288ee7264fdf5273eac349921c05df", + "name": "embree4", + "platform": "linux", + "arch": "x86_64", + "sha256": "757e6e8b987d13ac34aa7c4c3657120fd54a78c2a1034e30dda5cd5df06f3cdd", "strip_components": 1, - "target": "../embree2", - "url": "https://github.com/embree/embree/releases/download/v2.17.7/embree-2.17.7.x86_64.macosx.tar.gz" + "target": "../embree4", + "url": "https://github.com/RenderKit/embree/releases/download/v4.3.3/embree-4.3.3.aarch64.linux.tar.gz" }, { - "name": "embree2", - "platform": "windows", - "sha256": "6fb7c828eef6cfe7186a5c002b52157a0d67471cf2c3072c3dced7d480071907", - "target": "../embree2", + "extract_skip": ["bin/*", "doc/*"], + "name": "embree4", + "platform": "mac", + "arch": "arm64", + "sha256": "ee310bcd8480ed82f2be29289b9a811c83db6a36160c8afdcb61bb4de4d337df", "strip_components": 1, - "url": "https://github.com/embree/embree/releases/download/v2.17.7/embree-2.17.7.x64.windows.zip" + "target": "../embree4", + "url": "https://github.com/RenderKit/embree/releases/download/v4.3.3/embree-4.3.3.arm64.macosx.zip" }, { "extract_skip": ["bin/*", "doc/*"], "name": "embree4", - "platform": "linux", - "sha256": "524842e2f141dca0db584c33a0821176373e7058f3ec2201bfb19d9e9a1b80b9", + "platform": "mac", + "arch": "x86_64", + "sha256": "98997523dfff8efd8120075f7feba00cfc765c992d758d9be12d56bfe6bec233", "strip_components": 1, "target": "../embree4", - "url": "https://github.com/embree/embree/releases/download/v4.0.0/embree-4.0.0.x86_64.linux.tar.gz" + "url": "https://github.com/RenderKit/embree/releases/download/v4.3.3/embree-4.3.3.x86_64.macosx.zip" + }, + { + "name": "embree4", + "platform": "windows", + "arch": "amd64", + "sha256": "d4c07f88df9f009dd84e4e9b9dcec32ad7d96f927bd88de00b721b0923d481a9", + "target": "../embree4", + "strip_components": 1, + "url": "https://github.com/RenderKit/embree/releases/download/v4.3.3/embree-4.3.3.x64.windows.zip" } ] diff --git a/ci/fetch-embree.py b/ci/fetch-embree.py index 8548467..d818a58 100755 --- a/ci/fetch-embree.py +++ b/ci/fetch-embree.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """A Python 3 standard library only utility to download embree releases -and copy them into the home directory for every plaform. +and copy them into the home directory for every plaform and architecture. """ import os @@ -11,7 +11,7 @@ import argparse from io import BytesIO from fnmatch import fnmatch -from platform import system +from platform import system, machine from typing import Optional from zipfile import ZipFile @@ -30,13 +30,12 @@ def fetch(url, sha256): Location of remote resource. sha256: str The SHA256 hash of the resource once retrieved, - wil raise a `ValueError` if the hash doesn't match. + will raise a `ValueError` if the hash doesn't match. Returns ------- data : bytes Retrieved data in memory with correct hash. - """ import hashlib from urllib.request import urlopen @@ -51,7 +50,7 @@ def fetch(url, sha256): def extract(tar, member, path, chmod): - """Extract a single member from a tarfile to a path.""" + """Extract a single member from a tarfile or ZipFile to a path.""" if os.path.isdir(path): return @@ -62,15 +61,16 @@ def extract(tar, member, path, chmod): return data = data.read() else: - # ZipFile -_- + # ZipFile data = tar.read(member.filename) if len(data) == 0: return - # make sure root path exists + os.makedirs(os.path.dirname(path), exist_ok=True) with open(path, "wb") as f: f.write(data) + if chmod is not None: # python os.chmod takes an octal value os.chmod(path, int(str(chmod), base=8)) @@ -81,12 +81,12 @@ def handle_fetch( sha256: str, target: str, chmod: Optional[int] = None, - extract_skip: Optional[bool] = None, - extract_only: Optional[bool] = None, + extract_skip: Optional[list] = None, + extract_only: Optional[str] = None, strip_components: int = 0, ): - """A macro to fetch a remote resource (usually an executable) and - move it somewhere on the file system. + """A macro to fetch a remote resource (archive or single file) + and move it somewhere on the file system. Parameters ---------- @@ -96,17 +96,15 @@ def handle_fetch( A hex string for the hash of the remote resource. target : str Target location on the local file system. - chmod : None or int. - Change permissions for extracted files. - extract_skip : None or iterable - Skip a certain member of the archive. - extract_only : None or str - Extract *only* a single file from the archive, + chmod : None or int + Change permissions for extracted files (octal). + extract_skip : list[str] + Skip a certain set of patterns from the archive. + extract_only : str + Extract only a single file from the archive, overrides `extract_skip`. strip_components : int - Strip off this many components from the file path - in the archive, i.e. at `1`, `a/b/c` is extracted to `target/b/c` - + Number of path components to strip from extracted paths. """ if ".." in target: target = os.path.join(_cwd, target) @@ -119,19 +117,18 @@ def handle_fetch( # get the raw bytes log.debug(f"fetching: `{url}`") raw = fetch(url=url, sha256=sha256) - if len(raw) == 0: raise ValueError(f"{url} is empty!") - # if we have an archive that tar supports - if url.endswith((".tar.gz", ".tar.xz", ".tar.bz2", "zip")): + # handle archive vs single file + if url.endswith((".tar.gz", ".tar.xz", ".tar.bz2", ".zip")): if url.endswith(".zip"): tar = ZipFile(BytesIO(raw)) members = tar.infolist() else: - # mode needs to know what type of compression - mode = f'r:{url.split(".")[-1]}' - # get the archive + # deduce tar mode from extension + ext = url.split(".")[-1] + mode = f"r:{ext}" # e.g. "r:gz", "r:xz", ... tar = tarfile.open(fileobj=BytesIO(raw), mode=mode) members = tar.getmembers() @@ -139,40 +136,36 @@ def handle_fetch( extract_skip = [] for member in members: - if hasattr(member, "filename"): - name = member.filename - else: - name = member.name - - # final name after stripping components - name = "/".join(name.split("/")[strip_components:]) - - # if any of the skip patterns match continue - if any(fnmatch(name, p) for p in extract_skip): - log.debug(f"skipping: `{name}`") + # tarfile uses member.name, ZipFile uses member.filename + name = getattr(member, "filename", getattr(member, "name", "")) + # apply strip_components + split_path = name.split("/") + name_stripped = "/".join(split_path[strip_components:]) + + # skip if pattern matches any in extract_skip + if not extract_only and any(fnmatch(name_stripped, p) for p in extract_skip): + log.debug(f"skipping: `{name_stripped}`") continue - if extract_only is None: - path = os.path.join(target, name) - log.debug(f"extracting: `{path}`") - extract(tar=tar, member=member, path=path, chmod=chmod) - else: - name = name.split("/")[-1] - if name == extract_only: - path = os.path.join(target, name) - log.debug(f"extracting `{path}`") + # if we are extracting only a single file, ignore everything else + if extract_only: + # final base name + base_only = os.path.basename(name_stripped) + if base_only == extract_only: + path = os.path.join(target, base_only) + log.debug(f"extracting only `{path}`") extract(tar=tar, member=member, path=path, chmod=chmod) return + else: + path = os.path.join(target, name_stripped) + log.debug(f"extracting: `{path}`") + extract(tar=tar, member=member, path=path, chmod=chmod) else: # a single file - name = url.split("/")[-1].strip() path = target with open(path, "wb") as f: f.write(raw) - - # apply chmod if requested if chmod is not None: - # python os.chmod takes an octal value os.chmod(path, int(str(chmod), base=8)) @@ -185,41 +178,82 @@ def load_config(path: Optional[str] = None) -> list: return json.load(f) -def is_current_platform(platform: str) -> bool: - """Check to see if a string platform identifier matches the current platform.""" - # 'linux', 'darwin', 'windows' +def is_current_platform(platform_name: str) -> bool: + """ + Check whether the given 'platform_name' from the JSON + matches our current OS: + - 'linux' + - 'darwin' or 'mac' + - 'windows' + """ current = system().lower().strip() if current.startswith("dar"): - return platform.startswith("dar") or platform.startswith("mac") + return platform_name.startswith("dar") or platform_name.startswith("mac") elif current.startswith("win"): - return platform.startswith("win") + return platform_name.startswith("win") elif current.startswith("lin"): - return platform.startswith("lin") + return platform_name.startswith("lin") else: - raise ValueError(f"{current} ?= {platform}") + raise ValueError(f"Unrecognized platform: {current}") + + +def unify_arch_name(raw_arch: str) -> str: + """ + Normalize architecture names to a smaller set: + - x86_64 + - arm64 + - amd64 (only if you truly want to treat it differently from x86_64) + Modify this map if you want to unify 'amd64' and 'x86_64' or treat them separately. + """ + normalized = raw_arch.lower() + # Example: unify synonyms if desired + synonyms = { + "amd64": "amd64", + "x86_64": "x86_64", + "aarch64": "arm64", + "arm64": "arm64", + } + return synonyms.get(normalized, normalized) + + +def is_current_arch(arch: Optional[str]) -> bool: + """ + Returns True if the given 'arch' matches our current machine architecture. + If 'arch' is None or empty, assume it's a match (no arch restriction). + """ + if not arch: + return True + current_arch = unify_arch_name(machine()) + desired_arch = unify_arch_name(arch) + return current_arch == desired_arch if __name__ == "__main__": parser = argparse.ArgumentParser(description="Install system packages for trimesh.") parser.add_argument("--install", type=str, action="append", help="Install package.") - parser.add_argument( - "--config", type=str, help="Specify a different config JSON path" - ) + parser.add_argument("--config", type=str, help="Specify a different config JSON path") args = parser.parse_args() - config = load_config(path=args.config) - # allow comma delimeters and de-duplicate + # --install can appear multiple times; allow comma-delimited as well if args.install is None: parser.print_help() - exit() + sys.exit(0) else: select = set(" ".join(args.install).replace(",", " ").split()) for option in config: - if option["name"] in select and is_current_platform(option["platform"]): + # Only install if name + OS + arch match + # Some JSON entries may not have "arch", so default to True if missing + if ( + option["name"] in select + and is_current_platform(option["platform"]) + and is_current_arch(option.get("arch")) + ): subset = option.copy() - subset.pop("name") - subset.pop("platform") + # Remove keys not used by 'handle_fetch' + subset.pop("name", None) + subset.pop("platform", None) + subset.pop("arch", None) handle_fetch(**subset) diff --git a/embreex/__init__.py b/embreex/__init__.py index 0a8da88..af8e923 100644 --- a/embreex/__init__.py +++ b/embreex/__init__.py @@ -1 +1 @@ -__version__ = "0.1.6" +__version__ = "4.3.3" diff --git a/embreex/mesh_construction.pyx b/embreex/mesh_construction.pyx index 69e9ec6..dd2066e 100644 --- a/embreex/mesh_construction.pyx +++ b/embreex/mesh_construction.pyx @@ -1,12 +1,14 @@ # distutils: language=c++ cimport numpy as np +from cython cimport floating cimport rtcore as rtc -cimport rtcore_ray as rtcr -cimport rtcore_scene as rtcs -cimport rtcore_geometry as rtcg -cimport rtcore_geometry_user as rtcgu -from rtcore cimport Vertex, Triangle +# These are now all unified under rtcore_geometry +# cimport rtcore_ray as rtcr +# cimport rtcore_scene as rtcs +# cimport rtcore_geometry as rtcg +# cimport rtcore_geometry_user as rtcgu +from rtcore cimport Vertex, Triangle, Vec3f # Import directly from rtcore cdef extern from "mesh_construction.h": @@ -15,7 +17,6 @@ cdef extern from "mesh_construction.h": cdef class TriangleMesh: r''' - This class constructs a polygon mesh with triangular elements and adds it to the scene. @@ -49,87 +50,95 @@ cdef class TriangleMesh: ''' - cdef Vertex* vertices - cdef Triangle* indices - cdef unsigned int mesh + cdef Vertex * vertices + cdef Triangle * indices + # cdef unsigned int mesh # Embree 3 + cdef rtc.RTCGeometry mesh # Embree 4 Geometry Handle - def __init__(self, rtcs.EmbreeScene scene, - np.ndarray vertices, - np.ndarray indices = None): + def __init__(self, rtc.EmbreeScene scene, + np.ndarray[floating, ndim=2] vertices, + np.ndarray[np.int32_t, ndim=2] indices = None): if indices is None: self._build_from_flat(scene, vertices) else: self._build_from_indices(scene, vertices, indices) - cdef void _build_from_flat(self, rtcs.EmbreeScene scene, - np.ndarray tri_vertices): + def __dealloc__(self): + if self.mesh is not NULL: # Check if mesh was initialized + rtc.rtcReleaseGeometry(self.mesh) # release in dealloc + + cdef void _build_from_flat(self, rtc.EmbreeScene scene, + np.ndarray[floating, ndim=3] tri_vertices) except +: cdef int i, j cdef int nt = tri_vertices.shape[0] # In this scheme, we don't share any vertices. This leads to cracks, # but also means we have exactly three times as many vertices as # triangles. - cdef unsigned int mesh = rtcg.rtcNewTriangleMesh(scene.scene_i, - rtcg.RTC_GEOMETRY_STATIC, nt, nt*3, 1) - cdef Vertex* vertices = rtcg.rtcMapBuffer(scene.scene_i, mesh, - rtcg.RTC_VERTEX_BUFFER) + # Embree 4: Create a triangle mesh geometry + cdef rtc.RTCGeometry mesh = rtc.rtcNewGeometry(scene.device.device, rtc.RTC_GEOMETRY_TYPE_TRIANGLE) + + # Embree 4: Use rtcSetSharedBuffer instead of Map/Unmap + cdef Vertex * vertices = rtc.rtcSetNewBuffer(mesh, + rtc.RTC_BUFFER_TYPE_VERTEX, 0, rtc.RTC_FORMAT_FLOAT3, + sizeof(Vertex), nt * 3) for i in range(nt): for j in range(3): - vertices[i*3 + j].x = tri_vertices[i,j,0] - vertices[i*3 + j].y = tri_vertices[i,j,1] - vertices[i*3 + j].z = tri_vertices[i,j,2] - rtcg.rtcUnmapBuffer(scene.scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) + vertices[i * 3 + j].x = tri_vertices[i, j, 0] + vertices[i * 3 + j].y = tri_vertices[i, j, 1] + vertices[i * 3 + j].z = tri_vertices[i, j, 2] - cdef Triangle* triangles = rtcg.rtcMapBuffer(scene.scene_i, - mesh, rtcg.RTC_INDEX_BUFFER) + cdef Triangle * triangles = rtc.rtcSetNewBuffer(mesh, + rtc.RTC_BUFFER_TYPE_INDEX, 0, rtc.RTC_FORMAT_UINT3, + sizeof(Triangle), nt) for i in range(nt): - triangles[i].v0 = i*3 + 0 - triangles[i].v1 = i*3 + 1 - triangles[i].v2 = i*3 + 2 + triangles[i].v0 = i * 3 + 0 + triangles[i].v1 = i * 3 + 1 + triangles[i].v2 = i * 3 + 2 - rtcg.rtcUnmapBuffer(scene.scene_i, mesh, rtcg.RTC_INDEX_BUFFER) self.vertices = vertices self.indices = triangles self.mesh = mesh + rtc.rtcCommitGeometry(self.mesh) + rtc.rtcAttachGeometry(scene.scene_i, self.mesh) - cdef void _build_from_indices(self, rtcs.EmbreeScene scene, - np.ndarray tri_vertices, - np.ndarray tri_indices): + cdef void _build_from_indices(self, rtc.EmbreeScene scene, + np.ndarray[floating, ndim=2] tri_vertices, + np.ndarray[np.int32_t, ndim=2] tri_indices) except +: cdef int i cdef int nv = tri_vertices.shape[0] cdef int nt = tri_indices.shape[0] - cdef unsigned int mesh = rtcg.rtcNewTriangleMesh(scene.scene_i, - rtcg.RTC_GEOMETRY_STATIC, nt, nv, 1) + # Embree 4 geometry creation + cdef rtc.RTCGeometry mesh = rtc.rtcNewGeometry(scene.device.device, rtc.RTC_GEOMETRY_TYPE_TRIANGLE) # set up vertex and triangle arrays. In this case, we just read # them directly from the inputs - cdef Vertex* vertices = rtcg.rtcMapBuffer(scene.scene_i, mesh, - rtcg.RTC_VERTEX_BUFFER) + cdef Vertex * vertices = rtc.rtcSetNewBuffer(mesh, + rtc.RTC_BUFFER_TYPE_VERTEX, 0, rtc.RTC_FORMAT_FLOAT3, + sizeof(Vertex), nv) for i in range(nv): vertices[i].x = tri_vertices[i, 0] vertices[i].y = tri_vertices[i, 1] vertices[i].z = tri_vertices[i, 2] - rtcg.rtcUnmapBuffer(scene.scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) - - cdef Triangle* triangles = rtcg.rtcMapBuffer(scene.scene_i, - mesh, rtcg.RTC_INDEX_BUFFER) + cdef Triangle * triangles = rtc.rtcSetNewBuffer(mesh, + rtc.RTC_BUFFER_TYPE_INDEX, 0, rtc.RTC_FORMAT_UINT3, + sizeof(Triangle), nt) for i in range(nt): triangles[i].v0 = tri_indices[i][0] triangles[i].v1 = tri_indices[i][1] triangles[i].v2 = tri_indices[i][2] - rtcg.rtcUnmapBuffer(scene.scene_i, mesh, rtcg.RTC_INDEX_BUFFER) - self.vertices = vertices self.indices = triangles self.mesh = mesh - + rtc.rtcCommitGeometry(self.mesh) # Commit geometry + rtc.rtcAttachGeometry(scene.scene_i, self.mesh) #Attach geometry cdef class ElementMesh(TriangleMesh): r''' @@ -162,9 +171,9 @@ cdef class ElementMesh(TriangleMesh): ''' - def __init__(self, rtcs.EmbreeScene scene, - np.ndarray vertices, - np.ndarray indices): + def __init__(self, rtc.EmbreeScene scene, + np.ndarray[floating, ndim=2] vertices, + np.ndarray[np.int32_t, ndim=2] indices): # We need now to figure out if we've been handed quads or tetrahedra. # If it's quads, we can build the mesh slightly differently. # http://stackoverflow.com/questions/23723993/converting-quadriladerals-in-an-obj-file-into-triangles @@ -175,9 +184,9 @@ cdef class ElementMesh(TriangleMesh): else: raise NotImplementedError - cdef void _build_from_hexahedra(self, rtcs.EmbreeScene scene, - np.ndarray quad_vertices, - np.ndarray quad_indices): + cdef void _build_from_hexahedra(self, rtc.EmbreeScene scene, + np.ndarray[floating, ndim=2] quad_vertices, + np.ndarray[np.int32_t, ndim=2] quad_indices) except +: cdef int i, j cdef int nv = quad_vertices.shape[0] @@ -185,70 +194,72 @@ cdef class ElementMesh(TriangleMesh): # There are six faces for every quad. Each of those will be divided # into two triangles. - cdef int nt = 6*2*ne + cdef int nt = 6 * 2 * ne - cdef unsigned int mesh = rtcg.rtcNewTriangleMesh(scene.scene_i, - rtcg.RTC_GEOMETRY_STATIC, nt, nv, 1) + # Embree 4 geometry creation + cdef rtc.RTCGeometry mesh = rtc.rtcNewGeometry(scene.device.device, rtc.RTC_GEOMETRY_TYPE_TRIANGLE) # first just copy over the vertices - cdef Vertex* vertices = rtcg.rtcMapBuffer(scene.scene_i, mesh, - rtcg.RTC_VERTEX_BUFFER) + cdef Vertex * vertices = rtc.rtcSetNewBuffer(mesh, rtc.RTC_BUFFER_TYPE_VERTEX, 0, + rtc.RTC_FORMAT_FLOAT3, sizeof(Vertex), nv) for i in range(nv): vertices[i].x = quad_vertices[i, 0] vertices[i].y = quad_vertices[i, 1] vertices[i].z = quad_vertices[i, 2] - rtcg.rtcUnmapBuffer(scene.scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) # now build up the triangles - cdef Triangle* triangles = rtcg.rtcMapBuffer(scene.scene_i, - mesh, rtcg.RTC_INDEX_BUFFER) + cdef Triangle * triangles = rtc.rtcSetNewBuffer( + mesh, rtc.RTC_BUFFER_TYPE_INDEX, 0, rtc.RTC_FORMAT_UINT3, sizeof(Triangle), nt + ) for i in range(ne): for j in range(12): - triangles[12*i+j].v0 = quad_indices[i][triangulate_hex[j][0]] - triangles[12*i+j].v1 = quad_indices[i][triangulate_hex[j][1]] - triangles[12*i+j].v2 = quad_indices[i][triangulate_hex[j][2]] + triangles[12 * i + j].v0 = quad_indices[i][triangulate_hex[j][0]] + triangles[12 * i + j].v1 = quad_indices[i][triangulate_hex[j][1]] + triangles[12 * i + j].v2 = quad_indices[i][triangulate_hex[j][2]] - rtcg.rtcUnmapBuffer(scene.scene_i, mesh, rtcg.RTC_INDEX_BUFFER) self.vertices = vertices self.indices = triangles self.mesh = mesh + rtc.rtcCommitGeometry(self.mesh) + rtc.rtcAttachGeometry(scene.scene_i, self.mesh) - cdef void _build_from_tetrahedra(self, rtcs.EmbreeScene scene, - np.ndarray tetra_vertices, - np.ndarray tetra_indices): + cdef void _build_from_tetrahedra(self, rtc.EmbreeScene scene, + np.ndarray[floating, ndim=2] tetra_vertices, + np.ndarray[np.int32_t, ndim=2] tetra_indices) except +: cdef int i, j cdef int nv = tetra_vertices.shape[0] cdef int ne = tetra_indices.shape[0] # There are four triangle faces for each tetrahedron. - cdef int nt = 4*ne + cdef int nt = 4 * ne - cdef unsigned int mesh = rtcg.rtcNewTriangleMesh(scene.scene_i, - rtcg.RTC_GEOMETRY_STATIC, nt, nv, 1) + cdef rtc.RTCGeometry mesh = rtc.rtcNewGeometry(scene.device.device, rtc.RTC_GEOMETRY_TYPE_TRIANGLE) # Just copy over the vertices - cdef Vertex* vertices = rtcg.rtcMapBuffer(scene.scene_i, mesh, - rtcg.RTC_VERTEX_BUFFER) + cdef Vertex * vertices = rtc.rtcSetNewBuffer( + mesh, rtc.RTC_BUFFER_TYPE_VERTEX, 0, rtc.RTC_FORMAT_FLOAT3, sizeof(Vertex), nv + ) for i in range(nv): vertices[i].x = tetra_vertices[i, 0] vertices[i].y = tetra_vertices[i, 1] vertices[i].z = tetra_vertices[i, 2] - rtcg.rtcUnmapBuffer(scene.scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) # Now build up the triangles - cdef Triangle* triangles = rtcg.rtcMapBuffer(scene.scene_i, - mesh, rtcg.RTC_INDEX_BUFFER) + cdef Triangle * triangles = rtc.rtcSetNewBuffer( + mesh, rtc.RTC_BUFFER_TYPE_INDEX, 0, rtc.RTC_FORMAT_UINT3, sizeof(Triangle), nt + ) for i in range(ne): for j in range(4): - triangles[4*i+j].v0 = tetra_indices[i][triangulate_tetra[j][0]] - triangles[4*i+j].v1 = tetra_indices[i][triangulate_tetra[j][1]] - triangles[4*i+j].v2 = tetra_indices[i][triangulate_tetra[j][2]] + triangles[4 * i + j].v0 = tetra_indices[i][triangulate_tetra[j][0]] + triangles[4 * i + j].v1 = tetra_indices[i][triangulate_tetra[j][1]] + triangles[4 * i + j].v2 = tetra_indices[i][triangulate_tetra[j][2]] - rtcg.rtcUnmapBuffer(scene.scene_i, mesh, rtcg.RTC_INDEX_BUFFER) self.vertices = vertices self.indices = triangles self.mesh = mesh + rtc.rtcCommitGeometry(self.mesh) + rtc.rtcAttachGeometry(scene.scene_i, self.mesh) \ No newline at end of file diff --git a/embreex/rtcore.pxd b/embreex/rtcore.pxd index 989e47b..f9d0257 100644 --- a/embreex/rtcore.pxd +++ b/embreex/rtcore.pxd @@ -1,59 +1,913 @@ # rtcore.pxd wrapper cimport cython +from cython cimport bint, ssize_t cimport numpy as np -cdef extern from "embree2/rtcore.h": - cdef int RTCORE_VERSION_MAJOR - cdef int RTCORE_VERSION_MINOR - cdef int RTCORE_VERSION_PATCH +cdef extern from "embree4/rtcore.h": + # Embree 4 API changes from v3 + # - rtcInit and rtcExit are removed. + # - rtcDevice retained/released + # - RTCErrorFunc2, userPtr + # - RTCMemoryMonitorFunc - void rtcInit(const char* cfg) - void rtcExit() + # void rtcInit(const char* cfg) # REMOVED in Embree 4 + # void rtcExit() # REMOVED in Embree 4 cdef enum RTCError: - RTC_NO_ERROR - RTC_UNKNOWN_ERROR - RTC_INVALID_ARGUMENT - RTC_INVALID_OPERATION - RTC_OUT_OF_MEMORY - RTC_UNSUPPORTED_CPU - RTC_CANCELLED + RTC_ERROR_NONE + RTC_ERROR_UNKNOWN + RTC_ERROR_INVALID_ARGUMENT + RTC_ERROR_INVALID_OPERATION + RTC_ERROR_OUT_OF_MEMORY + RTC_ERROR_UNSUPPORTED_CPU + RTC_ERROR_CANCELLED + # Embree 4.3.3 - New error type + RTC_ERROR_LEVEL_ZERO_RAYTRACING_SUPPORT_MISSING - # typedef struct __RTCDevice {}* RTCDevice; - ctypedef void* RTCDevice + # typedef struct __RTCDevice {}* RTCDevice; # No longer an opaque pointer. + ctypedef void * RTCDevice - RTCDevice rtcNewDevice(const char* cfg) - void rtcDeleteDevice(RTCDevice device) + RTCDevice rtcNewDevice(const char * cfg) + # Embree 4 added retain/release + void rtcRetainDevice(RTCDevice device) + void rtcReleaseDevice(RTCDevice device) RTCError rtcGetError() - ctypedef void (*RTCErrorFunc)(const RTCError code, const char* _str) - void rtcSetErrorFunction(RTCErrorFunc func) + # Embree 4 uses a single error function with a user pointer. + ctypedef void (*RTCErrorFunc2)(void * userPtr, const RTCError code, const char * str) + void rtcSetDeviceErrorFunction2(RTCDevice device, RTCErrorFunc2 func, void * userPtr) + #void rtcSetErrorFunction(RTCErrorFunc func) # REMOVED - # Embree 2.14.0-0 - void rtcDeviceSetErrorFunction(RTCDevice device, RTCErrorFunc func) + ctypedef bint (*RTCMemoryMonitorFunc)(void * userPtr, ssize_t bytes, bint post) # Added userPtr + bint rtcSetDeviceMemoryMonitorFunction(RTCDevice device, RTCMemoryMonitorFunc func, + void * userPtr) # Added device arg + # void rtcSetMemoryMonitorFunction(RTCMemoryMonitorFunc func) # REMOVED - # Embree 2.15.1 - ctypedef void (*RTCErrorFunc2)(void* userPtr, const RTCError code, const char* str) - void rtcDeviceSetErrorFunction2(RTCDevice device, RTCErrorFunc2 func, void* userPtr) + # Embree 4.3.3 New functions + const char * rtcGetDeviceLastErrorMessage(RTCDevice device) + const char * rtcGetErrorString(RTCError code) - ctypedef bint RTCMemoryMonitorFunc(const ssize_t _bytes, const bint post) - void rtcSetMemoryMonitorFunction(RTCMemoryMonitorFunc func) +cdef extern from "embree4/rtcore_ray.h": + # RTCORE_ALIGN(16) # Macro no longer needed (assume alignment) -cdef extern from "embree2/rtcore_ray.h": - pass + # This is for a *single* ray + cdef struct RTCRay: + # Ray data + float org_x # Embree4 uses explicit members + float org_y + float org_z + #float align0 # No longer needed -cdef struct Vertex: - float x, y, z, r + float dir_x # Explicit members + float dir_y + float dir_z + #float align1 -cdef struct Triangle: - int v0, v1, v2 + float tnear + float tfar -cdef struct Vec3f: - float x, y, z + float time + unsigned int mask # Changed to unsigned int -cdef void print_error(RTCError code) + # Hit data + float Ng_x # Explicit members, and grouped with u,v + float Ng_y + float Ng_z + #float align2 + + float u # Now directly in RTCRay + float v + + int geomID # Now int, not unsigned int + int primID + int instID[1] # Just the first instance ID. instID[RTC_MAX_INSTANCE_LEVEL_COUNT] if needed. + + # This is for a packet of 4 rays + cdef struct RTCRay4: + # Ray data + float orgx[4] + float orgy[4] + float orgz[4] + #float align0 # No longer needed + + float dirx[4] + float diry[4] + float dirz[4] + + float tnear[4] + float tfar[4] + + float time[4] + int mask[4] # still int in RTCRay4/8/16 + + # Hit data + float Ngx[4] + float Ngy[4] + float Ngz[4] + + float u[4] + float v[4] + + int geomID[4] + int primID[4] + int instID[4] + + # This is for a packet of 8 rays + cdef struct RTCRay8: + # Ray data + float orgx[8] + float orgy[8] + float orgz[8] + #float align0 # No longer needed + + float dirx[8] + float diry[8] + float dirz[8] + + float tnear[8] + float tfar[8] + + float time[8] + int mask[8] + + # Hit data + float Ngx[8] + float Ngy[8] + float Ngz[8] + + float u[8] + float v[8] + + int geomID[8] + int primID[8] + int instID[8] + + # This is for a packet of 16 rays + cdef struct RTCRay16: + # Ray data + float orgx[16] + float orgy[16] + float orgz[16] + #float align0 # No longer needed + + float dirx[16] + float diry[16] + float dirz[16] + + float tnear[16] + float tfar[16] + + float time[16] + int mask[16] + + # Hit data + float Ngx[16] + float Ngy[16] + float Ngz[16] + + float u[16] + float v[16] + + int geomID[16] + int primID[16] + int instID[16] + + # Combined Ray/Hit Structures (Embree 4) + cdef struct RTCRayHit: + RTCRay ray + RTCHit hit # Contains u,v,Ng,geomID,primID,instID + + cdef struct RTCHit: # New in Embree 4 - contains hit information + float Ng_x + float Ng_y + float Ng_z + float u + float v + int geomID + int primID + int instID[1] # Just the top level instance ID + + +cdef extern from *: # Hack for struct forward decls + ctypedef struct RTCIntersectArguments + ctypedef struct RTCOccludedArguments + + +# Combined intersect/occluded arguments (Embree 4 API) +cdef extern from "embree4/rtcore_ray.h": + # New enum for ray query flags + cdef enum RTCRayQueryFlags: + RTC_RAY_QUERY_FLAG_NONE + RTC_RAY_QUERY_FLAG_INCOHERENT + RTC_RAY_QUERY_FLAG_COHERENT + RTC_RAY_QUERY_FLAG_INVOKE_ARGUMENT_FILTER + + cdef enum RTCFeatureFlags: # New in Embree4 + RTC_FEATURE_FLAG_NONE + RTC_FEATURE_FLAG_MOTION_BLUR + RTC_FEATURE_FLAG_TRIANGLE + RTC_FEATURE_FLAG_QUAD + RTC_FEATURE_FLAG_GRID + RTC_FEATURE_FLAG_SUBDIVISION + RTC_FEATURE_FLAG_POINT + RTC_FEATURE_FLAG_CURVES + RTC_FEATURE_FLAG_CONE_LINEAR_CURVE + RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE + RTC_FEATURE_FLAG_FLAT_LINEAR_CURVE + RTC_FEATURE_FLAG_ROUND_BEZIER_CURVE + RTC_FEATURE_FLAG_FLAT_BEZIER_CURVE + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BEZIER_CURVE + RTC_FEATURE_FLAG_ROUND_BSPLINE_CURVE + RTC_FEATURE_FLAG_FLAT_BSPLINE_CURVE + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BSPLINE_CURVE + RTC_FEATURE_FLAG_ROUND_HERMITE_CURVE + RTC_FEATURE_FLAG_FLAT_HERMITE_CURVE + RTC_FEATURE_FLAG_NORMAL_ORIENTED_HERMITE_CURVE + RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE + RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE + RTC_FEATURE_FLAG_NORMAL_ORIENTED_CATMULL_ROM_CURVE + RTC_FEATURE_FLAG_SPHERE_POINT + RTC_FEATURE_FLAG_DISC_POINT + RTC_FEATURE_FLAG_ORIENTED_DISC_POINT + RTC_FEATURE_FLAG_ROUND_CURVES + RTC_FEATURE_FLAG_FLAT_CURVES + RTC_FEATURE_FLAG_NORMAL_ORIENTED_CURVES + RTC_FEATURE_FLAG_LINEAR_CURVES + RTC_FEATURE_FLAG_BEZIER_CURVES + RTC_FEATURE_FLAG_BSPLINE_CURVES + RTC_FEATURE_FLAG_HERMITE_CURVES + RTC_FEATURE_FLAG_INSTANCE + RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS + RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_GEOMETRY + RTC_FEATURE_FLAG_FILTER_FUNCTION + RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_ARGUMENTS + RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_GEOMETRY + RTC_FEATURE_FLAG_USER_GEOMETRY + RTC_FEATURE_FLAG_32_BIT_RAY_MASK + RTC_FEATURE_FLAG_ALL + + ctypedef void (*RTCFilterFunctionN)(const struct RTCFilterFunctionNArguments + * args + ) + + ctypedef struct RTCFilterFunctionNArguments: + int * valid + void * geometryUserPtr + const struct RTCRayQueryContext + * context + struct RTCRayN + * ray + struct RTCHitN + * hit + unsigned int N + + ctypedef void (*RTCIntersectFunctionN)(const struct RTCIntersectFunctionNArguments + * args + ) + + ctypedef struct RTCIntersectFunctionNArguments: + int * valid + void * geometryUserPtr + unsigned int primID + struct RTCRayQueryContext + * context + struct RTCRayHitN + * rayhit + unsigned int N + unsigned int geomID + + ctypedef void (*RTCOccludedFunctionN)(const struct RTCOccludedFunctionNArguments + * args + ) + + ctypedef struct RTCOccludedFunctionNArguments: + int * valid + void * geometryUserPtr + unsigned int primID + struct RTCRayQueryContext + * context + struct RTCRayN + * ray + unsigned int N + unsigned int geomID + + ctypedef struct RTCIntersectArguments: + RTCRayQueryFlags flags + RTCFeatureFlags feature_mask + struct RTCRayQueryContext + * context # Renamed in Embree 4 + RTCFilterFunctionN filter + RTCIntersectFunctionN intersect # New in Embree 4 + + ctypedef struct RTCOccludedArguments: + RTCRayQueryFlags flags + RTCFeatureFlags feature_mask + struct RTCRayQueryContext + * context # Renamed in Embree 4 + RTCFilterFunctionN filter + RTCOccludedFunctionN occluded # New in Embree 4 + + # New functions to invoke filter functions from geometry callbacks + void rtcInvokeIntersectFilterFromGeometry(const struct RTCIntersectFunctionNArguments + * args, const + struct RTCFilterFunctionNArguments + * filterArgs + ) + void rtcInvokeOccludedFilterFromGeometry(const struct RTCOccludedFunctionNArguments + * args, const + struct RTCFilterFunctionNArguments + * filterArgs + ) + + # Ray query context (renamed from RTCIntersectContext) + ctypedef struct RTCRayQueryContext: + #unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT] # Now in RTCHit + pass # Simplified - other fields not directly needed here. + + void rtcInitIntersectArguments(RTCIntersectArguments * args) + void rtcInitOccludedArguments(RTCOccludedArguments * args) + void rtcInitRayQueryContext(RTCRayQueryContext * context) + + +cdef extern from "embree4/rtcore_geometry.h": + # RTCBufferType definitions + ctypedef enum RTCBufferType: + RTC_BUFFER_TYPE_INDEX + RTC_BUFFER_TYPE_VERTEX + RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE + RTC_BUFFER_TYPE_NORMAL + RTC_BUFFER_TYPE_TANGENT + RTC_BUFFER_TYPE_NORMAL_DERIVATIVE + RTC_BUFFER_TYPE_GRID + RTC_BUFFER_TYPE_FACE + RTC_BUFFER_TYPE_LEVEL + RTC_BUFFER_TYPE_EDGE_CREASE_INDEX + RTC_BUFFER_TYPE_EDGE_CREASE_WEIGHT + RTC_BUFFER_TYPE_VERTEX_CREASE_INDEX + RTC_BUFFER_TYPE_VERTEX_CREASE_WEIGHT + RTC_BUFFER_TYPE_HOLE + RTC_BUFFER_TYPE_TRANSFORM # Embree 4 Instance Array transform buffer + + ctypedef enum RTCFormat: # For buffer data types + RTC_FORMAT_UCHAR + RTC_FORMAT_UCHAR2 + RTC_FORMAT_UCHAR3 + RTC_FORMAT_UCHAR4 + RTC_FORMAT_CHAR + RTC_FORMAT_CHAR2 + RTC_FORMAT_CHAR3 + RTC_FORMAT_CHAR4 + RTC_FORMAT_USHORT + RTC_FORMAT_USHORT2 + RTC_FORMAT_USHORT3 + RTC_FORMAT_USHORT4 + RTC_FORMAT_SHORT + RTC_FORMAT_SHORT2 + RTC_FORMAT_SHORT3 + RTC_FORMAT_SHORT4 + RTC_FORMAT_UINT + RTC_FORMAT_UINT2 + RTC_FORMAT_UINT3 + RTC_FORMAT_UINT4 + RTC_FORMAT_INT + RTC_FORMAT_INT2 + RTC_FORMAT_INT3 + RTC_FORMAT_INT4 + RTC_FORMAT_FLOAT + RTC_FORMAT_FLOAT2 + RTC_FORMAT_FLOAT3 + RTC_FORMAT_FLOAT4 + RTC_FORMAT_FLOAT5 + RTC_FORMAT_FLOAT6 + RTC_FORMAT_FLOAT7 + RTC_FORMAT_FLOAT8 + RTC_FORMAT_FLOAT9 + RTC_FORMAT_FLOAT10 + RTC_FORMAT_FLOAT11 + RTC_FORMAT_FLOAT12 + RTC_FORMAT_FLOAT13 + RTC_FORMAT_FLOAT14 + RTC_FORMAT_FLOAT15 + RTC_FORMAT_FLOAT16 + RTC_FORMAT_FLOAT3X4_ROW_MAJOR + RTC_FORMAT_FLOAT4X4_ROW_MAJOR + RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR + RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR + RTC_FORMAT_GRID # Special type for Grid meshes. + RTC_FORMAT_QUATERNION_DECOMPOSITION # For quaternion motion blur + + ctypedef enum RTCGeometryType: # New in Embree 4 + RTC_GEOMETRY_TYPE_TRIANGLE + RTC_GEOMETRY_TYPE_QUAD + RTC_GEOMETRY_TYPE_GRID + RTC_GEOMETRY_TYPE_SUBDIVISION + RTC_GEOMETRY_TYPE_CURVE # Generic curve type. + RTC_GEOMETRY_TYPE_POINT # Generic point type. + + RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE + RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE + RTC_GEOMETRY_TYPE_FLAT_BSPLINE_CURVE + RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE + RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE + + RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE + RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE + RTC_GEOMETRY_TYPE_ROUND_BSPLINE_CURVE + RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE + RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE + + RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BEZIER_CURVE + RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BSPLINE_CURVE + RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_HERMITE_CURVE + RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_CATMULL_ROM_CURVE + + RTC_GEOMETRY_TYPE_CONE_LINEAR_CURVE # New in Embree 3.11.0 + + RTC_GEOMETRY_TYPE_SPHERE_POINT + RTC_GEOMETRY_TYPE_DISC_POINT + RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT + + RTC_GEOMETRY_TYPE_USER + RTC_GEOMETRY_TYPE_INSTANCE + RTC_GEOMETRY_TYPE_INSTANCE_ARRAY # Embree 4 Instance Array + + ctypedef enum RTCCurveBasis: + RTC_CURVE_BASIS_LINEAR + RTC_CURVE_BASIS_BEZIER + RTC_CURVE_BASIS_BSPLINE + RTC_CURVE_BASIS_HERMITE + RTC_CURVE_BASIS_CATMULL_ROM + + ctypedef enum RTCRayQueryLevel: # New in Embree 4 + RTC_RAY_QUERY_LEVEL_INSTANCE + RTC_RAY_QUERY_LEVEL_TOP_LEVEL + + # Type for geometry/scene handles is now consistent. + #typedef struct RTCScene {}* RTCScene; + ctypedef void * RTCGeometry; + + # No more flags or numTimeSteps - use rtcNewGeometry + #unsigned rtcNewTriangleMesh(RTCScene scene, RTCGeometryFlags flags, + # size_t numTriangles, size_t numVertices, + # size_t numTimeSteps) + RTCGeometry rtcNewGeometry(RTCDevice device, RTCGeometryType type) + + # Simplified buffer management: rtcSetNewBuffer, rtcSetSharedBuffer, rtcGetBufferData + void * rtcSetNewBuffer(RTCGeometry geometry, RTCBufferType type, unsigned int slot, RTCFormat format, + size_t byteStride, size_t itemCount) + void rtcSetSharedBuffer(RTCGeometry geometry, RTCBufferType type, unsigned int slot, RTCFormat format, + const void * ptr, size_t byteOffset, size_t byteStride, size_t itemCount) + void * rtcGetGeometryBufferData(RTCGeometry geometry, RTCBufferType type, unsigned int slot) + + # Simplified updating: + void rtcUpdateGeometryBuffer(RTCGeometry geometry, RTCBufferType type, unsigned int slot) + + # Simplified enable/disable + void rtcEnableGeometry(RTCGeometry geometry) + void rtcDisableGeometry(RTCGeometry geometry) + + # Simplified Commit + void rtcCommitGeometry(RTCGeometry geometry) + + # Key API differences: + # - rtcMapBuffer/rtcUnmapBuffer are REMOVED + # - Use rtcSetNewBuffer, rtcSetSharedBuffer, rtcGetBufferData + # - Use rtcNewGeometry for ALL geometry types. + # - Use a single RTCGeometry handle, not unsigned int. + + # New functions for setting parameters: + + # Subdivision mode: + ctypedef enum RTCSubdivisionMode: + RTC_SUBDIVISION_MODE_NO_BOUNDARY + RTC_SUBDIVISION_MODE_SMOOTH_BOUNDARY + RTC_SUBDIVISION_MODE_PIN_CORNERS + RTC_SUBDIVISION_MODE_PIN_BOUNDARY + RTC_SUBDIVISION_MODE_PIN_ALL + void rtcSetGeometrySubdivisionMode(RTCGeometry geometry, unsigned int topologyID, enum RTCSubdivisionMode + mode + ) + + void rtcSetGeometryVertexAttributeTopology(RTCGeometry geometry, unsigned int vertexAttributeID, + unsigned int topologyID) + void rtcSetGeometryDisplacementFunction(RTCGeometry geometry, + RTCDisplacementFunctionN func) # Just accept RTCDisplacementFunctionN + + void rtcSetGeometryTimeStepCount(RTCGeometry geometry, unsigned int timeStepCount) # Embree 4 uses this + void rtcSetGeometryTimeRange(RTCGeometry geometry, float startTime, float endTime) # Added in Embree 3.3.0 + + void rtcSetGeometryMask(RTCGeometry geometry, int mask) + void rtcSetGeometryBuildQuality(RTCGeometry geometry, enum RTCBuildQuality + quality + ) + + # New in Embree 3.2.0 + void rtcSetGeometryMaxRadiusScale(RTCGeometry geometry, float maxRadiusScale) + + # Subdivision related functions + float rtcGetGeometryTessellationRate(RTCGeometry geometry, unsigned int edge) + void rtcSetGeometryTessellationRate(RTCGeometry geometry, float tessellationRate) + + void rtcSetGeometryTopologyCount(RTCGeometry geometry, unsigned int topologyCount) + + # New functions to work with curves (flags buffer) + ctypedef enum RTCCurveFlags: unsigned + char + RTC_CURVE_FLAG_NEIGHBOR_LEFT = 1 << 0 + RTC_CURVE_FLAG_NEIGHBOR_RIGHT = 1 << 1 + +# New in Embree 4 - User data passed through scene, not geometry +void * rtcGetGeometryUserDataFromScene(RTCScene +scene, unsigned +int +geomID) + +# New Instance API +void +rtcSetGeometryInstancedScene(RTCGeometry +geometry, RTCScene +scene) +void +rtcSetGeometryInstancedScenes(RTCGeometry +geometry, RTCScene * scenes, size_t +numScenes) # Embree 4 Instance Arrays + +# Matrix layout for transforms +ctypedef enum +RTCMatrixLayout: +RTC_MATRIX_ROW_MAJOR +RTC_MATRIX_COLUMN_MAJOR +RTC_MATRIX_COLUMN_MAJOR_ALIGNED16 + +void +rtcSetGeometryTransform(RTCGeometry +geometry, unsigned +int +timeStep, RTCFormat +format, const +float * xfm) + +# New Instance API (Quaternion motion blur) +ctypedef struct +RTCQuaternionDecomposition +float +scale_x +float +scale_y +float +scale_z +float +skew_xy +float +skew_xz +float +skew_yz +float +shift_x +float +shift_y +float +shift_z +float +quaternion_r +float +quaternion_i +float +quaternion_j +float +quaternion_k +float +translation_x +float +translation_y +float +translation_z + +void +rtcInitQuaternionDecomposition(struct +RTCQuaternionDecomposition * qd) + +void +rtcSetGeometryTransformQuaternion(RTCGeometry +geometry, unsigned +int +timeStep, const +struct +RTCQuaternionDecomposition * qd) + +# Simplified getting user data +void * rtcGetGeometryUserData(RTCGeometry +geometry) + +# New functions for getting geometry information: +unsigned +int +rtcGetGeometryFirstHalfEdge(RTCGeometry +geometry, unsigned +int +faceID) +unsigned +int +rtcGetGeometryFace(RTCGeometry +geometry, unsigned +int +edgeID) +unsigned +int +rtcGetGeometryNextHalfEdge(RTCGeometry +geometry, unsigned +int +edgeID) +unsigned +int +rtcGetGeometryPreviousHalfEdge(RTCGeometry +geometry, unsigned +int +edgeID) +unsigned +int +rtcGetGeometryOppositeHalfEdge(RTCGeometry +geometry, unsigned +int +topologyID, unsigned +int +edgeID) + +# For instancing +void +rtcGetGeometryTransform(RTCGeometry +geometry, float +time, RTCFormat +format, void * xfm) +void +rtcGetGeometryTransformEx(RTCGeometry +geometry, unsigned +int +instPrimID, float +time, RTCFormat +format, void * xfm) # Embree 4 extended version +void * rtcGetGeometryTransformFromScene(RTCScene +scene, unsigned +int +geomID, float +time, RTCFormat +format, void * xfm) # Embree4 +void +rtcSetGeometryUserPrimitiveCount(RTCGeometry +geometry, size_t +numPrimitives) + +# Interpolation functions +void +rtcInterpolate(const +struct +RTCInterpolateArguments * args) +void +rtcInterpolateN(const +struct +RTCInterpolateNArguments * args) + +#New filter functions +void +rtcSetGeometryIntersectFilterFunction(RTCGeometry +geometry, RTCFilterFunctionN +filter) +void +rtcSetGeometryOccludedFilterFunction(RTCGeometry +geometry, RTCFilterFunctionN +filter) + +# Embree 4 filter functions +void +rtcSetGeometryEnableFilterFunctionFromArguments(RTCGeometry +geometry, bint +enable) + +# New API function in Embree 4 +ctypedef struct +RTCBounds: +float +lower_x, lower_y, lower_z, align0 +float +upper_x, upper_y, upper_z, align1 + +ctypedef void (*RTCBoundsFunction)(const struct RTCBoundsFunctionArguments +*args ) + +ctypedef struct +RTCBoundsFunctionArguments: +void * geometryUserPtr +unsigned +int +primID +unsigned +int +timeStep +RTCBounds * bounds_o # Output bounds + +void +rtcSetGeometryBoundsFunction(RTCGeometry +geometry, RTCBoundsFunction +bounds, void * userPtr) + +# For compatibility, keep old function names. +#ctypedef RTCBoundsFunc RTCBoundsFunc2 + +# New functions in Embree 4. +RTCGeometry +rtcGetGeometry(RTCScene +scene, unsigned +int +geomID) # Now returns RTCGeometry +RTCGeometry +rtcGetGeometryThreadSafe(RTCScene +scene, unsigned +int +geomID) # Now returns RTCGeometry + +# For instance array support +void +rtcSetGeometryInstancedScenes(RTCGeometry +geometry, RTCScene * scenes, size_t +numScenes) + +cdef extern +from + +"embree4/rtcore_geometry_user.h": + +ctypedef struct RTCPointQueryFunctionArguments: + #const struct RTCPointQuery* query # The original query + #void* userPtr # User data + #unsigned int primID + #unsigned int geomID + #struct RTCPointQueryContext* context # required to access the current instance + #float similarityScale + pass # Cython has problems if this is a substruct. Access from Python. + +ctypedef bint (*RTCPointQueryFunc)(struct RTCPointQueryFunctionArguments +*args) + +# point query related functions +void +rtcSetGeometryPointQueryFunction(RTCGeometry +geometry, RTCPointQueryFunc +queryFunc) + +cdef extern from "embree4/rtcore_scene.h": + # ctypedef void* RTCDevice # Already defined + ctypedef void * RTCScene + + RTCScene rtcNewScene(RTCDevice device) # device instead of flags, aflags + + # device functions + RTCScene rtcDeviceNewScene(RTCDevice device, RTCSceneFlags flags, RTCAlgorithmFlags aflags) # Old API + + # No longer need progress monitor function + #void rtcSetProgressMonitorFunction(RTCScene scene, RTCProgressMonitorFunc func, void* ptr) + + void rtcCommitScene(RTCScene scene) # Instead of rtcCommit + void rtcJoinCommitScene(RTCScene scene) + + # Ray tracing functions. Accept RTCRayHit + void rtcIntersect1(RTCScene scene, struct RTCRayHit + * rayhit, struct + RTCIntersectArguments * args + ) # Embree4 adds args struct + void rtcOccluded1(RTCScene scene, struct RTCRayHit + * rayhit, struct + RTCOccludedArguments * args + ) # Embree4 adds args struct + + void rtcIntersect4(const void * valid, RTCScene scene, struct RTCRayHit4 + * rayhit, struct + RTCIntersectArguments * args + ) # Embree4 + void rtcOccluded4(const void * valid, RTCScene scene, struct RTCRayHit4 + * rayhit, struct + RTCOccludedArguments * args + ) # Embree4 + + void rtcIntersect8(const void * valid, RTCScene scene, struct RTCRayHit8 + * rayhit, struct + RTCIntersectArguments * args + ) # Embree4 + void rtcOccluded8(const void * valid, RTCScene scene, struct RTCRayHit8 + * rayhit, struct + RTCOccludedArguments * args + ) # Embree4 + + void rtcIntersect16(const void * valid, RTCScene scene, struct RTCRayHit16 + * rayhit, struct + RTCIntersectArguments * args + ) # Embree4 + void rtcOccluded16(const void * valid, RTCScene scene, struct RTCRayHit16 + * rayhit, struct + RTCOccludedArguments * args + ) # Embree4 + + # New function in Embree 4 for forwarding rays + void rtcForwardIntersect1(const struct RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay * ray, unsigned + int instID + ) + void rtcForwardOccluded1(const struct RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay * ray, unsigned + int instID + ) + # New extended functions in Embree 4 for forwarding rays (for instance arrays) + void rtcForwardIntersect1Ex(const struct RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay * ray, unsigned + int instID, unsigned + int instPrimID + ) + void rtcForwardOccluded1Ex(const struct RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay * ray, unsigned + int instID, unsigned + int instPrimID + ) + + void rtcForwardIntersect4(void * valid, const struct RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay4 * ray, unsigned + int instID + ) + void rtcForwardOccluded4(void * valid, const struct RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay4 * ray, unsigned + int instID + ) + void rtcForwardIntersect8(void * valid, const struct RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay8 * ray, unsigned + int instID + ) + void rtcForwardOccluded8(void * valid, const struct RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay8 * ray, unsigned + int instID + ) + void rtcForwardIntersect16(void * valid, const struct RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay16 * ray, unsigned + int instID + ) + void rtcForwardOccluded16(void * valid, const struct RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay16 * ray, unsigned + int instID + ) + + void rtcDeleteScene(RTCScene scene) + # Use retain/release + void rtcRetainScene(RTCScene scene) + void rtcReleaseScene(RTCScene scene) + + # Scene flags: + cdef enum RTCSceneFlags: + RTC_SCENE_FLAG_NONE + RTC_SCENE_FLAG_DYNAMIC + RTC_SCENE_FLAG_COMPACT + RTC_SCENE_FLAG_ROBUST + # New in Embree 4 + RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS # Enable passing filter function as argument. + + RTCSceneFlags rtcGetSceneFlags(RTCScene scene) + void rtcSetSceneFlags(RTCScene scene, RTCSceneFlags flags) + + # New functions in Embree 4 - scene bounds + ctypedef struct RTCLinearBounds: + RTCBounds bounds0 + RTCBounds bounds1 + void rtcGetSceneBounds(RTCScene scene, RTCBounds * bounds_o) + void rtcGetSceneLinearBounds(RTCScene scene, RTCLinearBounds * bounds_o) + + RTCDevice rtcGetSceneDevice(RTCScene scene) + + # New in Embree 4 + ctypedef enum RTCAlgorithmFlags: + RTC_INTERSECT1 # No longer really flags. Just one at a time. + RTC_INTERSECT4 + RTC_INTERSECT8 + RTC_INTERSECT16 cdef class EmbreeDevice: cdef RTCDevice device + +cdef void print_error(rtc.RTCError code) except + # Use Embree 4 error codes. \ No newline at end of file diff --git a/embreex/rtcore.pyx b/embreex/rtcore.pyx index c186e77..76754cc 100644 --- a/embreex/rtcore.pyx +++ b/embreex/rtcore.pyx @@ -1,37 +1,59 @@ # distutils: language=c++ import logging +import warnings +cimport rtcore as rtc # Import the updated rtcore module log = logging.getLogger('embreex') -cdef void print_error(RTCError code): - if code == RTC_NO_ERROR: - log.error("ERROR: No error") - elif code == RTC_UNKNOWN_ERROR: +cdef void print_error(rtc.RTCError code) except +: # Use Embree 4 error codes, and handle exceptions + if code == rtc.RTC_ERROR_NONE: + return # No error, return (don't log "ERROR: No error") + elif code == rtc.RTC_ERROR_UNKNOWN: log.error("ERROR: Unknown error") - elif code == RTC_INVALID_ARGUMENT: + elif code == rtc.RTC_ERROR_INVALID_ARGUMENT: log.error("ERROR: Invalid argument") - elif code == RTC_INVALID_OPERATION: + elif code == rtc.RTC_ERROR_INVALID_OPERATION: log.error("ERROR: Invalid operation") - elif code == RTC_OUT_OF_MEMORY: + elif code == rtc.RTC_ERROR_OUT_OF_MEMORY: log.error("ERROR: Out of memory") - elif code == RTC_UNSUPPORTED_CPU: + elif code == rtc.RTC_ERROR_UNSUPPORTED_CPU: log.error("ERROR: Unsupported CPU") - elif code == RTC_CANCELLED: + elif code == rtc.RTC_ERROR_CANCELLED: log.error("ERROR: Cancelled") + elif code == rtc.RTC_ERROR_LEVEL_ZERO_RAYTRACING_SUPPORT_MISSING: #Embree 4.3.3 + log.error("ERROR: Level Zero Raytracing support missing. Check GPU drivers") else: - raise RuntimeError + raise RuntimeError(f"Unknown Embree error code: {code}") + +cdef void error_printer(void* userPtr, const rtc.RTCError code, const char *_str) noexcept: + """ + error_printer function depends on embree version + Embree 2.14.1 + -> cdef void error_printer(const rtc.RTCError code, const char *_str): + Embree 2.17.1 + -> cdef void error_printer(void* userPtr, const rtc.RTCError code, const char *_str): + """ + log.error("ERROR CAUGHT IN EMBREE") + print_error(code) + if _str: # Check that the string is not null + log.error("ERROR MESSAGE: %s", _str.decode('utf-8', 'replace')) # Decode to a Python string cdef class EmbreeDevice: def __init__(self): - self.device = rtcNewDevice(NULL) + self.device = rtc.rtcNewDevice(NULL) + if self.device == NULL: #Check if device creation was successful + error_code = rtc.rtcGetError() + print_error(error_code) #print error + raise RuntimeError(f"Embree device creation failed. {rtc.rtcGetErrorString(error_code).decode()}") #Raise error as python exception + rtc.rtcSetDeviceErrorFunction2(self.device, error_printer, self) # Pass self as user data def __dealloc__(self): - rtcDeleteDevice(self.device) + if self.device is not NULL: # Avoid double-free + rtc.rtcReleaseDevice(self.device) # Use rtcReleaseDevice def __repr__(self): - return 'Embree version: {0}.{1}.{2}'.format(RTCORE_VERSION_MAJOR, - RTCORE_VERSION_MINOR, - RTCORE_VERSION_PATCH) + # Embree 4 doesn't have version numbers in rtcore.h + return "Embree Device" \ No newline at end of file diff --git a/embreex/rtcore_geometry.pxd b/embreex/rtcore_geometry.pxd index 3c002a1..6a0913e 100644 --- a/embreex/rtcore_geometry.pxd +++ b/embreex/rtcore_geometry.pxd @@ -1,88 +1,295 @@ # rtcore_geometry wrapper -from .rtcore_ray cimport RTCRay, RTCRay4, RTCRay8, RTCRay16 -from .rtcore_scene cimport RTCScene +#from .rtcore_ray cimport RTCRay, RTCRay4, RTCRay8, RTCRay16 #Removed in Embree4 +#from .rtcore_scene cimport RTCScene #Removed in Embree4 +import rtcore as rtc #Embree 4 cimport cython cimport numpy as np -cdef extern from "embree2/rtcore_geometry.h": - cdef unsigned int RTC_INVALID_GEOMETRY_ID +cdef extern from "embree4/rtcore_geometry.h": + #cdef unsigned int RTC_INVALID_GEOMETRY_ID # Now a constant, not an enum. Access via rtcore - cdef enum RTCBufferType: - RTC_INDEX_BUFFER - RTC_VERTEX_BUFFER - RTC_VERTEX_BUFFER0 - RTC_VERTEX_BUFFER1 + ctypedef enum RTCBufferType: + RTC_BUFFER_TYPE_INDEX + RTC_BUFFER_TYPE_VERTEX + RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE + RTC_BUFFER_TYPE_NORMAL + RTC_BUFFER_TYPE_TANGENT + RTC_BUFFER_TYPE_NORMAL_DERIVATIVE + RTC_BUFFER_TYPE_GRID + RTC_BUFFER_TYPE_FACE + RTC_BUFFER_TYPE_LEVEL + RTC_BUFFER_TYPE_EDGE_CREASE_INDEX + RTC_BUFFER_TYPE_EDGE_CREASE_WEIGHT + RTC_BUFFER_TYPE_VERTEX_CREASE_INDEX + RTC_BUFFER_TYPE_VERTEX_CREASE_WEIGHT + RTC_BUFFER_TYPE_HOLE + RTC_BUFFER_TYPE_TRANSFORM # Embree 4 Instance Array transform buffer - RTC_FACE_BUFFER - RTC_LEVEL_BUFFER + ctypedef enum RTCFormat: # For buffer data types + RTC_FORMAT_UCHAR + RTC_FORMAT_UCHAR2 + RTC_FORMAT_UCHAR3 + RTC_FORMAT_UCHAR4 + RTC_FORMAT_CHAR + RTC_FORMAT_CHAR2 + RTC_FORMAT_CHAR3 + RTC_FORMAT_CHAR4 + RTC_FORMAT_USHORT + RTC_FORMAT_USHORT2 + RTC_FORMAT_USHORT3 + RTC_FORMAT_USHORT4 + RTC_FORMAT_SHORT + RTC_FORMAT_SHORT2 + RTC_FORMAT_SHORT3 + RTC_FORMAT_SHORT4 + RTC_FORMAT_UINT + RTC_FORMAT_UINT2 + RTC_FORMAT_UINT3 + RTC_FORMAT_UINT4 + RTC_FORMAT_INT + RTC_FORMAT_INT2 + RTC_FORMAT_INT3 + RTC_FORMAT_INT4 + RTC_FORMAT_FLOAT + RTC_FORMAT_FLOAT2 + RTC_FORMAT_FLOAT3 + RTC_FORMAT_FLOAT4 + RTC_FORMAT_FLOAT5 + RTC_FORMAT_FLOAT6 + RTC_FORMAT_FLOAT7 + RTC_FORMAT_FLOAT8 + RTC_FORMAT_FLOAT9 + RTC_FORMAT_FLOAT10 + RTC_FORMAT_FLOAT11 + RTC_FORMAT_FLOAT12 + RTC_FORMAT_FLOAT13 + RTC_FORMAT_FLOAT14 + RTC_FORMAT_FLOAT15 + RTC_FORMAT_FLOAT16 + RTC_FORMAT_FLOAT3X4_ROW_MAJOR + RTC_FORMAT_FLOAT4X4_ROW_MAJOR + RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR + RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR + RTC_FORMAT_GRID # Special type for Grid meshes. + RTC_FORMAT_QUATERNION_DECOMPOSITION # For quaternion motion blur - RTC_EDGE_CREASE_INDEX_BUFFER - RTC_EDGE_CREASE_WEIGHT_BUFFER + ctypedef enum RTCGeometryType: # New in Embree 4 + RTC_GEOMETRY_TYPE_TRIANGLE + RTC_GEOMETRY_TYPE_QUAD + RTC_GEOMETRY_TYPE_GRID + RTC_GEOMETRY_TYPE_SUBDIVISION + RTC_GEOMETRY_TYPE_CURVE # Generic curve type. + RTC_GEOMETRY_TYPE_POINT # Generic point type. - RTC_VERTEX_CREASE_INDEX_BUFFER - RTC_VERTEX_CREASE_WEIGHT_BUFFER + RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE + RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE + RTC_GEOMETRY_TYPE_FLAT_BSPLINE_CURVE + RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE + RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE - RTC_HOLE_BUFFER + RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE + RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE + RTC_GEOMETRY_TYPE_ROUND_BSPLINE_CURVE + RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE + RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE - cdef enum RTCMatrixType: + RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BEZIER_CURVE + RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BSPLINE_CURVE + RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_HERMITE_CURVE + RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_CATMULL_ROM_CURVE + + RTC_GEOMETRY_TYPE_CONE_LINEAR_CURVE # New in Embree 3.11.0 + + RTC_GEOMETRY_TYPE_SPHERE_POINT + RTC_GEOMETRY_TYPE_DISC_POINT + RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT + + RTC_GEOMETRY_TYPE_USER + RTC_GEOMETRY_TYPE_INSTANCE + RTC_GEOMETRY_TYPE_INSTANCE_ARRAY # Embree 4 Instance Array + + ctypedef enum RTCCurveBasis: + RTC_CURVE_BASIS_LINEAR + RTC_CURVE_BASIS_BEZIER + RTC_CURVE_BASIS_BSPLINE + RTC_CURVE_BASIS_HERMITE + RTC_CURVE_BASIS_CATMULL_ROM + + ctypedef enum RTCRayQueryLevel: # New in Embree 4 + RTC_RAY_QUERY_LEVEL_INSTANCE + RTC_RAY_QUERY_LEVEL_TOP_LEVEL + + # Type for geometry/scene handles is now consistent. + #typedef struct RTCScene {}* RTCScene; + ctypedef void* RTCGeometry; + + + # No more flags or numTimeSteps - use rtcNewGeometry + #unsigned rtcNewTriangleMesh(RTCScene scene, RTCGeometryFlags flags, + # size_t numTriangles, size_t numVertices, + # size_t numTimeSteps) + RTCGeometry rtcNewGeometry(rtc.RTCDevice device, RTCGeometryType type) + + + # Simplified buffer management: rtcSetNewBuffer, rtcSetSharedBuffer, rtcGetBufferData + void* rtcSetNewBuffer(RTCGeometry geometry, RTCBufferType type, unsigned int slot, RTCFormat format, size_t byteStride, size_t itemCount) + void rtcSetSharedBuffer(RTCGeometry geometry, RTCBufferType type, unsigned int slot, RTCFormat format, const void* ptr, size_t byteOffset, size_t byteStride, size_t itemCount) + void* rtcGetGeometryBufferData(RTCGeometry geometry, RTCBufferType type, unsigned int slot) + + # Simplified updating: + void rtcUpdateGeometryBuffer(RTCGeometry geometry, RTCBufferType type, unsigned int slot) + + # Simplified enable/disable + void rtcEnableGeometry(RTCGeometry geometry) + void rtcDisableGeometry(RTCGeometry geometry) + + # Simplified Commit + void rtcCommitGeometry(RTCGeometry geometry) + + # Key API differences: + # - rtcMapBuffer/rtcUnmapBuffer are REMOVED + # - Use rtcSetNewBuffer, rtcSetSharedBuffer, rtcGetBufferData + # - Use rtcNewGeometry for ALL geometry types. + # - Use a single RTCGeometry handle, not unsigned int. + + + # New functions for setting parameters: + + # Subdivision mode: + ctypedef enum RTCSubdivisionMode: + RTC_SUBDIVISION_MODE_NO_BOUNDARY + RTC_SUBDIVISION_MODE_SMOOTH_BOUNDARY + RTC_SUBDIVISION_MODE_PIN_CORNERS + RTC_SUBDIVISION_MODE_PIN_BOUNDARY + RTC_SUBDIVISION_MODE_PIN_ALL + void rtcSetGeometrySubdivisionMode(RTCGeometry geometry, unsigned int topologyID, enum RTCSubdivisionMode mode) + + void rtcSetGeometryVertexAttributeTopology(RTCGeometry geometry, unsigned int vertexAttributeID, unsigned int topologyID) + void rtcSetGeometryDisplacementFunction (RTCGeometry geometry, rtc.RTCDisplacementFunctionN func) # Just accept RTCDisplacementFunctionN + + void rtcSetGeometryTimeStepCount(RTCGeometry geometry, unsigned int timeStepCount) # Embree 4 uses this + void rtcSetGeometryTimeRange(RTCGeometry geometry, float startTime, float endTime) # Added in Embree 3.3.0 + + void rtcSetGeometryMask(RTCGeometry geometry, int mask) + void rtcSetGeometryBuildQuality(RTCGeometry geometry, enum RTCBuildQuality quality) + + # New in Embree 3.2.0 + void rtcSetGeometryMaxRadiusScale(RTCGeometry geometry, float maxRadiusScale) + + # Subdivision related functions + float rtcGetGeometryTessellationRate(RTCGeometry geometry, unsigned int edge) + void rtcSetGeometryTessellationRate(RTCGeometry geometry, float tessellationRate) + + void rtcSetGeometryTopologyCount(RTCGeometry geometry, unsigned int topologyCount) + + # New functions to work with curves (flags buffer) + ctypedef enum RTCCurveFlags : unsigned char + RTC_CURVE_FLAG_NEIGHBOR_LEFT = 1 << 0 + RTC_CURVE_FLAG_NEIGHBOR_RIGHT = 1 << 1 + + # New in Embree 4 - User data passed through scene, not geometry + void* rtcGetGeometryUserDataFromScene (rtc.RTCScene scene, unsigned int geomID) + + # New Instance API + void rtcSetGeometryInstancedScene(RTCGeometry geometry, rtc.RTCScene scene) + void rtcSetGeometryInstancedScenes(RTCGeometry geometry, rtc.RTCScene* scenes, size_t numScenes) # Embree 4 Instance Arrays + + # Matrix layout for transforms + ctypedef enum RTCMatrixLayout: RTC_MATRIX_ROW_MAJOR RTC_MATRIX_COLUMN_MAJOR RTC_MATRIX_COLUMN_MAJOR_ALIGNED16 - cdef enum RTCGeometryFlags: - RTC_GEOMETRY_STATIC - RTC_GEOMETRY_DEFORMABLE - RTC_GEOMETRY_DYNAMIC + void rtcSetGeometryTransform(RTCGeometry geometry, unsigned int timeStep, RTCFormat format, const float* xfm) + + # New Instance API (Quaternion motion blur) + ctypedef struct RTCQuaternionDecomposition: + float scale_x + float scale_y + float scale_z + float skew_xy + float skew_xz + float skew_yz + float shift_x + float shift_y + float shift_z + float quaternion_r + float quaternion_i + float quaternion_j + float quaternion_k + float translation_x + float translation_y + float translation_z + + void rtcInitQuaternionDecomposition(struct RTCQuaternionDecomposition* qd) + + void rtcSetGeometryTransformQuaternion(RTCGeometry geometry, unsigned int timeStep, const struct RTCQuaternionDecomposition* qd) + + # Simplified getting user data + void* rtcGetGeometryUserData (RTCGeometry geometry) + + # New functions for getting geometry information: + unsigned int rtcGetGeometryFirstHalfEdge(RTCGeometry geometry, unsigned int faceID) + unsigned int rtcGetGeometryFace(RTCGeometry geometry, unsigned int edgeID) + unsigned int rtcGetGeometryNextHalfEdge(RTCGeometry geometry, unsigned int edgeID) + unsigned int rtcGetGeometryPreviousHalfEdge(RTCGeometry geometry, unsigned int edgeID) + unsigned int rtcGetGeometryOppositeHalfEdge(RTCGeometry geometry, unsigned int topologyID, unsigned int edgeID) + + # For instancing + void rtcGetGeometryTransform(RTCGeometry geometry, float time, RTCFormat format, void* xfm) + void rtcGetGeometryTransformEx(RTCGeometry geometry, unsigned int instPrimID, float time, RTCFormat format, void* xfm) # Embree 4 extended version + void* rtcGetGeometryTransformFromScene (rtc.RTCScene scene, unsigned int geomID, float time, RTCFormat format, void* xfm) # Embree4 + void rtcSetGeometryUserPrimitiveCount (RTCGeometry geometry, size_t numPrimitives) - cdef struct RTCBounds: + # Interpolation functions + void rtcInterpolate(const struct rtc.RTCInterpolateArguments* args) + void rtcInterpolateN(const struct rtc.RTCInterpolateNArguments* args) + + #New filter functions + void rtcSetGeometryIntersectFilterFunction (RTCGeometry geometry, rtc.RTCFilterFunctionN filter) + void rtcSetGeometryOccludedFilterFunction (RTCGeometry geometry, rtc.RTCFilterFunctionN filter) + + # Embree 4 filter functions + void rtcSetGeometryEnableFilterFunctionFromArguments (RTCGeometry geometry, bint enable) + + # New API function in Embree 4 + ctypedef struct RTCBounds: float lower_x, lower_y, lower_z, align0 float upper_x, upper_y, upper_z, align1 - ctypedef void (*RTCFilterFunc)(void* ptr, RTCRay& ray) - ctypedef void (*RTCFilterFunc4)(void* ptr, RTCRay4& ray) - ctypedef void (*RTCFilterFunc8)(void* ptr, RTCRay8& ray) - ctypedef void (*RTCFilterFunc16)(void* ptr, RTCRay16& ray) - - ctypedef void (*RTCDisplacementFunc)(void* ptr, unsigned geomID, unsigned primID, - const float* u, const float* v, - const float* nx, const float* ny, const float* nz, - float* px, float* py, float* pz, size_t N) - - unsigned rtcNewInstance(RTCScene target, RTCScene source) - void rtcSetTransform(RTCScene scene, unsigned geomID, - RTCMatrixType layout, const float *xfm) - unsigned rtcNewTriangleMesh(RTCScene scene, RTCGeometryFlags flags, - size_t numTriangles, size_t numVertices, - size_t numTimeSteps) - - unsigned rtcNewSubdivisionMesh (RTCScene scene, RTCGeometryFlags flags, - size_t numFaces, size_t numEdges, - size_t numVertices, size_t numEdgeCreases, - size_t numVertexCreases, size_t numHoles, - size_t numTimeSteps) - unsigned rtcNewHairGeometry (RTCScene scene, RTCGeometryFlags flags, - size_t numCurves, size_t numVertices, - size_t numTimeSteps) - void rtcSetMask(RTCScene scene, unsigned geomID, int mask) - void *rtcMapBuffer(RTCScene scene, unsigned geomID, RTCBufferType type) - void rtcUnmapBuffer(RTCScene scene, unsigned geomID, RTCBufferType type) - void rtcSetBuffer(RTCScene scene, unsigned geomID, RTCBufferType type, - void *ptr, size_t offset, size_t stride) - void rtcEnable(RTCScene scene, unsigned geomID) - void rtcUpdate(RTCScene scene, unsigned geomID) - void rtcUpdateBuffer(RTCScene scene, unsigned geomID, RTCBufferType type) - void rtcDisable(RTCScene scene, unsigned geomID) - void rtcSetDisplacementFunction (RTCScene scene, unsigned geomID, RTCDisplacementFunc func, RTCBounds* bounds) - void rtcSetIntersectionFilterFunction (RTCScene scene, unsigned geomID, RTCFilterFunc func) - void rtcSetIntersectionFilterFunction4 (RTCScene scene, unsigned geomID, RTCFilterFunc4 func) - void rtcSetIntersectionFilterFunction8 (RTCScene scene, unsigned geomID, RTCFilterFunc8 func) - void rtcSetIntersectionFilterFunction16 (RTCScene scene, unsigned geomID, RTCFilterFunc16 func) - void rtcSetOcclusionFilterFunction (RTCScene scene, unsigned geomID, RTCFilterFunc func) - void rtcSetOcclusionFilterFunction4 (RTCScene scene, unsigned geomID, RTCFilterFunc4 func) - void rtcSetOcclusionFilterFunction8 (RTCScene scene, unsigned geomID, RTCFilterFunc8 func) - void rtcSetOcclusionFilterFunction16 (RTCScene scene, unsigned geomID, RTCFilterFunc16 func) - void rtcSetUserData (RTCScene scene, unsigned geomID, void* ptr) - void* rtcGetUserData (RTCScene scene, unsigned geomID) - void rtcDeleteGeometry (RTCScene scene, unsigned geomID) + ctypedef void (*RTCBoundsFunction)( const struct rtc.RTCBoundsFunctionArguments* args ) + + ctypedef struct RTCBoundsFunctionArguments: + void* geometryUserPtr + unsigned int primID + unsigned int timeStep + RTCBounds* bounds_o # Output bounds + + void rtcSetGeometryBoundsFunction (RTCGeometry geometry, RTCBoundsFunction bounds, void* userPtr) + + # For compatibility, keep old function names. + #ctypedef RTCBoundsFunc RTCBoundsFunc2 + + # New functions in Embree 4. + RTCGeometry rtcGetGeometry(rtc.RTCScene scene, unsigned int geomID) # Now returns RTCGeometry + RTCGeometry rtcGetGeometryThreadSafe(rtc.RTCScene scene, unsigned int geomID) # Now returns RTCGeometry + + # For instance array support + void rtcSetGeometryInstancedScenes(RTCGeometry geometry, rtc.RTCScene* scenes, size_t numScenes) + +cdef extern from "embree4/rtcore_geometry_user.h": + + ctypedef struct RTCPointQueryFunctionArguments: + #const struct RTCPointQuery* query # The original query + #void* userPtr # User data + #unsigned int primID + #unsigned int geomID + #struct RTCPointQueryContext* context # required to access the current instance + #float similarityScale + pass # Cython has problems if this is a substruct. Access from Python. + + ctypedef bint (*RTCPointQueryFunc)(struct RTCPointQueryFunctionArguments* args) + # point query related functions + void rtcSetGeometryPointQueryFunction(RTCGeometry geometry, RTCPointQueryFunc queryFunc) \ No newline at end of file diff --git a/embreex/rtcore_geometry_user.pxd b/embreex/rtcore_geometry_user.pxd index f1ad5fb..631aac5 100644 --- a/embreex/rtcore_geometry_user.pxd +++ b/embreex/rtcore_geometry_user.pxd @@ -1,35 +1,51 @@ # rtcore_geometry_user wrapper -#from libc.stdint cimport ssize_t, size_t -from .rtcore_ray cimport RTCRay, RTCRay4, RTCRay8, RTCRay16 -from .rtcore_geometry cimport RTCBounds -from .rtcore_scene cimport RTCScene +#from libc.stdint cimport ssize_t, size_t # No longer needed, Cython handles this +#from .rtcore_ray cimport RTCRay, RTCRay4, RTCRay8, RTCRay16 # Removed in Embree 4 +#from .rtcore_geometry cimport RTCBounds # Removed in Embree 4 +from .rtcore cimport EmbreeScene, RTCGeometry, RTCRayHitN, RTCRayQueryContext # Embree 4 +from cython cimport bint cimport cython cimport numpy as np -cdef extern from "embree2/rtcore_geometry_user.h": - ctypedef void (*RTCBoundsFunc)(void* ptr, size_t item, RTCBounds& bounds_o) - ctypedef void (*RTCIntersectFunc)(void* ptr, RTCRay& ray, size_t item) - ctypedef void (*RTCIntersectFunc4)(const void* valid, void* ptr, - RTCRay4& ray, size_t item) - ctypedef void (*RTCIntersectFunc8)(const void* valid, void* ptr, - RTCRay8& ray, size_t item) - ctypedef void (*RTCIntersectFunc16)(const void* valid, void* ptr, - RTCRay16& ray, size_t item) - ctypedef void (*RTCOccludedFunc)(void* ptr, RTCRay& ray, size_t item) - ctypedef void (*RTCOccludedFunc4)(const void* valid, void* ptr, - RTCRay4& ray, size_t item) - ctypedef void (*RTCOccludedFunc8)(const void* valid, void* ptr, - RTCRay8& ray, size_t item) - ctypedef void (*RTCOccludedFunc16)(const void* valid, void* ptr, - RTCRay16& ray, size_t item) - unsigned rtcNewUserGeometry(RTCScene scene, size_t numGeometries) - void rtcSetBoundsFunction(RTCScene scene, unsigned geomID, RTCBoundsFunc bounds) - void rtcSetIntersectFunction(RTCScene scene, unsigned geomID, RTCIntersectFunc intersect) - void rtcSetIntersectFunction4(RTCScene scene, unsigned geomID, RTCIntersectFunc4 intersect4) - void rtcSetIntersectFunction8(RTCScene scene, unsigned geomID, RTCIntersectFunc8 intersect8) - void rtcSetIntersectFunction16(RTCScene scene, unsigned geomID, RTCIntersectFunc16 intersect16) - void rtcSetOccludedFunction(RTCScene scene, unsigned geomID, RTCOccludedFunc occluded) - void rtcSetOccludedFunction4(RTCScene scene, unsigned geomID, RTCOccludedFunc4 occluded4) - void rtcSetOccludedFunction8(RTCScene scene, unsigned geomID, RTCOccludedFunc8 occluded8) - void rtcSetOccludedFunction16(RTCScene scene, unsigned geomID, RTCOccludedFunc16 occluded16) +cdef extern from "embree4/rtcore_geometry_user.h": + # These typedefs have changed significantly. We now have unified callbacks + # that accept a struct containing ALL arguments (ray, hit, context, etc.) + # The valid pointer indicates which rays in a packet are active. + + # Use the new Embree 4 structs and function pointer types from rtcore.pxd + + #ctypedef void (*RTCBoundsFunc)(void* ptr, size_t item, RTCBounds& bounds_o) # Replaced in Embree4 + + # Use new function definition. + ctypedef void (*RTCBoundsFunction)( const struct rtc.RTCBoundsFunctionArguments* args ) + + # Replaced by RTCIntersectFunctionN and RTCOccludedFunctionN in Embree 4 + #ctypedef void (*RTCIntersectFunc)(void* ptr, RTCRay& ray, size_t item) + #ctypedef void (*RTCIntersectFunc4)(const void* valid, void* ptr, RTCRay4& ray, size_t item) + #ctypedef void (*RTCIntersectFunc8)(const void* valid, void* ptr, RTCRay8& ray, size_t item) + #ctypedef void (*RTCIntersectFunc16)(const void* valid, void* ptr, RTCRay16& ray, size_t item) + #ctypedef void (*RTCOccludedFunc)(void* ptr, RTCRay& ray, size_t item) + #ctypedef void (*RTCOccludedFunc4)(const void* valid, void* ptr, RTCRay4& ray, size_t item) + #ctypedef void (*RTCOccludedFunc8)(const void* valid, void* ptr, RTCRay8& ray, size_t item) + #ctypedef void (*RTCOccludedFunc16)(const void* valid, void* ptr, RTCRay16& ray, size_t item) + + #unsigned rtcNewUserGeometry(RTCScene scene, size_t numGeometries) # Removed in Embree4 use rtcNewGeometry + + # Use new function definition. Note: scene -> geometry, unsigned int -> RTCGeometry + void rtcSetBoundsFunction(RTCGeometry geometry, unsigned geomID, rtc.RTCBoundsFunction bounds) #unsigned geomID is not used + + # The following functions are REMOVED. Use rtcSetGeometryIntersectFunction/rtcSetGeometryOccludedFunction + # and pass the appropriate function pointer (RTCIntersectFunctionN or RTCOccludedFunctionN). + #void rtcSetIntersectFunction(RTCScene scene, unsigned geomID, RTCIntersectFunc intersect) + #void rtcSetIntersectFunction4(RTCScene scene, unsigned geomID, RTCIntersectFunc4 intersect4) + #void rtcSetIntersectFunction8(RTCScene scene, unsigned geomID, RTCIntersectFunc8 intersect8) + #void rtcSetIntersectFunction16(RTCScene scene, unsigned geomID, RTCIntersectFunc16 intersect16) + #void rtcSetOccludedFunction(RTCScene scene, unsigned geomID, RTCOccludedFunc occluded) + #void rtcSetOccludedFunction4(RTCScene scene, unsigned geomID, RTCOccludedFunc4 occluded4) + #void rtcSetOccludedFunction8(RTCScene scene, unsigned geomID, RTCOccludedFunc8 occluded8) + #void rtcSetOccludedFunction16(RTCScene scene, unsigned geomID, RTCOccludedFunc16 occluded16) + + # New functions + void rtcSetIntersectFunction(RTCGeometry geometry, rtc.RTCIntersectFunctionN intersect) + void rtcSetOccludedFunction (RTCGeometry geometry, rtc.RTCOccludedFunctionN occluded) \ No newline at end of file diff --git a/embreex/rtcore_ray.pxd b/embreex/rtcore_ray.pxd index 3f248b0..d0e7f5a 100644 --- a/embreex/rtcore_ray.pxd +++ b/embreex/rtcore_ray.pxd @@ -3,33 +3,40 @@ cimport cython cimport numpy as np -cdef extern from "embree2/rtcore_ray.h": - # RTCORE_ALIGN(16) +cdef extern from "embree4/rtcore_ray.h": + # RTCORE_ALIGN(16) # This macro is no longer needed. Assume alignment. + # This is for a *single* ray cdef struct RTCRay: # Ray data - float org[3] - float align0 + float org_x # Embree4 uses explicit members + float org_y + float org_z + #float align0 # No longer needed - float dir[3] - float align1 + float dir_x # Explicit members + float dir_y + float dir_z + #float align1 float tnear float tfar float time - int mask + unsigned int mask # Changed to unsigned int # Hit data - float Ng[3] - float align2 + float Ng_x # Explicit members, and grouped with u,v + float Ng_y + float Ng_z + #float align2 - float u + float u # Now directly in RTCRay float v - int geomID + int geomID # Now int, not unsigned int int primID - int instID + int instID[1] # Just the first instance ID. instID[RTC_MAX_INSTANCE_LEVEL_COUNT] if needed. # This is for a packet of 4 rays cdef struct RTCRay4: @@ -37,7 +44,7 @@ cdef extern from "embree2/rtcore_ray.h": float orgx[4] float orgy[4] float orgz[4] - float align0 + #float align0 # No longer needed float dirx[4] float diry[4] @@ -47,7 +54,7 @@ cdef extern from "embree2/rtcore_ray.h": float tfar[4] float time[4] - int mask[4] + int mask[4] # still int in RTCRay4/8/16 # Hit data float Ngx[4] @@ -67,7 +74,7 @@ cdef extern from "embree2/rtcore_ray.h": float orgx[8] float orgy[8] float orgz[8] - float align0 + #float align0 # No longer needed float dirx[8] float diry[8] @@ -97,7 +104,7 @@ cdef extern from "embree2/rtcore_ray.h": float orgx[16] float orgy[16] float orgz[16] - float align0 + #float align0 # No longer needed float dirx[16] float diry[16] @@ -120,3 +127,158 @@ cdef extern from "embree2/rtcore_ray.h": int geomID[16] int primID[16] int instID[16] + + # Combined Ray/Hit Structures (Embree 4) + cdef struct RTCRayHit: + RTCRay ray + RTCHit hit # Contains u,v,Ng,geomID,primID,instID + + cdef struct RTCHit: # New in Embree 4 - contains hit information + float Ng_x + float Ng_y + float Ng_z + float u + float v + int geomID + int primID + int instID[1] # Just the top level instance ID + + +cdef extern from *: # Hack for struct forward decls + ctypedef struct RTCIntersectArguments + ctypedef struct RTCOccludedArguments + + +# Combined intersect/occluded arguments (Embree 4 API) +cdef extern from "embree4/rtcore_ray.h": + # New enum for ray query flags + cdef enum RTCRayQueryFlags: + RTC_RAY_QUERY_FLAG_NONE + RTC_RAY_QUERY_FLAG_INCOHERENT + RTC_RAY_QUERY_FLAG_COHERENT + RTC_RAY_QUERY_FLAG_INVOKE_ARGUMENT_FILTER + + cdef enum RTCFeatureFlags: # New in Embree4 + RTC_FEATURE_FLAG_NONE + RTC_FEATURE_FLAG_MOTION_BLUR + RTC_FEATURE_FLAG_TRIANGLE + RTC_FEATURE_FLAG_QUAD + RTC_FEATURE_FLAG_GRID + RTC_FEATURE_FLAG_SUBDIVISION + RTC_FEATURE_FLAG_POINT + RTC_FEATURE_FLAG_CURVES + RTC_FEATURE_FLAG_CONE_LINEAR_CURVE + RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE + RTC_FEATURE_FLAG_FLAT_LINEAR_CURVE + RTC_FEATURE_FLAG_ROUND_BEZIER_CURVE + RTC_FEATURE_FLAG_FLAT_BEZIER_CURVE + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BEZIER_CURVE + RTC_FEATURE_FLAG_ROUND_BSPLINE_CURVE + RTC_FEATURE_FLAG_FLAT_BSPLINE_CURVE + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BSPLINE_CURVE + RTC_FEATURE_FLAG_ROUND_HERMITE_CURVE + RTC_FEATURE_FLAG_FLAT_HERMITE_CURVE + RTC_FEATURE_FLAG_NORMAL_ORIENTED_HERMITE_CURVE + RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE + RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE + RTC_FEATURE_FLAG_NORMAL_ORIENTED_CATMULL_ROM_CURVE + RTC_FEATURE_FLAG_SPHERE_POINT + RTC_FEATURE_FLAG_DISC_POINT + RTC_FEATURE_FLAG_ORIENTED_DISC_POINT + RTC_FEATURE_FLAG_ROUND_CURVES + RTC_FEATURE_FLAG_FLAT_CURVES + RTC_FEATURE_FLAG_NORMAL_ORIENTED_CURVES + RTC_FEATURE_FLAG_LINEAR_CURVES + RTC_FEATURE_FLAG_BEZIER_CURVES + RTC_FEATURE_FLAG_BSPLINE_CURVES + RTC_FEATURE_FLAG_HERMITE_CURVES + RTC_FEATURE_FLAG_INSTANCE + RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS + RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_GEOMETRY + RTC_FEATURE_FLAG_FILTER_FUNCTION + RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_ARGUMENTS + RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_GEOMETRY + RTC_FEATURE_FLAG_USER_GEOMETRY + RTC_FEATURE_FLAG_32_BIT_RAY_MASK + RTC_FEATURE_FLAG_ALL + + ctypedef void (*RTCFilterFunctionN)(const struct RTCFilterFunctionNArguments + * args + ) + + ctypedef struct RTCFilterFunctionNArguments: + int * valid + void * geometryUserPtr + const struct RTCRayQueryContext + * context + struct RTCRayN + * ray + struct RTCHitN + * hit + unsigned int N + + ctypedef void (*RTCIntersectFunctionN)(const struct RTCIntersectFunctionNArguments + * args + ) + + ctypedef struct RTCIntersectFunctionNArguments: + int * valid + void * geometryUserPtr + unsigned int primID + struct RTCRayQueryContext + * context + struct RTCRayHitN + * rayhit + unsigned int N + unsigned int geomID + + ctypedef void (*RTCOccludedFunctionN)(const struct RTCOccludedFunctionNArguments + * args + ) + + ctypedef struct RTCOccludedFunctionNArguments: + int * valid + void * geometryUserPtr + unsigned int primID + struct RTCRayQueryContext + * context + struct RTCRayN + * ray + unsigned int N + unsigned int geomID + + ctypedef struct RTCIntersectArguments: + RTCRayQueryFlags flags + RTCFeatureFlags feature_mask + struct RTCRayQueryContext + * context # Renamed in Embree 4 + RTCFilterFunctionN filter + RTCIntersectFunctionN intersect # New in Embree 4 + + ctypedef struct RTCOccludedArguments: + RTCRayQueryFlags flags + RTCFeatureFlags feature_mask + struct RTCRayQueryContext + * context # Renamed in Embree 4 + RTCFilterFunctionN filter + RTCOccludedFunctionN occluded # New in Embree 4 + + # New functions to invoke filter functions from geometry callbacks + void rtcInvokeIntersectFilterFromGeometry(const struct RTCIntersectFunctionNArguments + * args, conststruct + RTCFilterFunctionNArguments * filterArgsa + ) + void rtcInvokeOccludedFilterFromGeometry(const struct RTCOccludedFunctionNArguments + * args, const + struct RTCFilterFunctionNArguments + * filterArgs + ) + + # Ray query context (renamed from RTCIntersectContext) + ctypedef struct RTCRayQueryContext: + #unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT] # Now in RTCHit + pass # Simplified - other fields not directly needed here. + + void rtcInitIntersectArguments(RTCIntersectArguments * args) + void rtcInitOccludedArguments(RTCOccludedArguments * args) + void rtcInitRayQueryContext(RTCRayQueryContext * context) diff --git a/embreex/rtcore_scene.pxd b/embreex/rtcore_scene.pxd index 006357a..f1786a7 100644 --- a/embreex/rtcore_scene.pxd +++ b/embreex/rtcore_scene.pxd @@ -3,65 +3,182 @@ cimport cython cimport numpy as np cimport rtcore as rtc -cimport rtcore_ray as rtcr - -cdef extern from "embree2/rtcore_scene.h": +#cimport rtcore_ray as rtcr # Removed in Embree 4 +cdef extern from "embree4/rtcore_scene.h": + # ctypedef struct RTCRay {} RTCRay # Already defined in rtcore_ray.pxd REMOVED + # ctypedef struct RTCRay4 {} RTCRay4 + # ctypedef struct RTCRay8 {} RTCRay8 + # ctypedef struct RTCRay16 {} RTCRay16 ctypedef struct RTCRay ctypedef struct RTCRay4 ctypedef struct RTCRay8 ctypedef struct RTCRay16 cdef enum RTCSceneFlags: - RTC_SCENE_STATIC - RTC_SCENE_DYNAMIC - RTC_SCENE_COMPACT - RTC_SCENE_COHERENT - RTC_SCENE_INCOHERENT - RTC_SCENE_HIGH_QUALITY - RTC_SCENE_ROBUST - + RTC_SCENE_FLAG_NONE # Embree 4 adds a NONE option. + RTC_SCENE_FLAG_DYNAMIC + RTC_SCENE_FLAG_COMPACT + RTC_SCENE_FLAG_ROBUST + # These are removed in Embree 4 + #RTC_SCENE_COHERENT + #RTC_SCENE_INCOHERENT + #RTC_SCENE_HIGH_QUALITY + # New in Embree 4 + RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS # Enable passing filter function as argument. + + # New in Embree 4 cdef enum RTCAlgorithmFlags: - RTC_INTERSECT1 + RTC_INTERSECT1 # No longer really flags. Just one at a time. RTC_INTERSECT4 RTC_INTERSECT8 RTC_INTERSECT16 - # ctypedef void* RTCDevice - ctypedef void* RTCScene - - RTCScene rtcNewScene(RTCSceneFlags flags, RTCAlgorithmFlags aflags) - - RTCScene rtcDeviceNewScene(rtc.RTCDevice device, RTCSceneFlags flags, RTCAlgorithmFlags aflags) - - ctypedef bint (*RTCProgressMonitorFunc)(void* ptr, const double n) - - void rtcSetProgressMonitorFunction(RTCScene scene, RTCProgressMonitorFunc func, void* ptr) - - void rtcCommit(RTCScene scene) + # ctypedef void* RTCDevice # Already defined in rtcore.pxd + ctypedef void * RTCScene + + #RTCScene rtcNewScene(RTCSceneFlags flags, RTCAlgorithmFlags aflags) # OLD API, takes flags. + RTCScene rtcNewScene(rtc.RTCDevice device) # Embree 4 version - takes device. + + # device functions + RTCScene rtcDeviceNewScene(rtc.RTCDevice device, RTCSceneFlags flags, RTCAlgorithmFlags aflags) # Old API + + #ctypedef bint (*RTCProgressMonitorFunc)(void* ptr, const double n) # No longer needed + + #void rtcSetProgressMonitorFunction(RTCScene scene, RTCProgressMonitorFunc func, void* ptr) # Removed in Embree4 + + #void rtcCommit(RTCScene scene) # REMOVED, replaced by rtcCommitScene + void rtcCommitScene(RTCScene scene) # New in Embree 4 + void rtcJoinCommitScene(RTCScene scene) + + #void rtcCommitThread(RTCScene scene, unsigned int threadID, unsigned int numThreads) # REMOVED + + # Use new Embree 4 ray/hit structs + #void rtcIntersect(RTCScene scene, RTCRay& ray) + void rtcIntersect1(rtc.RTCScene scene, rtc.RTCRayHit * rayhit, rtc.RTCIntersectArguments * args) # Embree4 + #void rtcIntersect4(const void* valid, RTCScene scene, RTCRay4& ray) + void rtcIntersect4(const void * valid, rtc.RTCScene scene, rtc.RTCRayHit4 * rayhit, + rtc.RTCIntersectArguments * args) # Embree4 + #void rtcIntersect8(const void* valid, RTCScene scene, RTCRay8& ray) + void rtcIntersect8(const void * valid, rtc.RTCScene scene, rtc.RTCRayHit8 * rayhit, + rtc.RTCIntersectArguments * args) # Embree4 + #void rtcIntersect16(const void* valid, RTCScene scene, RTCRay16& ray) + void rtcIntersect16(const void * valid, rtc.RTCScene scene, rtc.RTCRayHit16 * rayhit, + rtc.RTCIntersectArguments * args) # Embree4 + + #void rtcOccluded(RTCScene scene, RTCRay& ray) + void rtcOccluded1(rtc.RTCScene scene, rtc.RTCRayHit * rayhit, rtc.RTCOccludedArguments * args) # Embree4 + #void rtcOccluded4(const void* valid, RTCScene scene, RTCRay4& ray) + void rtcOccluded4(const void * valid, rtc.RTCScene scene, rtc.RTCRayHit4 * rayhit, + rtc.RTCOccludedArguments * args) # Embree4 + #void rtcOccluded8(const void* valid, RTCScene scene, RTCRay8& ray) + void rtcOccluded8(const void * valid, rtc.RTCScene scene, rtc.RTCRayHit8 * rayhit, + rtc.RTCOccludedArguments * args) # Embree4 + #void rtcOccluded16(const void* valid, RTCScene scene, RTCRay16& ray) + void rtcOccluded16(const void * valid, rtc.RTCScene scene, rtc.RTCRayHit16 * rayhit, + rtc.RTCOccludedArguments * args) # Embree4 + + # New function in Embree 4 for forwarding rays + void rtcForwardIntersect1(const struct rtc + .RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay * ray, unsigned + int instID + ) + void rtcForwardOccluded1(const struct rtc + .RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay * ray, unsigned + int instID + ) + # New extended functions in Embree 4 for forwarding rays (for instance arrays) + void rtcForwardIntersect1Ex(const struct rtc + .RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay * ray, unsigned + int instID, unsigned + int instPrimID + ) + void rtcForwardOccluded1Ex(const struct rtc + .RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay * ray, unsigned + int instID, unsigned + int instPrimID + ) + + void rtcForwardIntersect4(void * valid, const struct rtc + .RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay4 * ray, unsigned + int instID + ) + void rtcForwardOccluded4(void * valid, const struct rtc + .RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay4 * ray, unsigned + int instID + ) + void rtcForwardIntersect8(void * valid, const struct rtc + .RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay8 * ray, unsigned + int instID + ) + void rtcForwardOccluded8(void * valid, const struct rtc + .RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay8 * ray, unsigned + int instID + ) + void rtcForwardIntersect16(void * valid, const struct rtc + .RTCIntersectFunctionNArguments + * args, RTCScene + scene, struct + RTCRay16 * ray, unsigned + int instID + ) + void rtcForwardOccluded16(void * valid, const struct rtc + .RTCOccludedFunctionNArguments + * args, RTCScene + scene, struct + RTCRay16 * ray, unsigned + int instID + ) - void rtcCommitThread(RTCScene scene, unsigned int threadID, unsigned int numThreads) - - void rtcIntersect(RTCScene scene, RTCRay& ray) - - void rtcIntersect4(const void* valid, RTCScene scene, RTCRay4& ray) - - void rtcIntersect8(const void* valid, RTCScene scene, RTCRay8& ray) - - void rtcIntersect16(const void* valid, RTCScene scene, RTCRay16& ray) - - void rtcOccluded(RTCScene scene, RTCRay& ray) + void rtcDeleteScene(RTCScene scene) + # Use retain/release + void rtcRetainScene(RTCScene scene) + void rtcReleaseScene(RTCScene scene) - void rtcOccluded4(const void* valid, RTCScene scene, RTCRay4& ray) + # New functions in Embree 4 - scene bounds + ctypedef struct RTCLinearBounds: + rtc.RTCBounds bounds0 + rtc.RTCBounds bounds1 + void rtcGetSceneBounds(rtc.RTCScene scene, rtc.RTCBounds * bounds_o) + void rtcGetSceneLinearBounds(rtc.RTCScene scene, RTCLinearBounds * bounds_o) - void rtcOccluded8(const void* valid, RTCScene scene, RTCRay8& ray) + rtc.RTCDevice rtcGetSceneDevice(rtc.RTCScene scene) - void rtcOccluded16(const void* valid, RTCScene scene, RTCRay16& ray) + #New functions in Embree 4 + RTCSceneFlags rtcGetSceneFlags(rtc.RTCScene scene) + void rtcSetSceneFlags(rtc.RTCScene scene, RTCSceneFlags flags) + void rtcSetSceneProgressMonitorFunction(rtc.RTCScene scene, rtc.RTCProgressMonitorFunc func, void * ptr) + void rtcSetSceneBuildQuality(rtc.RTCScene scene, enum RTCBuildQuality + quality + ) - void rtcDeleteScene(RTCScene scene) cdef class EmbreeScene: - cdef RTCScene scene_i + cdef rtc.RTCScene scene_i # Optional device used if not given, it should be as input of EmbreeScene cdef public int is_committed cdef rtc.EmbreeDevice device @@ -69,4 +186,4 @@ cdef class EmbreeScene: cdef enum rayQueryType: intersect, occluded, - distance + distance \ No newline at end of file diff --git a/embreex/rtcore_scene.pyx b/embreex/rtcore_scene.pyx index 87424e4..e256bd9 100644 --- a/embreex/rtcore_scene.pyx +++ b/embreex/rtcore_scene.pyx @@ -5,14 +5,14 @@ cimport numpy as np import numpy as np import logging import numbers -cimport rtcore as rtc -cimport rtcore_ray as rtcr -cimport rtcore_geometry as rtcg +cimport rtcore as rtc # Use the unified rtcore module +#cimport rtcore_ray as rtcr # No longer needed +#cimport rtcore_geometry as rtcg # No longer needed log = logging.getLogger('embreex') -cdef void error_printer(const rtc.RTCError code, const char *_str) noexcept: +cdef void error_printer(void* userPtr, const rtc.RTCError code, const char *_str) noexcept: """ error_printer function depends on embree version Embree 2.14.1 @@ -22,46 +22,66 @@ cdef void error_printer(const rtc.RTCError code, const char *_str) noexcept: """ log.error("ERROR CAUGHT IN EMBREE") rtc.print_error(code) - log.error("ERROR MESSAGE: %s" % _str) - + if _str: # Check that the string is not null + log.error("ERROR MESSAGE: %s", _str.decode('utf-8', 'replace')) # Decode to a Python string cdef class EmbreeScene: + cdef rtc.RTCScene scene_i + # Optional device used if not given, it should be as input of EmbreeScene + cdef public int is_committed + cdef rtc.EmbreeDevice device + def __init__(self, rtc.EmbreeDevice device=None, robust=False): if device is None: # We store the embree device inside EmbreeScene to avoid premature deletion self.device = rtc.EmbreeDevice() device = self.device - flags = RTC_SCENE_STATIC + else: + #Keep a reference to device + self.device = device + + # Embree 4: Create scene using the device. + self.scene_i = rtc.rtcNewScene(device.device) # All scenes created from device + if self.scene_i is NULL: + raise RuntimeError(f"Failed to create Embree scene: {rtc.rtcGetError()}") + + #flags = rtc.RTC_SCENE_FLAG_STATIC # Removed in Embree 4 + flags = rtc.RTC_SCENE_FLAG_NONE # Start with no flags if robust: # bitwise-or the robust flag - flags |= RTC_SCENE_ROBUST - rtc.rtcDeviceSetErrorFunction(device.device, error_printer) - self.scene_i = rtcDeviceNewScene(device.device, flags, RTC_INTERSECT1) + #flags |= rtc.RTC_SCENE_FLAG_ROBUST # Removed in Embree4 + flags |= rtc.RTC_SCENE_FLAG_ROBUST # Use new flags + rtc.rtcSetSceneFlags(self.scene_i, flags) # Embree 4 + #rtc.rtcDeviceSetErrorFunction(device.device, error_printer) # Replaced in Embree4 + rtc.rtcSetDeviceErrorFunction2(device.device, error_printer, self) + #self.scene_i = rtc.rtcDeviceNewScene(device.device, flags, rtc.RTC_INTERSECT1) # Old API, takes flags. self.is_committed = 0 + def run(self, np.ndarray[np.float32_t, ndim=2] vec_origins, np.ndarray[np.float32_t, ndim=2] vec_directions, dists=None,query='INTERSECT',output=None): if self.is_committed == 0: - rtcCommit(self.scene_i) + #rtcCommit(self.scene_i) # Replaced + rtc.rtcCommitScene(self.scene_i) # Use new function self.is_committed = 1 cdef int nv = vec_origins.shape[0] cdef int vo_i, vd_i, vd_step cdef np.ndarray[np.int32_t, ndim=1] intersect_ids cdef np.ndarray[np.float32_t, ndim=1] tfars - cdef rayQueryType query_type + cdef rtc.rayQueryType query_type # Now use rtcore types if query == 'INTERSECT': - query_type = intersect + query_type = rtc.intersect elif query == 'OCCLUDED': - query_type = occluded + query_type = rtc.occluded elif query == 'DISTANCE': - query_type = distance + query_type = rtc.distance else: - raise ValueError("Embree ray query type %s not recognized." + raise ValueError("Embree ray query type %s not recognized." "\nAccepted types are (INTERSECT,OCCLUDED,DISTANCE)" % (query)) if dists is None: @@ -82,51 +102,75 @@ cdef class EmbreeScene: else: intersect_ids = np.empty(nv, dtype="int32") - cdef rtcr.RTCRay ray + #cdef rtcr.RTCRay ray # Old ray struct. + cdef rtc.RTCRayHit rayhit # Use combined ray/hit struct + cdef rtc.RTCRay ray #Define ray to easily fill the struct. vd_i = 0 vd_step = 1 # If vec_directions is 1 long, we won't be updating it. if vec_directions.shape[0] == 1: vd_step = 0 + # Set up the intersection arguments (Embree 4) + cdef rtc.RTCIntersectArguments args + rtc.rtcInitIntersectArguments(&args) # Initialize the args struct + + # Set up the occlusion arguments (Embree 4) + cdef rtc.RTCOccludedArguments oargs + rtc.rtcInitOccludedArguments(&oargs) # Initialize the args struct + for i in range(nv): - for j in range(3): - ray.org[j] = vec_origins[i, j] - ray.dir[j] = vec_directions[vd_i, j] + # Fill Ray struct and then copy to RTCRayHit + ray.org_x = vec_origins[i, 0] # Use explicit members + ray.org_y = vec_origins[i, 1] + ray.org_z = vec_origins[i, 2] + ray.dir_x = vec_directions[vd_i, 0] + ray.dir_y = vec_directions[vd_i, 1] + ray.dir_z = vec_directions[vd_i, 2] ray.tnear = 0.0 ray.tfar = tfars[i] - ray.geomID = rtcg.RTC_INVALID_GEOMETRY_ID - ray.primID = rtcg.RTC_INVALID_GEOMETRY_ID - ray.instID = rtcg.RTC_INVALID_GEOMETRY_ID - ray.mask = -1 - ray.time = 0 + ray.mask = -1 # Enable all geometries + ray.time = 0.0 + # Initialize hit information + rayhit.hit.geomID = rtc.RTC_INVALID_GEOMETRY_ID + rayhit.hit.primID = rtc.RTC_INVALID_GEOMETRY_ID + rayhit.hit.instID[0] = rtc.RTC_INVALID_GEOMETRY_ID # Just the first instID + + #Copy ray to rayhit + rayhit.ray = ray + vd_i += vd_step - if query_type == intersect or query_type == distance: - rtcIntersect(self.scene_i, ray) + if query_type == rtc.intersect or query_type == rtc.distance: + rtc.rtcIntersect1(self.scene_i, &rayhit, &args) # Pass args struct if not output: - if query_type == intersect: - intersect_ids[i] = ray.primID + if query_type == rtc.intersect: + intersect_ids[i] = rayhit.hit.primID # Access hit info from .hit else: - tfars[i] = ray.tfar + tfars[i] = rayhit.ray.tfar else: - primID[i] = ray.primID - geomID[i] = ray.geomID - u[i] = ray.u - v[i] = ray.v - tfars[i] = ray.tfar + primID[i] = rayhit.hit.primID + geomID[i] = rayhit.hit.geomID + u[i] = rayhit.hit.u + v[i] = rayhit.hit.v + tfars[i] = rayhit.ray.tfar #Access tfar from .ray for j in range(3): - Ng[i, j] = ray.Ng[j] + Ng[i, j] = rayhit.hit.Ng_x #Access Ng from .hit + if j == 1: + Ng[i, j] = rayhit.hit.Ng_y + elif j==2: + Ng[i, j] = rayhit.hit.Ng_z else: - rtcOccluded(self.scene_i, ray) - intersect_ids[i] = ray.geomID + rtc.rtcOccluded1(self.scene_i, &rayhit, &oargs) # Pass args struct. + intersect_ids[i] = rayhit.hit.geomID # Access geomID from hit if output: return {'u':u, 'v':v, 'Ng': Ng, 'tfar': tfars, 'primID': primID, 'geomID': geomID} else: - if query_type == distance: + if query_type == rtc.distance: return tfars else: return intersect_ids def __dealloc__(self): - rtcDeleteScene(self.scene_i) + if self.scene_i is not NULL: + rtc.rtcReleaseScene(self.scene_i) \ No newline at end of file diff --git a/embreex/triangles.pyx b/embreex/triangles.pyx index d47bda5..6daf557 100644 --- a/embreex/triangles.pyx +++ b/embreex/triangles.pyx @@ -2,24 +2,27 @@ cimport numpy as np cimport rtcore as rtc -cimport rtcore_ray as rtcr -cimport rtcore_scene as rtcs -cimport rtcore_geometry as rtcg -cimport rtcore_geometry_user as rtcgu -from rtcore cimport Vertex, Triangle, Vec3f +#cimport rtcore_ray as rtcr # Removed +#cimport rtcore_scene as rtcs # Removed +#cimport rtcore_geometry as rtcg # Removed +#cimport rtcore_geometry_user as rtcgu # Removed +from rtcore cimport Vertex, Triangle, Vec3f # Use new unified rtcore module from libc.stdlib cimport malloc, free -ctypedef Vec3f (*renderPixelFunc)(float x, float y, - const Vec3f &vx, const Vec3f &vy, const Vec3f &vz, - const Vec3f &p) +# typedef removed in Embree 4. +#ctypedef Vec3f (*renderPixelFunc)(float x, float y, +# const Vec3f &vx, const Vec3f &vy, const Vec3f &vz, +# const Vec3f &p) def run_triangles(): pass -cdef unsigned int addCube(rtcs.RTCScene scene_i): - cdef unsigned int mesh = rtcg.rtcNewTriangleMesh(scene_i, - rtcg.RTC_GEOMETRY_STATIC, 12, 8, 1) - cdef Vertex* vertices = rtcg.rtcMapBuffer(scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) +cdef rtc.RTCGeometry addCube(rtc.EmbreeScene scene_i): #Return RTCGeometry and receive EmbreeScene + # Use rtcNewGeometry for all geometry creation. + cdef rtc.RTCGeometry mesh = rtc.rtcNewGeometry(scene_i.device.device, rtc.RTC_GEOMETRY_TYPE_TRIANGLE) + + # Use rtcSetNewBuffer instead of rtcMapBuffer/rtcUnmapBuffer + cdef Vertex* vertices = rtc.rtcSetNewBuffer(mesh, rtc.RTC_BUFFER_TYPE_VERTEX, 0, rtc.RTC_FORMAT_FLOAT3, sizeof(Vertex), 8) vertices[0].x = -1 vertices[0].y = -1 vertices[0].z = -1 @@ -52,13 +55,14 @@ cdef unsigned int addCube(rtcs.RTCScene scene_i): vertices[7].y = +1 vertices[7].z = +1 - rtcg.rtcUnmapBuffer(scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) + # rtcg.rtcUnmapBuffer(scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) # No longer needed - cdef Vec3f *colors = malloc(12*sizeof(Vec3f)) + # Example of how you *could* share vertex data, if you wanted to. + # colors = rtc.rtcSetSharedBuffer(mesh, rtc.RTC_BUFFER_TYPE_VERTEX, 1, rtc.RTC_FORMAT_FLOAT3, colors_np, 0, sizeof(Vec3f), 12) + cdef Vec3f *colors = malloc(12*sizeof(Vec3f)) # Not really necessary in this example, could be a stack variable cdef int tri = 0 - cdef Triangle* triangles = rtcg.rtcMapBuffer(scene_i, mesh, - rtcg.RTC_INDEX_BUFFER) + cdef Triangle* triangles = rtc.rtcSetNewBuffer(mesh, rtc.RTC_BUFFER_TYPE_INDEX, 0, rtc.RTC_FORMAT_UINT3, sizeof(Triangle), 12) # left side colors[tri].x = 1.0 @@ -156,15 +160,19 @@ cdef unsigned int addCube(rtcs.RTCScene scene_i): triangles[tri].v2 = 5 tri += 1 - rtcg.rtcUnmapBuffer(scene_i, mesh, rtcg.RTC_INDEX_BUFFER) - + # rtcg.rtcUnmapBuffer(scene_i, mesh, rtcg.RTC_INDEX_BUFFER) # No longer needed + rtc.rtcCommitGeometry(mesh) # Commit the *geometry*, not the scene + rtc.rtcAttachGeometry(scene_i.scene_i, mesh) # Attach geometry and increment reference count + free(colors) #Free colors return mesh -cdef unsigned int addGroundPlane (rtcs.RTCScene scene_i): - cdef unsigned int mesh = rtcg.rtcNewTriangleMesh (scene_i, - rtcg.RTC_GEOMETRY_STATIC, 2, 4, 1) - cdef Vertex* vertices = rtcg.rtcMapBuffer(scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) +cdef rtc.RTCGeometry addGroundPlane (rtc.EmbreeScene scene_i): #Return RTCGeometry + #cdef unsigned int mesh = rtcg.rtcNewTriangleMesh (scene_i, rtcg.RTC_GEOMETRY_STATIC, 2, 4, 1) # Removed in Embree4 + cdef rtc.RTCGeometry mesh = rtc.rtcNewGeometry(scene_i.device.device, rtc.RTC_GEOMETRY_TYPE_TRIANGLE) + + #cdef Vertex* vertices = rtcg.rtcMapBuffer(scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) # Removed in Embree 4 + cdef Vertex* vertices = rtc.rtcSetNewBuffer(mesh, rtc.RTC_BUFFER_TYPE_VERTEX, 0, rtc.RTC_FORMAT_FLOAT3, sizeof(Vertex), 4) vertices[0].x = -10 vertices[0].y = -2 vertices[0].z = -10 @@ -180,15 +188,18 @@ cdef unsigned int addGroundPlane (rtcs.RTCScene scene_i): vertices[3].x = +10 vertices[3].y = -2 vertices[3].z = +10 - rtcg.rtcUnmapBuffer(scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) + # rtcg.rtcUnmapBuffer(scene_i, mesh, rtcg.RTC_VERTEX_BUFFER) # No longer needed - cdef Triangle* triangles = rtcg.rtcMapBuffer(scene_i, mesh, rtcg.RTC_INDEX_BUFFER) + #cdef Triangle* triangles = rtcg.rtcMapBuffer(scene_i, mesh, rtcg.RTC_INDEX_BUFFER) # Removed in Embree 4 + cdef Triangle* triangles = rtc.rtcSetNewBuffer(mesh, rtc.RTC_BUFFER_TYPE_INDEX, 0, rtc.RTC_FORMAT_UINT3, sizeof(Triangle), 2) triangles[0].v0 = 0 triangles[0].v1 = 2 triangles[0].v2 = 1 triangles[1].v0 = 1 triangles[1].v1 = 2 triangles[1].v2 = 3 - rtcg.rtcUnmapBuffer(scene_i, mesh, rtcg.RTC_INDEX_BUFFER) - return mesh + # rtcg.rtcUnmapBuffer(scene_i, mesh, rtcg.RTC_INDEX_BUFFER) # No longer needed + rtc.rtcCommitGeometry(mesh) # Commit *geometry* + rtc.rtcAttachGeometry(scene_i.scene_i, mesh) # Attach geometry + return mesh \ No newline at end of file diff --git a/examples/attenuate.py b/examples/attenuate.py index 64cddb2..490ac85 100644 --- a/examples/attenuate.py +++ b/examples/attenuate.py @@ -1,5 +1,5 @@ from embreex.mesh_construction import TriangleMesh -from embreex import rtcore_scene as rtcs +from embreex import rtcore as rtc # Import the unified rtcore module import sys import time @@ -25,7 +25,10 @@ def xplane(x): triangles = xplane(0.0) + xplane(1.0) + xplane(2.0) + xplane(3.0) triangles = np.array(triangles, "float32") -scene = rtcs.EmbreeScene() +# Embree 4: Create a device first +device = rtc.EmbreeDevice() +scene = rtc.EmbreeScene(device) # Pass the device to the scene + mesh = TriangleMesh(scene, triangles) xgrid = np.linspace(0.0, 3.0, 100) tally = np.zeros(len(xgrid), dtype=int) @@ -71,4 +74,4 @@ def transport_region(r, origins, maxdist, exist): plt.plot(xgrid, tally) plt.xlabel("x [cm]") plt.ylabel("flux") - plt.savefig("attenuate.png") + plt.savefig("attenuate.png") \ No newline at end of file diff --git a/examples/intersection.py b/examples/intersection.py index 70f07da..3bf9a86 100644 --- a/examples/intersection.py +++ b/examples/intersection.py @@ -1,7 +1,7 @@ import time import numpy as np -from embreex import rtcore_scene as rtcs +from embreex import rtcore as rtc # Use the unified rtcore module from embreex.mesh_construction import TriangleMesh N = 4 @@ -17,7 +17,10 @@ def xplane(x): triangles = xplane(7.0) triangles = np.array(triangles, "float32") -scene = rtcs.EmbreeScene() +# Embree 4: Create a device first +device = rtc.EmbreeDevice() +scene = rtc.EmbreeScene(device) # Pass the device to the scene + mesh = TriangleMesh(scene, triangles) origins = np.zeros((N, 3), dtype="float32") @@ -31,7 +34,7 @@ def xplane(x): dirs[:, 0] = 1.0 t1 = time.time() -res = scene.run(origins, dirs, output=1) +res = scene.run(origins, dirs, output=True) #output=True is equivalent to output=1 t2 = time.time() print("Ran in {0:.3f} s".format(t2 - t1)) @@ -52,4 +55,4 @@ def xplane(x): + np.vstack(u) * triangles[primID][:, 1, :] + np.vstack(v) * triangles[primID][:, 2, :] ) -print(inters) +print(inters) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 77afc32..318415f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,8 +10,8 @@ build-backend = "setuptools.build_meta" [project] name = "embreex" -version = "2.17.7.post6" -requires-python = ">=3.8" +version = "4.3.3.dev0" +requires-python = ">=3.9" dependencies = ["numpy"] description = "Python binding for Intel's Embree ray engine" @@ -34,19 +34,20 @@ embreex = ["*.pxd"] [tool.cibuildwheel] skip = "pp* *i686 *-win32 *musllinux*" manylinux-x86_64-image = "manylinux_2_28" +manylinux-aarch64-image = "manylinux_2_28" before-test = "pip install pytest" test-command = "pytest -v {project}/tests" -before-build = "python {project}/ci/fetch-embree.py --install embree2" +before-build = "python {project}/ci/fetch-embree.py --install embree4" [tool.cibuildwheel.windows] -before-build = "pip install delvewheel && python {project}\\ci\\fetch-embree.py --install embree2" -repair-wheel-command = "delvewheel repair --add-path embree2\\bin --no-mangle tbb12.dll;embree2.dll -w {dest_dir} {wheel}" +before-build = "pip install delvewheel && python {project}\\ci\\fetch-embree.py --install embree4" +repair-wheel-command = "delvewheel repair --add-path embree4\\bin --no-mangle tbb12.dll;embree4.dll -w {dest_dir} {wheel}" [tool.cibuildwheel.macos] -repair-wheel-command = "DYLD_LIBRARY_PATH=embree2/lib delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}" +repair-wheel-command = "DYLD_LIBRARY_PATH=embree4/lib delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}" [tool.cibuildwheel.linux] -repair-wheel-command = "LD_LIBRARY_PATH=`realpath embree2/lib`; auditwheel repair -w {dest_dir} {wheel}" +repair-wheel-command = "LD_LIBRARY_PATH=`realpath embree4/lib`; auditwheel repair -w {dest_dir} {wheel}" [tool.ruff] select = ["E", "F", # the default rules diff --git a/setup.py b/setup.py index 92e3053..6fdbb8a 100755 --- a/setup.py +++ b/setup.py @@ -17,21 +17,21 @@ def ext_modules(): # embree search locations on windows includes = [ get_include(), - "c:/Program Files/Intel/Embree2/include", - os.path.join(_cwd, "embree2", "include"), + "c:/Program Files/Intel/embree4/include", + os.path.join(_cwd, "embree4", "include"), ] libraries = [ - "c:/Program Files/Intel/Embree2/lib", - os.path.join(_cwd, "embree2", "lib"), + "c:/Program Files/Intel/embree4/lib", + os.path.join(_cwd, "embree4", "lib"), ] else: # embree search locations on posix includes = [ get_include(), "/opt/local/include", - os.path.join(_cwd, "embree2", "include"), + os.path.join(_cwd, "embree4", "include"), ] - libraries = ["/opt/local/lib", os.path.join(_cwd, "embree2", "lib")] + libraries = ["/opt/local/lib", os.path.join(_cwd, "embree4", "lib")] ext_modules = cythonize("embreex/*.pyx", include_path=includes, language_level=2) for ext in ext_modules: diff --git a/tests/test_intersection.py b/tests/test_intersection.py index 0525968..a140890 100644 --- a/tests/test_intersection.py +++ b/tests/test_intersection.py @@ -1,7 +1,7 @@ from unittest import TestCase import numpy as np -from embreex import rtcore as rtc -from embreex import rtcore_scene as rtcs +from embreex import rtcore as rtc # Use unified rtcore module +#from embreex import rtcore_scene as rtcs # Removed in Embree 4 from embreex.mesh_construction import TriangleMesh from embreex.mesh_construction import ElementMesh @@ -35,19 +35,19 @@ def define_rays_origins_and_directions(): class Testembreex(TestCase): def test_embreex_should_be_able_to_display_embree_version(self): embreeDevice = rtc.EmbreeDevice() - print(embreeDevice) + print(embreeDevice) #The repr has changed in EmbreeDevice def test_embreex_should_be_able_to_create_a_scene(self): embreeDevice = rtc.EmbreeDevice() - rtcs.EmbreeScene(embreeDevice) + rtc.EmbreeScene(embreeDevice) # Use rtcore def test_embreex_should_be_able_to_create_several_scenes(self): embreeDevice = rtc.EmbreeDevice() - rtcs.EmbreeScene(embreeDevice) - rtcs.EmbreeScene(embreeDevice) + rtc.EmbreeScene(embreeDevice) # Use rtcore + rtc.EmbreeScene(embreeDevice) # Use rtcore def test_embreex_should_be_able_to_create_a_device_if_not_provided(self): - rtcs.EmbreeScene() + rtc.EmbreeScene() # Use rtcore class TestIntersectionTriangles(TestCase): @@ -57,7 +57,7 @@ def setUp(self): triangles = np.array(triangles, "float32") self.embreeDevice = rtc.EmbreeDevice() - self.scene = rtcs.EmbreeScene(self.embreeDevice) + self.scene = rtc.EmbreeScene(self.embreeDevice) # Use rtcore TriangleMesh(self.scene, triangles) origins, dirs = define_rays_origins_and_directions() @@ -66,22 +66,22 @@ def setUp(self): def test_intersect_simple(self): res = self.scene.run(self.origins, self.dirs) - self.assertTrue([0, 1, 1, -1], res) + self.assertTrue(np.array_equal(np.array([0, 1, 1, -1]), res)) # Use np.array_equal def test_intersect_distance(self): res = self.scene.run(self.origins, self.dirs, query="DISTANCE") self.assertTrue(np.allclose([6.9, 6.9, 6.9, 1e37], res)) def test_intersect(self): - res = self.scene.run(self.origins, self.dirs, output=1, dists=100) + res = self.scene.run(self.origins, self.dirs, output=True, dists=100) # output=1 -> output=True - self.assertTrue([0, 0, 0, -1], res["geomID"]) + self.assertTrue(np.array_equal(np.array([0, 0, 0, -1]), res["geomID"])) # Use np.array_equal ray_inter = res["geomID"] >= 0 primID = res["primID"][ray_inter] u = res["u"][ray_inter] v = res["v"][ray_inter] tfar = res["tfar"] - self.assertTrue([0, 1, 1], primID) + self.assertTrue(np.array_equal(np.array([0, 1, 1]), primID))# Use np.array_equal self.assertTrue(np.allclose([6.9, 6.9, 6.9, 100], tfar)) self.assertTrue(np.allclose([0.4, 0.1, 0.15], u)) self.assertTrue(np.allclose([0.5, 0.4, 0.35], v)) @@ -95,7 +95,7 @@ def setUp(self): indices = np.array([[0, 1, 2], [1, 3, 2]], "uint32") self.embreeDevice = rtc.EmbreeDevice() - self.scene = rtcs.EmbreeScene(self.embreeDevice) + self.scene = rtc.EmbreeScene(self.embreeDevice) # Use rtcore TriangleMesh(self.scene, points, indices) origins, dirs = define_rays_origins_and_directions() @@ -104,19 +104,19 @@ def setUp(self): def test_intersect_simple(self): res = self.scene.run(self.origins, self.dirs) - self.assertTrue([0, 1, 1, -1], res) + self.assertTrue(np.array_equal(np.array([0, 1, 1, -1]), res)) # Use np.array_equal def test_intersect(self): - res = self.scene.run(self.origins, self.dirs, output=1) + res = self.scene.run(self.origins, self.dirs, output=True) # output=1 -> output=True - self.assertTrue([0, 0, 0, -1], res["geomID"]) + self.assertTrue(np.array_equal(np.array([0, 0, 0, -1]), res["geomID"])) # Use np.array_equal ray_inter = res["geomID"] >= 0 primID = res["primID"][ray_inter] u = res["u"][ray_inter] v = res["v"][ray_inter] tfar = res["tfar"][ray_inter] - self.assertTrue([0, 1, 1], primID) + self.assertTrue(np.array_equal(np.array([0, 1, 1]), primID)) # Use np.array_equal self.assertTrue(np.allclose([6.9, 6.9, 6.9], tfar)) self.assertTrue(np.allclose([0.4, 0.1, 0.15], u)) self.assertTrue(np.allclose([0.5, 0.4, 0.35], v)) @@ -129,7 +129,7 @@ def setUp(self): vertices = np.array(vertices, "float32") indices = np.array([[0, 1, 2, 3]], "uint32") self.embreeDevice = rtc.EmbreeDevice() - self.scene = rtcs.EmbreeScene(self.embreeDevice) + self.scene = rtc.EmbreeScene(self.embreeDevice) # Use rtcore ElementMesh(self.scene, vertices, indices) N = 2 @@ -141,19 +141,19 @@ def setUp(self): def test_intersect_simple(self): res = self.scene.run(self.origins, self.dirs) - self.assertTrue([1, 1], res) + self.assertTrue(np.array_equal(np.array([1, 1]), res)) # Use np.array_equal def test_intersect(self): - res = self.scene.run(self.origins, self.dirs, output=1) + res = self.scene.run(self.origins, self.dirs, output=True) # output=1 -> output=True - self.assertTrue([0, 0], res["geomID"]) + self.assertTrue(np.array_equal(np.array([0, 0]), res["geomID"]))# Use np.array_equal ray_inter = res["geomID"] >= 0 primID = res["primID"][ray_inter] u = res["u"][ray_inter] v = res["v"][ray_inter] tfar = res["tfar"][ray_inter] - self.assertTrue([0, 1], primID) + self.assertTrue(np.array_equal(np.array([0, 1]), primID)) # Use np.array_equal self.assertTrue(np.allclose([0.1, 0.1], tfar)) self.assertTrue(np.allclose([0.1, 0.2], u)) self.assertTrue(np.allclose([0.1, 0.2], v)) @@ -175,7 +175,7 @@ def setUp(self): vertices = np.array(vertices, "float32") indices = np.array([[0, 1, 2, 3, 4, 5, 6, 7]], "uint32") self.embreeDevice = rtc.EmbreeDevice() - self.scene = rtcs.EmbreeScene(self.embreeDevice) + self.scene = rtc.EmbreeScene(self.embreeDevice) # Use rtcore ElementMesh(self.scene, vertices, indices) N = 2 @@ -187,19 +187,19 @@ def setUp(self): def test_intersect_simple(self): res = self.scene.run(self.origins, self.dirs) - self.assertTrue([1, 1], res) + self.assertTrue(np.array_equal(np.array([1, 1]), res)) # Use np.array_equal def test_intersect(self): - res = self.scene.run(self.origins, self.dirs, output=1) + res = self.scene.run(self.origins, self.dirs, output=True) # output=1 -> output=True - self.assertTrue([0, 0], res["geomID"]) + self.assertTrue(np.array_equal(np.array([0, 0]), res["geomID"])) # Use np.array_equal ray_inter = res["geomID"] >= 0 primID = res["primID"][ray_inter] u = res["u"][ray_inter] v = res["v"][ray_inter] tfar = res["tfar"][ray_inter] - self.assertTrue([0, 1], primID) + self.assertTrue(np.array_equal(np.array([0, 1]), primID)) # Use np.array_equal self.assertTrue(np.allclose([0.1, 0.1], tfar)) self.assertTrue(np.allclose([0.1, 0.2], u)) self.assertTrue(np.allclose([0.8, 0.6], v)) @@ -208,4 +208,4 @@ def test_intersect(self): if __name__ == "__main__": from unittest import main - main() + main() \ No newline at end of file